当前位置: 首页 > news >正文

Spring MVC学习笔记,包含mvc架构使用,过滤器、拦截器、执行流程等等

😀😀😀创作不易,各位看官点赞收藏.

文章目录

  • Spring MVC 习笔记
    • 1、Spring MVC demo
    • 2、Spring MVC 中常见注解
    • 3、数据处理
      • 3.1、请求参数处理
      • 3.2、响应数据处理
    • 4、RESTFul 风格
    • 5、静态资源处理
    • 6、HttpMessageConverter 转换器
    • 7、过滤器与拦截器
    • 8、 异常处理
    • 9、理解SpringMVC的执行原理
    • 10、文件上传和下载

Spring MVC 习笔记

Spring MVC:Spring MVC是Spring Framework的一部分,是基于java实现的MVC的轻量级Web框架。

官网文档地址:https://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html

  • 轻量级,简单易学。
  • 高效,基于请求和响应的MVC框架。
  • 与Spring兼容性较好,无缝结合。
  • 约定优于配置。
  • 功能强大,简洁灵活。

MVC:是一种软件架构思想,按照软件的模型、试图、控制器进行划分。

M:model,模型层工程中的 javaBean 用于处理数据。

V:view,视图层工程中显示数据的页面,用于与用户交互使用。

C:controller,控制器层,用于接收前端请求和响应浏览器。

1、Spring MVC demo

导入依赖:

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.8</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency><dependency><groupId>javax.servlet.jsp.jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version></dependency>
</dependencies>

创建 web.xml 配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 		http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 注册DispatcherServlet--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 关联一个spring 容器的配置文件:springmvc-servlet.xml--><!-- 如果它不绑定一个 spring 容器配置文件,它会有一个在WEB-INF下默认名称为 springmvc-servlet.xml的配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!-- 设置该servlet在项目启动的时候就加载--><load-on-startup>1</load-on-startup></servlet><!-- 设置请求的访问路径--><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

创建 spring 容器配置文件:springmvc-servlet.xml

<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 注入映射器--><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/><!-- 注入适配器--><bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/><!-- 注入视图解析器,在控制器返回到视图层会根据返回路劲进行拼接--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">   <!--前缀-->   <property name="prefix" value="/WEB-INF/jsp/"/>   <!--后缀-->   <property name="suffix" value=".jsp"/></bean>
</beans>

编写controller:

