SpringMVC

1. 概述

SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 中。

SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。

MVC:

M:模型层 封装数据 实体类

V:视图层 展示数据的

C: 控制层

客户端:

前端的职责是向后端发起请求 收到后端返回的结果 将结果展示在页面上

  • 浏览器中的网页(前端)

  • App (Android IOS)

  • 小程序

后端:

后端的职责就是接收前端处理的请求,做一些业务逻辑操作(查询数据库)将结果返回给请求者

  • 就是处理前端请求的 PHP JAVA

1.1 请求响应

  • 请求:

    • 是前端向后端发起的,是一次交互。
  • 响应

    • 是后端给前端返回的,是一次交互
  • 请求和响应是一起的,不能分开,有请求,就一定有响应。

2. 快速入门

需求:客户端发起请求,服务器端接收请求,执行逻辑并进行视图跳转。客户端(前端)发起请求,服务端收到请求后打印一句话"收到了请求",进行视图跳转。跳转到成功页面。

2.1 开发步骤

前提:idea配置tomcat

①导入SpringMVC相关坐标

②配置SpringMVC核心控制器DispathcerServlet

③创建Controller类和视图页面

④使用注解配置Controller类中业务方法的映射地址

⑤配置SpringMVC核心文件 spring-mvc.xml(扫描) 加载

⑥客户端发起请求测试

2.2 代码实现

①导入Spring和SpringMVC的坐标、导入Servlet和Jsp的坐标

复制代码
 <!--Spring坐标-->
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>5.0.5.RELEASE</version>
 </dependency>
 <!--SpringMVC坐标-->
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>5.0.5.RELEASE</version>
 </dependency>
<!--Servlet坐标-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>
<!--Jsp坐标-->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.0</version>
</dependency>

②在web.xml配置SpringMVC的核心控制器

复制代码
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>   
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

③创建Controller和业务方法

复制代码
//将该类 放进IOC容器中
//@Controller注解 代表该类 是一个控制器的类
@Controller
public class TestController {

    //接收请求的方法
    //@RequestMapping代表该方法是接收请求的方法
    @RequestMapping("/test")
    public String test_01(){
        //这里返回的是一个页面的路径地址
        System.out.println("收到了前端的请求");
        return "/pages/show.jsp";
    }

}

③创建视图页面show.jsp

复制代码
<html>
<head>
    <title>Title</title>
</head>
<body>
    hello
</body>
</html>

④配置注解

  • @Controller

    • 是将某个类添加进IOC容器中,标注该类是控制器层的类
  • @RequestMapping

    • 放在方法上 代表该方法是处理请求的方法

⑤创建spring-mvc.xml

复制代码
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/mvc   
    http://www.springframework.org/schema/mvc/spring-mvc.xsd  
    http://www.springframework.org/schema/context   
    http://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置注解扫描-->
    <context:component-scan base-package="com.zrrd"/>
</beans>

⑥访问测试地址

2.3 视图跳转传值

以上的示例完成了客户端发起请求,我们后端处理请求,然后进行视图跳转到客户端的某个页面,SpringMVC的请求方法中可以设置一些数据 在跳转视图的时候传递给页面 这个其实就是响应数据,因为单独的页面跳转意义不大。

2.3.1 通过ModelAndView传值

