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

news2024/11/15 21:29:13

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

文章目录

  • 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/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc
                           http://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 {

    @Override
    public 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返回给DispatcherServlet
        return 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/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc
                           http://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 {

    // 初始化方法,这个方法必须执行成功,否则过滤器不生效
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 进行业务处理,如果不放行就通过request重定向或转发到对应页面
       
        // 放行请求
        filterChain.doFilter(servletRequest,servletResponse);
    }

    // 拦截器销毁方法
    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

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

// 自定义拦截器
@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public 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 {
    // 注册拦截器
    @Override
    public 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();
    // 设置页面不缓存,清空buffer
    response.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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/806446.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iOS开发-下拉刷新动画依次渐隐渐显Indicator指示器效果

iOS开发-下拉刷新动画依次渐隐渐显Indicator指示器效果 之前开发中实现下拉刷新动画三个球依次渐隐渐显指示器效果。 一、效果图 二、基础动画 CABasicAnimation类的使用方式就是基本的关键帧动画。 所谓关键帧动画&#xff0c;就是将Layer的属性作为KeyPath来注册&#xf…

【Linux进程】进程控制(下) {进程程序替换:程序替换的工作原理,程序替换函数exec*,简单的命令行解释器}

四、进程程序替换 之前用fork创建子进程后&#xff0c;父子进程执行同一个程序的不同代码段。 如何使子进程执行另一个不同的程序呢&#xff1f;子进程需要进行程序替换&#xff01; 程序替换&#xff0c;就是通过特定的接口&#xff0c;将磁盘上一个全新的程序&#xff08;包…

STL中的神秘“指针”:迭代器

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;C学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最大…

【Linux】- RPM 与 YUM

RPM 与 YUM 1.1 rpm 包的管理1.2 rpm 包的简单查询指令1.3 rpm 包的其它查询指令&#xff1a;1.4 卸载 rpm 包&#xff1a;2.1 安装 rpm 包3.1 yum3.2 yum 的基本指令3.3 安装指定的 yum 包3.4 yum 应用实例&#xff1a; 1.1 rpm 包的管理 介绍 rpm 用于互联网下载包的打包及安…

SDN系统方法 | 9. 接入网

随着互联网和数据中心流量的爆炸式增长&#xff0c;SDN已经逐步取代静态路由交换设备成为构建网络的主流方式&#xff0c;本系列是免费电子书《Software-Defined Networks: A Systems Approach》的中文版&#xff0c;完整介绍了SDN的概念、原理、架构和实现方式。原文: Softwar…

【Spring Boot丨序列化、反序列化】

序列化、反序列化 概述Jackson 序列化和反序列化简介自定义序列化器注册外部序列化程序&#xff1a; 指定类的 Json 序列化、反序列化 主页传送门&#xff1a;&#x1f4c0; 传送 概述 序列化是将对象转换为字节序列的过程&#xff0c;而反序列化则是将字节序列恢复为对象的过…

用于系统监控及进程管理python库之psutil

前言 对于一个job级别应用再进行测试的过程中&#xff0c;不可避免测试该服务的一些性能&#xff0c;比如占有cpu的使用量&#xff0c;使用的memory的大小等&#xff0c;比较简单的方式是在服务中起一个并行的线程&#xff0c;每隔一段时间打印这些关注量的大小&#xff0c;之后…

【二分答案】CF1661 C

Problem - C - Codeforces 题意&#xff1a; 思路&#xff1a; 在check的时候&#xff0c;我们要尽量用算贡献的思想&#xff0c;并且大胆贪心 Code&#xff1a; #include <bits/stdc.h>#define int long longusing namespace std;const int mxn3e510; const int mxe3…

MySQL基础扎实——列对比运算符是什么

词义解释 在MySQL中&#xff0c;用于进行列对比的运算符主要有以下几种&#xff0c;其实就是逻辑运算符号&#xff1a; 等号&#xff08;&#xff09;&#xff1a;用于判断两个列是否相等&#xff0c;例如&#xff1a;column_name value。 不等号&#xff08;<>或!&am…

Verilog语法学习——边沿检测

边沿检测 代码 module edge_detection_p(input sys_clk,input sys_rst_n,input signal_in,output edge_detected );//存储上一个时钟周期的输入信号reg signal_in_prev;always (posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)signal_in_prev < 0;else…

95. Python基础教程:异常处理try...except语句

【目录】 文章目录 1. try...except语法解析2. 程序异常3. except的4种使用方式3.1 单独的except3.2 except 异常名称3.3 except 异常类型 as 别名3.4 except (异常类型1,异常类型2) as 别名 4. 总结 【正文】 1. try…except语法解析 try[traɪ]&#xff1a;尝试。 except[…

【QT】Day4

1> 思维导图 2> 手动完成服务器的实现&#xff0c;并具体程序要注释清楚 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器类 #include <QTcpSocket> //客户端类 #include <QMessageBox> //…

综合能源系统(4)——综合能源系统建模方法

综合能源系统关键技术与典型案例  何泽家&#xff0c;李德智主编 本文主要从物理、信息、价值三个方面介绍综合能源系统关键技术&#xff0c;如图3-1所示。 物理方面&#xff1a;主要包括综合能源系统建模分析技术、规划设计(配置)技术、优化控制技术、运行维护技术和综合评…

mybatisPlus之逻辑删除解读

目录 为什么会有逻辑删除 逻辑删除基本介绍 逻辑删除的使用 局部使用 全局使用 为什么会有逻辑删除 在我们对数据进行增删查改的时候&#xff0c;对于删除操作来说&#xff0c;我们思考一个问题&#xff0c;在实际开发中我们真的会将数据完成从数据库中删除掉么&#xff1f…

二叉搜索树(二叉排序树)

文章目录 基本概念基本操作实现分析插入数据查找数据删除数据遍历数据 源码 基本概念 二叉搜索树也叫搜索二叉树、二叉排序树、排序二叉树。是一种对查找和排序都有用的特殊二叉树。 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称BST&#xff09; 如何构建一颗二叉…

【使用维纳滤波进行信号分离】基于维纳-霍普夫方程的信号分离或去噪维纳滤波器估计(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【Windows】WDS中如何跳过语言选择以及身份验证

WDS&#xff08;Windows Deployment Services&#xff09;是微软的一项网络服务&#xff0c;用于快速和方便地部署Windows操作系统到多台计算机上。它提供了一种自动化的方式来安装、配置和管理操作系统映像&#xff0c;使企业能够快速部署和更新大量的计算机系统。网上有很多W…

二叉搜索树的本质

引言 打算写写树形数据结构&#xff1a;二叉查找树、红黑树、跳表和 B 树。这些数据结构都是为了解决同一个基本问题&#xff1a;如何快速地对一个大集合执行增删改查。 本篇是第一篇&#xff0c;讲讲搜索树的基础&#xff1a;二叉搜索树。 基本问题 如何在一千万个手机号中…

设计模式-中介者模式在Java中使用示例-客户信息管理

场景 欲开发客户信息管理窗口界面&#xff0c;界面组件之间存在较为复杂的交互关系&#xff1a;如果删除一个客户&#xff0c; 要在客户列表(List)中删掉对应的项&#xff0c;客户选择组合框(ComboBox)中客户名称也将减少一个&#xff1b; 如果增加一个客户信息&#xff0c;…

SpringBoot2.7集成Swagger3.0和knife4j实现API接口文档开发

1. 概述 Swagger 3 是一个用于描述、构建和测试 RESTful Web 服务的开源工具集。它提供了一种简单而强大的方式来定义和文档化 API 接口&#xff0c;同时还具备自动生成客户端代码和服务器存根代码的功能。 Knife4j是一个集Swagger2 和 OpenAPI3为一体的增强解决方案&#xff…