public class HelloController implements Controller {@Overridepublic ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {// 创建ModelAndView对象,用于返回业务的数据ModelAndView mv = new ModelAndView();// 把业务获得的数据封装到mv中mv.addObject("msg","Hello,SpringMVC!");// 把要跳转的视图封装到mv中mv.setViewName("hello"); // 在springmvc-servlet.xml中拼接为 /WEB-INF/jsp/hello.jsp// 把mv返回给DispatcherServletreturn mv;}
}

controller 注入 Spring 容器:

<bean id="/hello" class="com.xiayuan.controller.HelloController"/>
  1. 编写测试的页面,在WEB-INF文件夹下创建一个jsp文件夹,在jsp文件夹下创建hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>test</title>
</head>
<body>${msg}
</body>
</html>

配置 Tomcat并测试:

image-20210906000548314

注意:在配置DisapatcherServlet时,拦截的请求是 / 表示拦截所有的请求, /* 也是拦截所有的请求,但是 / 不包括jsp文件,而 /* 会包括jsp文件,所以只能写 / 来拦截所有的请求。

2、Spring MVC 中常见注解

@RequestMapping:注解用于映射 url 到控制器类或一个特定的处理程序方法。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

@Controller
@RequestMapping("/test")
public class HelloController {// 映射的 url 地址就是 /test/helllo@RequestMapping("/hello")public String sayHello(Model model){model.addAttribute("msg","Hello,SpringMVCAnnotation!");return "hello";}
}

@RequestMapping 注解属性:

  • value:指定 url 地址映射的值,可以是一个数组,映射多个请求,是个必填属性,支持模糊匹配。
    • ?:单个字符。
    • *:表示任意一个或多个字符。
    • **:表示任意一层或多层目录。
  • method:是一个枚举值,可以指定请求方式来映射请求,通常有POST、GET、DELETED、PUT等,也是一个数组可以映射多个请求方法。
  • params:根据请求参数去匹配请求 url 地址,是一个字符串数组,可以指定多个,指定多个时必须同时满足多个条件才会映射。
    • params={"test","admin"}:请求中必须同时包含test、admin两个参数。
    • params={“!test”}:请求中必须不包含 test 参数。
    • params={“test=1”}:请求中必须包含 test 参数并且参数值必须是1。
    • params={“test!=1”}:请求中必须包含 test 参数并且参数值必须不等于1。
  • headers:根据 http 请求中的请求头来映射 url 地址,用法和 params 类似。
  • consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html,是一个数组可以指定多个。
  • produces: 指定返回的内容类型,仅当 request 请求头中的 (Accept) 类型中包含该指定类型才返回,是一个数组可以指定多个。

@RequestMapping 派生注解:

  • @GetMapping:请求映射 GET 方式请求到方法上,相当于在 @RequestMapping 上添加了 method 属性为 GET 方式。
  • @PostMapping:…
  • @DeleteMapping:…
  • @PutMapping:…

@RequestParam 注解:用于控制器的请求方法的参数上,将请求参数与方法参数两个相互映射。

@GetMapping("/test1")
// 将前端的user参数与name参数映射
public String test(@RequestParam("user") String name){return name;
}

@RequestHeader 注解:用于控制器方法上的参数,请求头信息与参数之间的关系映射。

@PostMapping("/test1")
// 将请求头中的Accept的值赋值给header
public String test(@RequestHeader("Accept") String header){return header;
}

@CookieValue 注解:用于控制器方法上的参数,将请求中的 cookie 与参数之间的关系映射起来。

@PostMapping("/test1")
public String test(@CookieValue String cookie){return cookie;
}

@Controller:用于类上,标识这个类是一个处理前端请求的类,会根据 url 地址映射到处理请求的方法上。

@Controller
public class ControllerTest {
}

@RestController:作用与 @Controller 相同,但是这个类处理请求返回的结果是 json 格式。

3、数据处理

3.1、请求参数处理

请求参数:每一次请求都会携带一些参数数据,后端可以获取这些参数数据进行一系列操作,获取请求参数的方式很多。

  • 通过 url 中的参数来获得前端参数。
@RequestMapping("/t1")
public String test1(@RequestParam("name") String name, @RequestParam("password") String password, Model model){// @RequestParam注解中的name和password就是从前端传过来的参数名称// 必须和前端参数名称一样,后面的string的名称可以和前端参数名称不一样System.out.println("name = "+name);System.out.println("password = "+password);return "test";
}
  • 通过封装一个实体类来接受数据。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private String name;private String password;
}
@RequestMapping("/t2")
public String test2(User user,Model model){System.out.println(user);return "test";
}

注意:把user作为参数来接受前端数据,而且前端的参数名称必须要和接受对象的字段名称保持一致,不能不一样。如果字段不一样的字段,就会自动为默认值。

  • 通过 Map 集合获取数据,这种方式只能从请求体中获取对象数据或则是 json 数据。
@PostMapping("/test2")
public String test(@RequestBody Map<String,String> params){System.out.println(params.get("name"));return "ok";
}

请求参数乱码问题:在前端传入的参数中有中文字符,在后端就会存在乱码问题,我们通常使用过滤器去解决乱码问题。

<!-- 向 web.xml 文件中注册一个 filer 过滤器就可以解决乱码问题--><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param><!-- 设置响应编码--><init-param><param-name>forceResponseEncoding</param-name><param-value>true</param-value></init-param>
</filter>
<filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

3.2、响应数据处理

request 域数据设置:

ModelAndView:这是之前的数据封装方式,使用的就是ModelAndView来给前端显示数据的。

@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {ModelAndView mv = new ModelAndView();// 数据mv.addObject("msg","封装的数据!"); // 视图的名称mv.setViewName("hello");return mv;
}

ModelMap:

@RequestMapping("/t3")
public String test3(ModelMap modelMap){modelMap.addAttribute("msg","封装的数据!");return "test";
}

Model:

@RequestMapping("/t4")
public String test4(Model model){model.addAttribute("msg","封装的数据!");return "test";
}

注意:ModelMap 它继承了 LinkedHashMap,所有他有该类的所有操作,而 Model 是 ModelMap 的简洁版本,没有继承 LinkedHashMap

​ Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解; ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性; ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转,它们都是把数据封装到在 request 域中的,实际上在底层返回中请求都是返回的一个 ModelAndView 对象。

session 域数据:这个数据是当前会话共享的数据。

@GetMapping("/test")
public String test(HttpServletSession session){
session.setAttribute("data","这是一个数据");
return "ok";
}

application 域数据:这个数据是应用程序共享的数据。

@GetMapping("/test")
public String test(HttpSession session){// 应用全局上下文ServletContext context = session.getServletContext();context.setAttribute("data","这是一个数据");return "ok";
}

请求转发:

@RequestMapping("/t2")
public String test2(HttpServletRequest request, HttpServletResponse response,Model model){// 请求转发:可以转发到页面,也可以转发到一个请求return "forward:/test" return "forward:/login.jsp"; 
}

重定向:

@RequestMapping("/t2")
public String test2(HttpServletRequest request, HttpServletResponse response,Model model){// 相当于重新发出一个请求return "redirect:/login.jsp" 
}

:注意重定向不能重定向到WEB-INF下的资源。

4、RESTFul 风格

Restful:是一个资源定位及资源操作的风格,是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

操作传统方式RESTFul风格
查询getById?id=1getById/1 ==== get方式
新增insertinsert === post方式
删除deletedByid?id=1deletedByid/1 ==== delete方式
更新updateByid?id=1updateByid/1 ==== put方式

url 地址参数绑定:

@Controller
public class RestFulController {@RequestMapping("/hello/{a}/{b}")public String test(@PathVariable String a, @PathVariable String b, Model model){// 需要使用`@PathVariable`注解来注解参数,上面a和b就是参数的名称。model.addAttribute("msg","Hello,RestFul!");return "hello";}
}

image-20210908133624519

5、静态资源处理

注意:在 Spring MVC 中所有的请求都会先呗被 DispatcherServlte 拦截并且映射到对应的控制器上,但是对于静态资源就会出现找不到的问题。

<!-- 解决:需要在 Spring MVC 配置文件中指定处理静态资源的 Sevlet -->
<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 加入处理静态资源的 servlet--><mvc:default-servlet-handler/><!-- 开启注解驱动,不开启静态资源 servlet 无效--><mvc:annotation-driven/>
</beans>

处理流程:

image-20230608175730418

6、HttpMessageConverter 转换器

消息转换器,将请求信息转换成 Java 对象,或者将 Java 对象装换成响应报文给前端。HttpMessageConverter 提供了两个注解和两个实体类:@RequestBody、@ResponseBody、RequestEntity、ResponseEntity。

@RequestBody:获取请求体中的参数,与方法参数绑定在一起,一般请求方式是 POST 方法也可以是 GET 方法,但是必须有请求体。

@PostMapping("/")
public String fun1(@RequestBody User user){ // 将请求体的参数与user对象进行映射,参数名需要对应return "ok";
}

RequestEntity:封装请求报文的一种类型,其中包含请求头、请求体等信息,在控制器方法上指定这个采参数就可以直接获取请求信息。

@PostMapping("/entity")
public String fun2(RequestEntity<String> entity){System.out.println(entity.getHeaders());System.out.println(entity.getBody());return "ok";
}

@ResponseBody:标识在控制器方法上,如果项目引入了 Json 解析包,对于返回的对象会解析成 Json 字符串。

@GetMapping("/")
// 将方法返回值作为响应体,不再是视图名臣
@ResponseBody
public User fun3(){User user = new User();user.setUsername("张三");user.setPassword("123456");return user;
}

ResponseEntity:用于控制器方法的返回值,该方法的返回值就是响应到浏览器的响应报文。

@GetMapping("/entity")
public ResponseEntity<User> fun4(){User user = new User();user.setUsername("张三");user.setPassword("123456");// 构建响应报文return new ResponseEntity<>(user, HttpStatus.OK);
}

7、过滤器与拦截器

过滤器:是基于函数回调的,过滤器中都会实现一个 doFilter()方法,这个方法有一个FilterChain 参数,而实际上它是一个回调接口。ApplicationFilterChain是它的实现类, 这个实现类内部也有一个 doFilter() 方法就是回调方法。

// 自定义过滤器
@Component
public class MyFilter implements Filter {// 初始化方法,这个方法必须执行成功,否则过滤器不生效@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 进行业务处理,如果不放行就通过request重定向或转发到对应页面// 放行请求filterChain.doFilter(servletRequest,servletResponse);}// 拦截器销毁方法@Overridepublic void destroy() {Filter.super.destroy();}
}

拦截器:应用中可以同时存在多个拦截器Interceptor, 一个请求也可以触发多个拦截器 ,而每个拦截器的调用会依据它的声明顺序依次执行,拦截器 则是基于 Java 的反射机制(动态代理)实现的,只有 Spring MVC 框架才能使用该拦截器。

// 自定义拦截器
@Component
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
  • preHandle方法:是过滤请求,相当于 servlet 中的 doFilter,如果返回 true 就放行该请求,返回 false 就不会放行请求。
  • postHandle方法:在控制器方法执行完成之后执行。
  • afterCompletion方法:在视图解析器解析之后执行。

过滤器的使用:编写配置类,将过滤器注册到 Spring 容器中并设置对应的拦截路径。

@Configuration
public class WebMvcConfig {@Bean("myFilterRegister")public FilterRegistrationBean<MyFilter> myFilter(MyFilter myFilter) {FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(myFilter);registrationBean.addUrlPatterns("/*");  //url拦截,不配置拦截所有请求registrationBean.setOrder(1); // 过滤顺序,越小越先过滤return registrationBean;}
}

拦截器的使用(方式一):将拦截器通过 XML 方式注入到 Spring 容器中。

<mvc:interceptors><mvc:interceptor><!-- 设置拦截的路径--><!-- /** 表示该文件夹下的所有请求--><!-- /* 表示所有的请求--><mvc:mapping path="/admin/**"/> <!-- 表示拦截admin下面的所有文件夹进行拦截--><!-- 使用哪个拦截器来拦截--><bean class="com.xiayuan.interceptor.MyInterceptor"/></mvc:interceptor>
</mvc:interceptors>

拦截器的使用(方式二):通过配置类的方式注入到 Spring 容器中。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {// 注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {// order越小越先拦截registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").order(1);}
}

执行流程:

image-20230618132123066

多个拦截器执行顺序:多个拦截器主要是通过配置顺序进行执行,也可以通过配置 order 设置执行顺序。

拦截器都放行:preHandle 方法按照拦截器依次执行,postHandle、afterCompletion会按照拦截器顺序倒序执行。

存在拦截器拦截:preHandle 方法按照拦截循序执行,被拦截以及后面的拦截器对应的 preHandle 都不执行。postHandle 所有拦截器都不会执行,afterCompletion 只会执行未被拦截的拦截器并且倒序执行(有一个拦截器执行的 index 记录执行拦截器的下标)。

8、 异常处理

针对异常不想显示为 Spring Mvc 默认的异常处理,可以之定义异常控制器来处理指定的异常。

// 实质就是一个 Controller 控制器
// @ControllerAdvice 方法返回结果是视图名称
@RestControllerAdvice // 方法返回结果是 json 字符串
public class GlobalExceptionHandler {private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);/*** 拦截未知的运行时异常,参数是一个指定处理异常的 Class 对象*/@ExceptionHandler(value = {RuntimeException.class,NullPointerException.class})public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request) {String requestURI = request.getRequestURI();log.error("请求地址'{}',发生未知异常.", requestURI, e);return AjaxResult.error(e.getMessage());}
}