ModelAndView`是 Spring MVC 框架中的一个类,用于在控制器方法中封装模型数据和视图信息。它通常用于将数据传递给视图,并指定要呈现的视图名称。

在 Spring MVC 中,控制器方法通常返回 ModelAndView 对象来指示响应的数据和视图。该对象包含两个主要部分:

  1. Model 数据:用于在视图中渲染的模型数据,以键值对的形式存在。这些数据可以在视图中使用 EL 表达式或者其他方式进行访问和展示。

  2. View 视图:要呈现的视图的名称,通常是 JSP、Thymeleaf 或其他视图技术的逻辑名称。

示例:

复制代码
    @RequestMapping("/test")
    public ModelAndView test() {
        //创建ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        //设置数据
        modelAndView.addObject("name", "张三");
        modelAndView.addObject("age", 20);
        //设置视图名称
        modelAndView.setViewName("/pages/show.jsp");
        return modelAndView;
    }

jsp页面

复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    姓名:${name} <br> 年龄:${age}

</body>
</html>

页面中通过${键}取值 这种是el表达式的写法

注意事项:isELIgnored="false" 代表不禁用el表达式

2.3.2 HttpServlet相关类传值

SpringMVC能处理请求的核心就是DispatcherServlet,底层本质其实也是一个Servlet。也就是说在接收请求的方法中 其实已经传过来了HttpServlet类的相关类对象。可以在方法的参数列表中直接定义接收

  • HttpServletRequest

    • 等同于前端传递过来的请求对象 可以通过该对象将数据存入到request域中

      复制代码
      @RequestMapping("/test")
      public String test(HttpServletRequest request) {
          request.setAttribute("name","张三");
          request.setAttribute("age",20);
          return "/pages/show.jsp";
      }

扩展知识点:

转发和重定向

转发是前端向后端发起请求 后端不处理本次请求 转发给其他人,转发实际上是1次请求。

重定向是前端向后端发起请求 后端在开启一个新的请求 去请求其他地方,重定向其实是多次请求

如何区分当前请求 是转发还是重定向,就看浏览器是否打开了新的窗口

重定向的话 地址栏的地址 会发生变化!

小提示:

接收请求的方法中 return返回的是页面文件的路径字符串,默认是转发操作,也可以更改为重定向操作

return "redirect:/页面路径.jsp"

3. 执行流程

3.1 图解

  1. 用户发送请求至前端控制器DispatcherServlet。

  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。

  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

  4. DispatcherServlet调用HandlerAdapter处理器适配器。

  5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

  6. Controller执行完成返回ModelAndView。success

  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

  9. ViewReslover解析后返回具体View。

  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。

3.2 组件解析

  • 前端控制器:DispatcherServlet

    • 用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
  • 处理器映射器:HandlerMapping

    • HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
  • 处理器适配器:HandlerAdapter

    • 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
  • 处理器:Handler

    • 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
  • 视图解析器:View Resolver

    • View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
  • 视图:View

    • SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面

3.3 SpringMVC的XML配置解析

SpringMVC有默认组件配置,默认组件都是DispatcherServlet.properties配置文件中配置的,该配置文件地址org/springframework/web/servlet/DispatcherServlet.properties,该文件中配置了默认的视图解析器,如下:

复制代码
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

翻看该解析器源码,可以看到该解析器的默认设置,如下:

REDIRECT_URL_PREFIX = "redirect:" --重定向前缀

FORWARD_URL_PREFIX = "forward:" --转发前缀(默认值)

prefix = ""; --视图名称前缀

suffix = ""; --视图名称后缀

我们可以通过属性注入的方式修改视图的的前后缀

复制代码
<!--配置内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/pages/"></property>
  <property name="suffix" value=".jsp"></property>
</bean>

4. 常用注解

4.1 控制器层的注解

4.1.1 @Controller
  • 作用:

    该注解的作用是将类添加进IOC容器中,使用@Controller注解的含义是标注一个类为SpringMVC的控制器

  • 位置

    类上

    @Controller注解里面封装了@Component

4.2 接收请求的注解

请求的方式:

浏览器地址栏的请求 默认是GET 也只能是GET请求 如果我们想使用POST请求有以下几种方式

  1. 自己编写一个前端页面 页面中写表单form 表达提交的方式可以改为POST

  2. 使用请求的测试软件

常用的软件 POSTMAN

使用:

4.2.1 @RequestMapping
  • 作用:

    • 用于建立请求 URL(网址) 和处理请求方法之间的对应关系
  • 位置

    • 类上,请求URL 的第一级访问目录。此处不写的话,就相当于应用的根目录

    • 方法上,请求 URL 的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起组成访问虚拟路径

  • 属性

    • value:用于指定请求的URL。它和path属性的作用是一样的

    • method:用于指定请求的方式 如果方式不对 报错405

    • params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样,如果参数有误 报错400

params = {"accountName"},表示请求参数必须有accountName

params = {"moeny!100"},表示请求参数中money不能是100

4.2.2 @GetMapping
  • 作用:

    • 和RequestMapping注解作用一致,区别是如果使用该注解 只能接收GET方式的请求。该注解一般用于接收查询的请求
  • 位置

    • 方法上
  • 实例

    复制代码
     //测试GET请求
      @GetMapping("/test04")
      public String test_04(){
          return "show";
      }
4.2.3 @PostMapping
  • 作用:

    • 和RequestMapping注解作用一致,区别是如果使用该注解 只能接收POST方式的请求。该注解一般用于接收新增的请求
  • 位置

    • 方法上
  • 实例

    复制代码
      //测试POST请求
      @PostMapping("/test05")
      public String test_05(){
          return "show";
      }
4.2.4 @PutMapping
  • 作用:

    • 和RequestMapping注解作用一致,区别是如果使用该注解 只能接收PUT方式的请求(PUT方式和POST方式类似)。该注解一般用于接收更新的请求
  • 位置

    • 方法上
  • 实例

    复制代码
      //测试PUT请求
      @PutMapping("/test06")
      public String test_06(){
          return "show";
      }
4.2.5 @DeleteMapping
  • 作用:

    • 和RequestMapping注解作用一致,区别是如果使用该注解 只能接收DELETE方式的请求。该注解一般用于接收删除的请求
  • 位置

    • 方法上
  • 实例

    复制代码
      //测试DELETE请求
      @DeleteMapping("/test07")
      public String test_07(){
          return "show";
      }

总结:

以上4个注解和@RequestMapping注解的使用方式一致,唯一的区别就是限定了请求的方式。实际上在开发中,我们处理的每一个请求 也应该规定请求方式,这样更符合规范。

4.3 请求参数相关的注解

4.3.1 @RequestParam
  • 作用:

    • 用于提取请求中的参数值,用于请求的参数和我们实际接收的参数名称不一致的情况。
  • 位置:

    • 方法中的参数列表中
  • 实例

    复制代码
      //测试@RequestParam注解
      @GetMapping("/test08")
      public String test_08(@RequestParam("name") String aaa,int age){
          System.out.println(aaa);
          System.out.println(age);
          return "show";
      }
4.3.2 @PathVariable
  • 作用:

    • 用于将 URI 模板变量映射到处理方法的参数,用于restful风格的请求
  • 位置:

    • 方法中的参数列表中
4.3.3 @RequestBody

JSON是一种数据格式,本质上其实就是一个字符串,在开发当中,前端可能会传递给后端json数据作为参数 后端给前端影响数据的时候,一般也是响应JSON数据 json都是有意义的,大部分情况 都是把一个对象转为json 或者把一个集合转为json

{

"name": "张三",

"age": 20,

"sex": "男"

}

以上数据就是一个json数据 代表一个学生对象

json的常用操作:

  • 将json数据转为对象

    复制代码
      @Test
      public void jsonToObject() throws JsonProcessingException {
          //定义一个json数据
          String json = "{\n" +
                  "\t\"name\": \"张三\",\n" +
                  "\t\"age\": 20,\n" +
                  "\t\"sex\": \"男\"\n" +
                  "}";
          ObjectMapper mapper = new ObjectMapper();
          //将json数据转为对象
          Student student = mapper.readValue(json, Student.class);
          System.out.println(student);
    
      }

将对象转为json

复制代码
    //将对象转为json
    @Test
    public void objectToJson() throws JsonProcessingException {
        //定义一个对象
        Student student = new Student("张三",20,"男");
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(student);
        System.out.println(json);
    }
  • 注意:

    必须要导入相关依赖

  • 作用:

    • 如果前端传递过来的参数是一个json数据,可以通过该注解将json转为对象来接收。
  • 位置:

    • 方法中的参数列表中

注意:

要完成前端传递的json 后端通过@RequestBody注解来将json自动转为实体类的对象 还需要配置以下几个步骤。

  1. 设置请求头支持json类型

Content-Type = application/json

2.添加json解析、生成的依赖

复制代码
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.10.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.1</version>
        </dependency>

3.配置消息类型转换器将JSON数据转换为Java对象。

RequestMappingHandlerAdapter是处理适配器,可用在Spring-xml.xml配置文件中使用

复制代码
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>
  1. 更简单的方法可以使用<mvc:annotation-driven />来自动加载驱动,默认底层就会集成jackson进行对象或集合的json格式字符串的转换

4.4 设置响应的注解

4.4.1 @ResponseBody
  • 作用:

    • 使用该注解后,整个方法的返回值就不会进行视图跳转,而是返回具体的内容,前后端分离开发的情况,该注解必须使用。
  • 位置:

    • 方法上
  • 实例

    • 响应基本类型的数据 int string

      复制代码
      @GetMapping(value = "/test11",produces = "application/json; charset=UTF-8")
      @ResponseBody
      public String test_11(){
          return "你好你好";
      }

响应json形式的数据 比如将一个学生对象转为json在响应

复制代码
    @GetMapping(value = "/test12",produces = "application/json; charset=UTF-8")
    @ResponseBody
    public String test_12() throws JsonProcessingException {
        //创建一个学生对象
        Student student = new Student("油桃",18,"男");
        //创建操作json的对象
        ObjectMapper mapper = new ObjectMapper();
        //将对象转为json字符串
        String json = mapper.writeValueAsString(student);
        return json;
    }

如果需要将一个对象转为josn在响应 可以不用手动转换 框架会自动帮我们完成 前提是

  1. 导入依赖

  2. 配置文件中配置

    复制代码
    <mvc:annotation-driven />
  3. 直接在方法中返回对象即可

    复制代码
     @GetMapping(value = "/test13",produces = "application/json; charset=UTF-8")
     @ResponseBody
     public List<Student> test_13() throws JsonProcessingException {
         //创建一个集合
         List<Student> list = new ArrayList<Student>();
         //创建一个学生对象
         Student student1 = new Student("油桃",18,"男");
         Student student2 = new Student("熊大",28,"男");
         Student student3 = new Student("熊二",20,"女");
         list.add(student1);
         list.add(student2);
         list.add(student3);
         return list;
     }

如果不需要响应

复制代码
   @GetMapping("/test14")
    @ResponseBody
    public void test_14(){
        System.out.println("收到了请求 不打算响应");
    }

4.5 相关配置

4.5.1 乱码问题

在接收前端请求参数或者返回给前端数据的时候,如果数据中有中文,可能会有乱码的情况,原因是没有设置指定的编码格式

  • 接收参数是乱码

    在web.xml文件中配置

    复制代码
    <!--配置全局过滤的filter-->
    <filter>
      <filter-name>CharacterEncodingFilter</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>
    </filter>
    <filter-mapping>
      <filter-name>CharacterEncodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

响应数据是乱码

在请求方法上 @RequestMapping注解中使用produces参数来设置编码格式

@RequestMapping(value = "/test01",produces = "application/json; charset=UTF-8")

4.5.2 开启静态资源访问

当有静态资源需要加载时,比如在jsp文件中加载一个项目中本地的图片。如果没有对应的设置 会导致加载失败。

  • 在spring-mvc.xml配置文件中指定放行的资源

<mvc:resources mapping="/images/**" location="/images/"/>

使用<mvc:default-servlet-handler/>标签

<mvc:default-servlet-handler/>

5. 类型转换器

SpringMVC 默认已经提供了一些常用的类型转换器,例如客户端提交的字符串转换成int型进行参数设置。

但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。

5.1 实现步骤

  1. 定义转换器类实现Converter接口

  2. 在配置文件中声明转换器

  3. 在<annotation-driven>中引用转换器

5.2 实现功能

需求:将前端请求传递过来的String类型 用Date类型接收

  1. 定义转换器类实现Converter接口

    public class DateConverter implements Converter<String, Date> {
    public Date convert(String dateStr) {
    //将日期字符串转换成日期对象 返回
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    Date date = null;
    try {
    date = format.parse(dateStr);
    } catch (ParseException e) {
    e.printStackTrace();
    }
    return date;
    }
    }

2.在配置文件中声明转换器

复制代码
<bean id="converterService"  
   class="org.springframework.context.support.ConversionServiceFactoryBean"> 
       <property name="converters"> 
            <list>            
                <bean class="cn.doyens.converter.DateConverter"/>
           </list>  
        </property>
</bean>

3.在<annotation-driven>中引用转换器

<mvc:annotation-driven conversion-service="converterService"/>

4.测试

复制代码
   //测试自定义的类型转换器
    @GetMapping("/test15")
    @ResponseBody
    public void test_15(Date date){
        System.out.println(date);
    }

6. 文件上传

文件上传就是前端给我们后端通过请求 传递的参数是一个文件,使用场景有很多,比如修改用户的头像,上传商品的封面等等,

6.1 前端实现

文件上传客户端表单需要满足:

  • 表单项type="file"

  • 表单的提交方式是post

  • 表单的enctype属性是多部分表单形式,及enctype="multipart/form-data"

    <form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data"> 名称
    文件1
    </form>

6.2 后端实现

6.2.1 添加依赖
复制代码
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.3</version>
    </dependency>
6.2.2 配置多媒体解析器
复制代码
<!--配置文件上传解析器  id必须是multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="maxUploadSize" value="500000"/>
    </bean>
6.2.3 接收请求的方法
复制代码
@RequestMapping(value="/method01")
    @ResponseBody
    public void method01(String username, MultipartFile uploadFile) throws IOException {
        System.out.println(username);
       	System.out.println(uploadFile);
    }
6.2.4 MultipartFile

在以上的接受请求方法中,接收前端的文件 使用MultipartFile接口来接收,

MultipartFile相关的API

  1. getOriginalFilename获取上传的文件名

  2. getSize():获取上传的文件大小

  3. transferTo(File path)将文件写到目的地中

作为后端来说 我们要做的就是接收前端传递过来的文件,然后作对应的处理,这个处理其实就是将文件存到某个地方

一般来说可以存入到2个位置

  1. 本地磁盘中的某个位置

    复制代码
     //将收到的文件 存入到本地磁盘某个位置
     @PostMapping("/upload01")
     @ResponseBody
     public void uploadFile01(String username, MultipartFile photo) throws IOException {
         System.out.println("用户名:" + username);
         //1.获取文件名字
         String filename = photo.getOriginalFilename();
         //2.使用UUID工具类生成不重复的字符串作为文件名字
         filename = UUID.randomUUID() + filename;
         //2.直接写入到某个位置
         photo.transferTo(new File("D:\\", filename));
     }

2.服务器中的某个位置

复制代码
//将收到的文件 存入到服务器的某个位置
    @PostMapping("/upload02")
    @ResponseBody
    public void uploadFile02(String username, MultipartFile photo, HttpServletRequest request) throws IOException {
        System.out.println("用户名:" + username);
        //1.获取文件名字
        String filename = photo.getOriginalFilename();
        //2.使用UUID工具类生成不重复的字符串作为文件名字
        filename = UUID.randomUUID() + filename;
        //3.获取服务器的上下文对象
        ServletContext servletContext = request.getSession().getServletContext();
        //4.根据上下文对象 获取服务器的某个位置(服务器中不一定会有该文件夹)
        String realPath = servletContext.getRealPath("/youtao");
        //5.判断该文件夹是否存在
        File file = new File(realPath);
        if (!file.exists()) {
            //创建文件夹
            file.mkdirs();
        }

        System.out.println("服务器的路径:"+realPath);

        //2.直接写入到某个位置
        photo.transferTo(new File(realPath, filename));
    }
6.2.5 多文件上传

多文件上传简单来说就是前端一次性可以传多个文件,后端的处理逻辑都是一样的。只是将MultipartFile对象 改编成MultipartFile[]数组来接收,在方法中遍历数组获取到每个MultipartFile对象即可

复制代码
//多文件上传
    @PostMapping("/upload03")
    @ResponseBody
    public void uploadFile03(String username, MultipartFile[] photo, HttpServletRequest request) throws IOException {
        System.out.println("用户名:" + username);

        //遍历文件数组
        for (MultipartFile multipartFile : photo) {
            //1.获取文件名字
            String filename = multipartFile.getOriginalFilename();
            //2.使用UUID工具类生成不重复的字符串作为文件名字
            filename = UUID.randomUUID() + filename;
            //3.获取服务器的上下文对象
            ServletContext servletContext = request.getSession().getServletContext();
            //4.根据上下文对象 获取服务器的某个位置(服务器中不一定会有该文件夹)
            String realPath = servletContext.getRealPath("/youtao");
            //5.判断该文件夹是否存在
            File file = new File(realPath);
            if (!file.exists()) {
                //创建文件夹
                file.mkdirs();
            }
            System.out.println("服务器的路径:"+realPath);

            //2.直接写入到某个位置
            multipartFile.transferTo(new File(realPath, filename));
        }

    }

7. 异常处理机制

7.1 异常处理的思路

系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。

系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理,如下图:

7.2 异常处理的方式

  1. 使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver

  2. 实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器

7.2.1 简单异常处理器

SpringMVC已经定义好了该类型转换(SimpleMappingExceptionResolver),在使用时可以根据项目情况进行相应异常与视图的映射配置

复制代码
    <!--配置简单映射异常处理器-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="defaultErrorView" value="error"/>
        <property name="exceptionMappings">
            <map>
                <entry key="com.zrrd.exception.MyException" value="error"/>
                <entry key="java.lang.ClassCastException" value="error"/>
            </map>
        </property>
    </bean>
7.2.2 自定义异常处理器

①创建异常处理器类实现HandlerExceptionResolver

复制代码
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, 
    HttpServletResponse response, Object handler, Exception ex) {
    //处理异常的代码实现
    //创建ModelAndView对象
    ModelAndView modelAndView = new ModelAndView(); 
    modelAndView.setViewName("exceptionPage");
    return modelAndView;
    }
}

②配置异常处理器

复制代码
<bean id="exceptionResolver"        
      class="com.zrrd.exception.MyExceptionResolver"/>

③编写异常页面

复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
	<title>Title</title>
</head>
<body>
	这是一个最终异常的显示页面
</body>
</html>

④测试异常跳转

复制代码
@RequestMapping("/quick22")
@ResponseBody
public void quickMethod22() throws IOException, ParseException {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); 
    simpleDateFormat.parse("abcde");
}

8. 拦截器

8.1 SpringMVC拦截器概述

Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理后处理

将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

8.2 快速入门

自定义拦截器很简单,只有如下三步:

①创建拦截器类实现HandlerInterceptor接口

复制代码
public class MyInterceptor1 implements HandlerInterceptor {
    //在目标方法执行之前 执行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object 			handler) throws ServletException, IOException {
             System.out.println("preHandle.....");
	}
 
}

②配置拦截器

复制代码
<!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--对哪些资源执行拦截操作-->
            <mvc:mapping path="/**"/>
            <bean class="com.zrrd.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

③测试拦截器的拦截效果

复制代码
@Controller
public class TargetController {

    @RequestMapping("/target")
    public ModelAndView show(){
        System.out.println("目标资源执行......");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name","doyens");
        modelAndView.setViewName("index");
        return modelAndView;
    }

}
  • preHandle:

    • 在目标方法执行之前 执行
  • postHandle:

    • 在目标方法执行之后 视图对象返回之前执行
  • afterCompletion:

    • 在流程都执行完毕后 执行
相关推荐
num_killer7 小时前
小白的Langchain学习
java·python·学习·langchain
期待のcode8 小时前
Java虚拟机的运行模式
java·开发语言·jvm
程序员老徐8 小时前
Tomcat源码分析三(Tomcat请求源码分析)
java·tomcat
a程序小傲8 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
仙俊红8 小时前
spring的IoC(控制反转)面试题
java·后端·spring
阿湯哥8 小时前
AgentScope Java 集成 Spring AI Alibaba Workflow 完整指南
java·人工智能·spring
小楼v8 小时前
说说常见的限流算法及如何使用Redisson实现多机限流
java·后端·redisson·限流算法
与遨游于天地9 小时前
NIO的三个组件解决三个问题
java·后端·nio
czlczl200209259 小时前
Guava Cache 原理与实战
java·后端·spring
yangminlei9 小时前
Spring 事务探秘:核心机制与应用场景解析
java·spring boot