9、理解SpringMVC的执行原理

Spring MVC 的原理图:

未命名文件

深入理解 Spring MVC 原理:

  1. 中心控制器(DispatcherServlet)

Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。

Spring MVC框架像其他其它MVC框架一样,以请求为驱动,围绕一个中心控制器的servlet派送请求和提供功能,中心控制器实际上就是一个servlet,它是继承至HttpServlet基类。所有的请求给中心控制器来拦截,然后在派送请求。

  1. 分析执行流程
  • DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
  • HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
  • HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器。
  • HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
  • HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
  • Handler让具体的Controller执行。
  • Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
  • HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
  • DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  • 视图解析器将解析的逻辑视图名传给DispatcherServlet。
  • DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
  • 最终视图响应给用户。

10、文件上传和下载

导入相应的依赖:

<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version>
</dependency>
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version>
</dependency>

配置文件解析器:

<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 --><property name="defaultEncoding" value="utf-8"/>    <!-- 上传文件大小上限,单位为字节(10485760=10M) --><property name="maxUploadSize" value="10485760"/><property name="maxInMemorySize" value="40960"/>
</bean>

注意:必须配置id属性,因为这个是根据id获取的,bean的id属性的名称必须是multipartResolver。

文件上传控制器(方式一):

public String upload(@RequestParam("my_file") CommonsMultipartFile file , HttpServletRequest request) throws IOException{//获取文件名 : file.getOriginalFilename();String uploadFileName = file.getOriginalFilename();// 如果文件名为空,直接回到首页!if ("".equals(uploadFileName)){return "redirect:/index.jsp";}System.out.println("上传文件名 : "+uploadFileName);// 上传路径保存设置String path = request.getServletContext().getRealPath("/upload");// 如果路径不存在,创建一个        File realPath = new File(path);if (!realPath.exists()){realPath.mkdir();}System.out.println("上传文件保存地址:"+realPath);InputStream is = file.getInputStream(); //文件输入流OutputStream os = new FileOutputStream(new File(realPath,uploadFileName));// 文件输出流// 读取写出int len=0;byte[] buffer = new byte[1024];while ((len=is.read(buffer))!=-1){os.write(buffer,0,len);os.flush();}os.close();is.close();return "redirect:/index.jsp";
}

文件上传控制器(方式二):

/* * 采用file.Transto 来保存上传的文件 */
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("my_file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {//上传路径保存设置String path = request.getServletContext().getRealPath("/upload");File realPath = new File(path);if (!realPath.exists()){realPath.mkdir();}// 上传文件地址System.out.println("上传文件保存地址:"+realPath);// 通过CommonsMultipartFile的方法直接写文件(注意这个时候)file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));return "redirect:/index.jsp";}
}

文件下载(方式一):通过超链接来下载文件,但是存在一个弊端,超链接下载文件对于浏览器能够解析的资源就直接在页面给你展示,浏览器不能够解析的资源会让你下载。

<a href="${pageContext.request.contextPath}/upload/lab.png">通过超链接下载</a>

文件下载(方式二):

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception {//要下载的图片地址String  path = request.getServletContext().getRealPath("/upload");String  fileName = "lab.png";// 1、设置response 响应头response.reset();// 设置页面不缓存,清空bufferresponse.setCharacterEncoding("UTF-8");// 字符编码response.setContentType("multipart/form-data");// 二进制传输数据// 设置响应头response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));File file = new File(path,fileName);// 2、 读取文件--输入流InputStream input=new FileInputStream(file);// 3、 写出文件--输出流OutputStream out = response.getOutputStream();byte[] buff =new byte[1024];int index=0;// 4、执行 写出操作while((index= input.read(buff))!= -1){out.write(buff, 0, index);out.flush();}out.close();input.close();return null;
}

相关文章:

Spring MVC学习笔记,包含mvc架构使用,过滤器、拦截器、执行流程等等

&#x1f600;&#x1f600;&#x1f600;创作不易&#xff0c;各位看官点赞收藏. 文章目录 Spring MVC 习笔记1、Spring MVC demo2、Spring MVC 中常见注解3、数据处理3.1、请求参数处理3.2、响应数据处理 4、RESTFul 风格5、静态资源处理6、HttpMessageConverter 转换器7、过…...

【LeetCode 算法】Linked List Cycle 环形链表

文章目录 Linked List Cycle 环形链表问题描述&#xff1a;分析代码哈希快慢指针 Tag Linked List Cycle 环形链表 问题描述&#xff1a; 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达…...

RedHat7.9安装mysql8.0.32 ↝ 二进制方式

RedHat7.9安装mysql8.0.32 ↝ 二进制方式 一、rpm方式安装1、检查是否安装了mariadb2、下载mysqlmysql8.0.323、上传解压4、创建安装目录&#xff0c;拷贝解压后的文件至安装目录/usr/local/mysql8.0/5、创建相关目录&#xff0c;开始安装6、创建mysql组和用户7、更改安装目录归…...

数据库面试题题

题干&#xff1a; -- 子查询 CREATE TABLE emp( empno INT, ename VARCHAR(50), job VARCHAR(50), mgr INT, hiredate DATE, sal DECIMAL(7,2), comm DECIMAL(7,2), deptno INT ) ; INSE…...

瑞吉外卖项目 基于spring Boot+mybatis-plus开发 超详细笔记,有源码链接

源码地址&#xff1a;https://gitee.com/programmer-xiao-kai/reggie_tack_out 前置知识&#xff1a; Java基础知识Java Web vueSpring BootSSMMaven 软件开发流程 角色分工 项目经理:对整个项目负责&#xff0c;任务分配、把控进度产品经理:进行需求调研&#xff0c;输出需…...

Redis Cluster 在Spring中遇到的问题

Redis集群配置可能会在运行时更改。可以添加新节点&#xff0c;可以更改特定插槽的主节点。还有可能因为master宕机或网络抖动等原因&#xff0c;引起了主从切换。 无法感知集群槽位变化 SpringBoot2.x 开始默认使用的 Redis 客户端由 Jedis 变成了 Lettuce&#xff0c;但是当…...

linux远程桌面管理工具 xrdp

Xrdp 是一个微软远程桌面协议&#xff08;RDP&#xff09;的开源实现&#xff0c;它允许你通过图形界面控制远程系统。通过 RDP&#xff0c;你可以登录远程机器&#xff0c;并且创建一个真实的桌面会话&#xff0c;就像你登录本地机器一样。 如何在Ubuntu 20.04 上安装 Xrdp 服…...

硬件-8-操作系统的历史

操作系统的最强入门科普&#xff08;Unix/Linux篇&#xff09; 操作系统的发展史&#xff08;DOS/Windows篇&#xff09; Mac操作系统进化史 手机操作系统的沉浮往事&#xff08;上&#xff09; 手机操作系统的沉浮往事&#xff08;下&#xff09; 1 操作系统种类 我们天天都…...

self.register_buffer()中的值发生变化

PyTorch中定义模型时&#xff0c;有时候会遇到self.register_buffer(name, Tensor)的操作&#xff0c;该方法的作用是定义一组参数&#xff0c;该组参数的特别之处在于&#xff1a;模型训练时不会更新&#xff08;即调用 optimizer.step() 后该组参数不会变化&#xff0c;只可人…...

[Tools: Pycharm] Bug合集

1. Debug mode&#xff1a;Pycharm不显示变量值&#xff08;Unable to display frame variables&#xff09;&#xff1b;在python console中交互不输出值 选择Gevent compatible&#xff1a;File > Settings > Build, Execution, Deployment > Python Debugger >…...

【JAVASE】循环结构

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 循环 1. 循环结构1.1 while 循环1.2 bre…...

NoSQL之Redis配置使用

目录 一、关系数据库与非关系型数据库 1.1.关系型数据库的概述 1.2关系型数据库的优缺点 1.2.1优点 1.2.2缺点 1.3.非关系型数据库的概述 二.关系数据库与非关系型数据库的区别 2.1数据存储方式不同 2.2扩展方式不同 2.3对事务性的支持不同 2.4非关系型数据库产生背景 2…...

Ansible最佳实践之Playbook使用过滤器处理网络地址

写在前面 使用过滤器检查、验证和操作包含网络信息的变量理解不足小伙伴帮忙指正 傍晚时分&#xff0c;你坐在屋檐下&#xff0c;看着天慢慢地黑下去&#xff0c;心里寂寞而凄凉&#xff0c;感到自己的生命被剥夺了。当时我是个年轻人&#xff0c;但我害怕这样生活下去&#xf…...

测试常见前端bug

目录 协作 测试方法 标签&#xff1a;标签 内容/ref/ 判断 arr&&arr.length 交互 样式不生效&#xff1a;devtools查找&#xff0c;编译前的标签&#xff0c;运行时不一定存在 可交互的需要提示 hover样式 没有交互逻辑&#xff0c;就不要设置交互 无法交互…...

【Python数据分析】Python常用内置函数(一)

&#x1f389;欢迎来到Python专栏~Python常用内置函数&#xff08;一&#xff09; ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;Python学习专栏 文章作者技术和水平有限&#xff0c;如果文…...

OpenCV图像处理-图像分割-MeanShift

MeanShift 1. 基本概念2.代码示例 1. 基本概念 MeanShift严格说来并不是用来对图像进行分割的&#xff0c;而是在色彩层面的平滑滤波。它会中和色彩分布相近的颜色&#xff0c;平滑色彩细节&#xff0c;侵蚀掉面积较小的的颜色区域&#xff0c;它以图像上任意一点P为圆心&…...

【Rust 基础篇】Rust Trait 实现:灵活的接口抽象

导言 Rust是一种以安全性和高效性著称的系统级编程语言&#xff0c;其设计哲学是在不损失性能的前提下&#xff0c;保障代码的内存安全和线程安全。为了实现这一目标&#xff0c;Rust引入了"所有权系统"、"借用检查器"等特性&#xff0c;有效地避免了常见…...

【嵌入式Linux项目】基于Linux的全志H616开发板智能家居项目(语音控制、人脸识别、安卓APP和PC端QT客户端远程操控)有视频功能展示

目录 一、功能需求 二、开发环境 1、硬件&#xff1a; 2、软件&#xff1a; 3、引脚分配&#xff1a; 三、关键点 1、设计模式之工厂模式 2、wiringPi库下的相关硬件操作函数调用 3、语音模块的串口通信 4、线程 5、摄像头的实时监控和拍照功能 6、人脸识别 四、编…...

ElasticSearch基础篇-条件查询与映射

ElasticSearch基础篇二 条件查询 GET http://10.192.193.98:9200/shopping/_search?qtitle:小米手机q:代表查询条件 响应结果 {"took": 772,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped…...

大模型部署框架 FastLLM 实现细节解析

0x0. 前言 接着 大模型部署框架 FastLLM 简要解析 这篇文章首先梳理了一下FastLLM的调用链和关键的数据结构&#xff0c;然后解析了 FastLLM 的一些实现细节和CPU/GPU后端实现采用的优化技巧。 0x1. 调用链和数据结构解析 以chatglm-6b的支持为例&#xff0c;函数入口在 htt…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...