SpringMVC

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。SpringMVC,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

4.SpringMVC
  • SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。
  • SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。
  • SpringMVC核心流程
4.1.SpringMVC入门案例
  • 引入依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.cskaoyan</groupId>
        <artifactId>demo1-introduction</artifactId>
        <version>1.0-SNAPSHOT</version>
        <!-- 这个标签可以将webapp文件夹配置为web路径 -->
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0-alpha-1</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    
    </project>
    
  • 在main根路径创建一个webapp路径,再在此路径下创建一个WEB-INF路径
    • 在Project Structure设置里,Facts选项中,配置webapp文件夹为web路径,或者在pom.xml中增加package标签
  • 在WEB-INF路径下,新增一个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">
        
        <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:application.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <!--除了web资源根路径下的jsp文件,其余所有都经过dispatcherServlet-->
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>
    
  • 在resource文件夹下建立application.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">
        
        <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:application.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <!--除了web资源根路径下的jsp文件,其余所有都经过dispatcherServlet-->
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    </web-app>
    
  • 创建controller层,controller层的类必须实现Controller接口
    //访问/hello请求,能够访问到hello.jsp,并且呈现hello springmvc
    //组件id必须和请求url相关联,因此要修改id值为url部分
    @Component("/hello")
    public class HelloController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("/WEB-INF/hello.jsp");
            //在对应jsp文件中,将SpringMVC字符串传入result参数
            modelAndView.addObject("result", "SpringMVC");
            return modelAndView;
        }
    }
    
  • 在WEBINF目录下创建一个hello.jsp,用于展示前端页面
    <%--
      Created by IntelliJ IDEA.
      User: stone
      Date: 2021/4/1
      Time: 14:29
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <!-- ${result}表示接收参数 -->
    <h1>hello ${result}</h1>
    </body>
    </html>
    
  • 配置Tomcat,在Deployment选项卡中选择war包,运行Tomcat,访问对应应用的hello页面,即可展示字符串
4.2.注解映射
  • 和上述案例同样,改为注解映射的方式
  • 引入依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.cskaoyan</groupId>
        <artifactId>demo2-requestmapping</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0-alpha-1</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    </project>
    
  • 创建webapp目录,创建WEBINF目录和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">
    
        <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:application.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 创建Spring配置文件application.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <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:aop="http://www.springframework.org/schema/aop"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- bean definitions here -->
        <context:component-scan base-package="com.cskaoyan"/>
        <!--RequestMappingHandlerMapping-->
        <!--RequestMappingHandlerAdapter-->
        <!--该标签也帮我们注册了HandlerMapping和HandlerAdapter-->
        <mvc:annotation-driven/>
    
        <!--缺少包含handlerMethod的handler组件-->
    
    </beans>
    
  • controller层,通过注解方式可以不实现接口
    //handler组件
    @Controller
    public class HelloController {
    
        //handlerMethod
        @RequestMapping("/hello")
        public ModelAndView hello(){
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("/WEB-INF/hello.jsp");
            modelAndView.addObject("result", "SpringMVC2");
            return modelAndView;
        }
    
        //获取容器的实例
        @Autowired
        ApplicationContext applicationContext;
    
        //不同的请求的时候,/可以不写
        @RequestMapping("login")
        public ModelAndView login(){
            ModelAndView modelAndView = new ModelAndView("/WEB-INF/hello.jsp");
            modelAndView.addObject("result", "景甜,登录成功");
            
            //获取所有组件的名字,封装为字符串数组
            String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
            
            //打印容器中有哪些组件
            for (String beanDefinitionName : beanDefinitionNames) {
                System.out.println(beanDefinitionName);
            }
            return modelAndView;
        }
    }
    
  • 创建jsp前端页面hello.jsp,用于展示
    <%--
      Created by IntelliJ IDEA.
      User: stone
      Date: 2021/4/1
      Time: 14:29
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <!-- ${result}表示接收参数 -->
    <h1>hello ${result}</h1>
    </body>
    </html>
    
  • 访问对应的login页面,可以看到控制台打印出了组件
4.3.Handler方法
4.3.1.url路径映射
  • 一个url映射到一个handler方法删:直接在方法名上声明,修改该注解的value值,表示访问路径,如上案例
  • 多个url映射到同一个方法上:
    • controll层
      @Controller
      public class HelloController {
      
          //value属性:String[],多个url映射到一个handler方法上
          @RequestMapping({"hello1","hello2","hello3"})
          public ModelAndView hello1(){
              ModelAndView modelAndView = new ModelAndView("/WEB-INF/hello.jsp");
              modelAndView.addObject("result", "SpringMVC3");
              return modelAndView;
          }
      
          @RequestMapping({"goodbye*","goodbye/*"})
          public ModelAndView goodBye(){
              return new ModelAndView("/WEB-INF/goodbye.jsp");
          }
      
      }
      
    • 再创建一个新的前端页面goodbye.jsp
      <%--
        Created by IntelliJ IDEA.
        User: stone
        Date: 2021/4/1
        Time: 15:20
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      	<h1>再见</h1>
      </body>
      </html>
      
  • 一个url映射到多个方法上,以后介绍
4.3.2.窄化请求
  • 提取公共的url部分,在类上加上注解@ResultMapping(“公共部分”),会自动拼接

    • controller层
      @Controller
      @RequestMapping("user")  //提取公共部分
      public class UserController {
      
          //把请求url从handler方法上的@RequestMapping注解的value属性值中提取出去
          //提取到类上 @RequestMapping("user")
          //Handler方法映射的url = 类上的RequestMapping的value属性值 + 方法上的ReqestuMapping的value属性值
          @RequestMapping("login")  //相当于访问user/login,可以不用写/
          public ModelAndView login(){
              return new ModelAndView("/WEB-INF/login.jsp");
          }
          @RequestMapping("register")  //相当于访问user/register
          public ModelAndView register(){
              return new ModelAndView("/WEB-INF/register.jsp");
          }
          @RequestMapping("logout")  //相当于访问user/logout
          public ModelAndView logout(){
              return new ModelAndView("/WEB-INF/logout.jsp");
          }
      
          //@RequestMapping("modify")
          //@RequestMapping("delete")
      }
      
  • 请求方法限定

    • 限定请求方法,要求只能通过某种请求访问的时候,对应的handler方法才会响应
    • controller层:
      //请求方法限定
      @Controller
      @RequestMapping("method") //窄化请求
      public class RequestMethodLimitController {
      
          //@RequestMapping(value = "get",method= RequestMethod.GET) //url = method/get
          @GetMapping("get")  //与上面注释的写法等价,value值为url拼接部分
          public ModelAndView methodGet(){
              ModelAndView modelAndView = new ModelAndView("/WEB-INF/method.jsp");
              modelAndView.addObject("method", "GET");
              return modelAndView;
          }
      
          //@RequestMapping(value = "post",method = RequestMethod.POST) //url = method/post
          @PostMapping("post")
          public ModelAndView methodPost(){
              ModelAndView modelAndView = new ModelAndView("/WEB-INF/method.jsp");
              modelAndView.addObject("method", "POST");
              return modelAndView;
          }
      
          //请求方法之间的关系是 or,请求方法为get或post
          @RequestMapping(value = "double",method = {RequestMethod.GET,RequestMethod.POST})
          public ModelAndView methodDouble(){
              ModelAndView modelAndView = new ModelAndView("/WEB-INF/method.jsp");
              modelAndView.addObject("method", "GET or POST");
              return modelAndView;
          }
      }
      
  • 请求参数限定

    • 限定url后携带的参数,包含所有限定参数才能通过handler处理。参数不符合规则报错代码为400。
    • controller层
      //请求参数限定
      @Controller
      @RequestMapping("parameter")
      public class ParameterLimitController {
      
          //localhost:8080/parameter/login?username=jingtian&password=niupi
          //@RequestMapping(value = "login",params = "username")//限定请求参数一定要携带username
          //@RequestMapping(value = "login",params = "password")//限定请求参数一定要携带password
          //@RequestMapping(value = "login",params = {"username","password"})//限定请求参数一定要携带username and password
          @RequestMapping(value = "login",params = {"username!=jingtian","password"})//限定请求参数一定要携带username and password,并且username不能是jingtian
          public ModelAndView login(){
              return new ModelAndView("/WEB-INF/parameter.jsp");
          }
      }
      
  • 请求头限定

    • 限定包含请求头或限定固定请求头的值
      • 限定特定的请求头,一般只限定两个,一个是Accept请求头,另一个是Content-Type,限定的是他们的值
        • Accept请求头:通过produces属性来限定,不符合限定返回406错误码
        • Content-Type请求头:通过consumes属性来限定,不符合限定返回415错误码
      @Controller
      @RequestMapping("header")
      public class RequestHeaderLimitController {
      
          //限定必须包含abc和def的请求头
          @RequestMapping(value = "limit",headers = {"abc","def"})//and
          public ModelAndView headerLimit(){
              return new ModelAndView("/WEB-INF/header.jsp");
          }
      
          //限定accept和contentType对应的值的类型格式写法是  xxx/xxx
          @RequestMapping(value = "accept",produces = "application/abc")
          public ModelAndView acceptLimit(){
              return new ModelAndView("/WEB-INF/header.jsp");
          }
          @RequestMapping(value = "contenttype",consumes = "application/def")
          public ModelAndView contenttypeLimit(){
              return new ModelAndView("/WEB-INF/header.jsp");
          }
      }
      
4.3.3.Handler方法的返回值
  • void:通过类似servlet的方式处理
  • ModelAndView:上述案例均是此种情况
  • String:返回值字符串作为ViewName,model直接写在形参中
  • 请求转发和重定向:返回值同样是字符串,转发和重定向的是请求
  • JSON:返回值可以直接写Object,Jackson工具类会自动将Object转换为JSON
  • 例:
    • 导入依赖
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.cskaoyan</groupId>
          <artifactId>demo4-return-value</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>war</packaging>
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.2.10.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>3.0-alpha-1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>1.18.16</version>
              </dependency>
              
              <!-- Jackson工具 -->
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.11.3</version>
              </dependency>
          </dependencies>
      
      </project>
      
    • 新建一个application.xml文件
      <?xml version="1.0" encoding="UTF-8"?>
      <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:aop="http://www.springframework.org/schema/aop"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="
              http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
              http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          <context:component-scan base-package="com.cskaoyan"/>
          <mvc:annotation-driven/>
      
      </beans>
      
    • 创建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">
          <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:application.xml</param-value>
              </init-param>
          </servlet>
          <servlet-mapping>
              <servlet-name>dispatcherServlet</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
    • 创建destination.jsp和hello.jsp页面,前端展示
      <!-- hello.jsp -->
      <%--
        Created by IntelliJ IDEA.
        User: stone
        Date: 2021/4/1
        Time: 17:24
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      
      <h1>hello ${result}</h1>
      </body>
      </html>
      
      
      <!-- destination.jsp -->
      <%--
        Created by IntelliJ IDEA.
        User: stone
        Date: 2021/4/1
        Time: 17:31
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      
      <h1>这是你最终的归宿</h1>
      </body>
      </html>
      
    • 创建controller层
      @Controller
      public class ModelAndViewRelationController {
      
          //1.返回值为void的方法,处理方式类似于servlet
          @RequestMapping("hellofriend")
          public void hellofriend(HttpServletRequest request, HttpServletResponse response) {
      
          }
          //省略了一个返回值为ModelAndView的handler方法
         
          
          //返回值字符串作为viewName,Model直接写在形参中
          @RequestMapping("hello")
          public String hello(Model model){
              model.addAttribute("result", "string");
              return "/WEB-INF/hello.jsp";
          }
      }
      
      
      //转发和重定向
      @Controller
      public class ForwardRirectController {
      
          @RequestMapping("destination")//目的地
          public String destination(){
              return "/WEB-INF/destination.jsp";
          }
      
          //转发
          @RequestMapping("forward")
          public String forward(){
              System.out.println("forward");
              //如果不写/,那么就是相对的路径,相对的是当前handler映射的url,即去除掉请求url的最后一级,然后拼接
              return "forward:/destination";
          }
      
          //重定向,会修改掉浏览器显示的url
          @RequestMapping("redirect")
          public String redirect(){
              System.out.println("redirect");
              //在这里也是同理,如果不写/,也是相对路径
              return "redirect:/destination"; 
              
          }
      }
      
      
      
      //Jackson
      
      //@Controller
      //@ResponseBody  //如果这个注解写在这里,那么相当于整个类的返回值都是Json字符串
      @RestController // @RestController = @Controller + @ResponseBody
      public class JsonController {
      
          @RequestMapping("login")
          //@ResponseBody  //如果写在这里相当于此方法的返回值将转换为Json字符串
          public BaseRespVo login(){
              BaseRespVo baseRespVo = new BaseRespVo();
              baseRespVo.setData("景甜");
              baseRespVo.setMessage("登录成功");
              baseRespVo.setErrno(0);
              return baseRespVo;
          }
      }
      
      //返回的数据类
      @Data
      public class BaseRespVo<T> {
      
          T data;
          String message;
          long errno;
      }
      
4.3.4.Handler的请求参数
  • springMVC提供的转换器让我们能够直接以需要的类型来接收请求参数

  • 直接封装:请求参数名必须与handler方法的形参名一致,如果类型不匹配,会调用converter转换器来转换类型

    • 导入依赖
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.cskaoyan</groupId>
          <artifactId>day06-spring-mvc2</artifactId>
          <version>1.0-SNAPSHOT</version>
          
          <!--会自动生成一个artifact,dependency里的内容发生变化的时候,lib会自动更新-->
          <packaging>war</packaging>
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.2.10.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>3.0-alpha-1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.11.3</version>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>1.18.18</version>
              </dependency>
              
              <!-- SpringMVC文件上传功能的依赖 -->
              <dependency>
                  <groupId>commons-fileupload</groupId>
                  <artifactId>commons-fileupload</artifactId>
                  <version>1.4</version>
              </dependency>
          </dependencies>
      
      </project>
      
    • 创建application.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <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:aop="http://www.springframework.org/schema/aop"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="
              http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
              http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          <!-- bean definitions here -->
          <context:component-scan base-package="com.cskaoyan"/>
          <mvc:annotation-driven conversion-service="conversionService2"/>
      
          <!-- 把自定义的转换器放入容器中 -->
          <bean id="conversionService2" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
              <!-- name必须为固定值,转换器 -->
              <property name="converters">
                  <set>
                      <!-- 引用该转换器组件,bean值为转换器的id -->
                      <ref bean="string2DateConverter"/>
                      <!-- 也可以写转换器的全类名 -->
                      <!--<bean class="com.cskaoyan.converter.String2DateConverter"/>-->
                  </set>
              </property>
          </bean>
      
          <!--文件上传功能的组件,组件id为固定值,不可以修改为其他值-->
          <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
              <!-- 最大上传文件的大小,单位是kb -->
              <property name="maxUploadSize" value="5*1024*1024"/>
          </bean>
      
      </beans>
      
    • 创建WEBINF目录下的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">
          <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:application.xml</param-value>
              </init-param>
          </servlet>
          <servlet-mapping>
              <servlet-name>dispatcherServlet</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
    • 创建用于响应的VO类
      @Data
      public class BaseRespVo<T> {
          T data;
          String message;
          long errno;
      
          public static BaseRespVo ok(){
              BaseRespVo baseRespVo = new BaseRespVo();
              baseRespVo.setMessage("成功");
              baseRespVo.setErrno(0);
              return baseRespVo;
          }
          public static BaseRespVo ok(Object data){
              BaseRespVo ok = BaseRespVo.ok();
              ok.setData(data);
              return ok;
          }
      }
      
    • 创建controller层
      @RestController  //请求参数的封装
      public class ParameterController {
      
          //localhost:8080/register?username=jingtian&password=niupi&age=36
          //如果想要接收基本类型,不建议直接写基本类型,建议以基本类型所对应的包装类来接收
          //请求参数key值必须和函数中的形参名一致,否则接收不到
          @RequestMapping("register")
          public BaseRespVo register(String username,String password,Integer age,Boolean married){
              return BaseRespVo.ok(username + ":" + password + ":" + age);
          }
          
          
          //localhost:8080/register2?username=jingtian&password=niupi&age=36&birthday=2000-05-15
          //如果想要接收Date需要指定日期的格式,使用@DateTimeFormat来修改格式
          @RequestMapping("register2")
          public BaseRespVo register2(String username, String password, Integer age,
                                      @DateTimeFormat(pattern = "yyyy-MM-dd")Date birthday){
              System.out.println(birthday);
              return BaseRespVo.ok();
          }
          
          
          
          //接收时间类型的参数,也可以自定义转换器来接收
          /*
          @Component
      	public class String2DateConverter implements Converter<String, Date> {
      		//传入的是String类型的时间日期,需要转化为Date类型的时间日期(register3中的形参类型和名称均与请求一致)
              //调用convert方法执行类型转换:请求参数名和handler方法的形参名一致,类型又匹配为Converter接口这里的类型
              @SneakyThrows
              @Override
              public Date convert(String s) {
                  Date date = null;
                  //业务逻辑自定义
                  String pattern1 = "yyyy-MM-dd";
                  String pattern2 = "yyyy-MM-dd HH:mm:ss";
                  String pattern3 = "yyyy-MM-dd HH:mm";
                  if (s.length() == pattern1.length()){
                      date = new SimpleDateFormat(pattern1).parse(s);
                  }else if (s.length() == pattern2.length()){
                      date = new SimpleDateFormat(pattern2).parse(s);
                  } else if (s.length() == pattern3.length()) {
                      date = new SimpleDateFormat(pattern3).parse(s);
                  }
                  return date;
              }
          }
          */
          @Autowired
          ConfigurableConversionService conversionService; //SpringMVC中转换器的服务,包含了很多转换器
      
          //localhost:8080/register3?username=jingtian&password=niupi&age=36&birthday=2000-05-15
          //localhost:8080/register3?username=jingtian&password=niupi&age=36&birthday=2000-05-15 15:24
          //localhost:8080/register3?username=jingtian&password=niupi&age=36&birthday=2000-05-15 15:24:28
          @RequestMapping("register3")
          public BaseRespVo register3(String username, String password, Integer age,
                                      Date birthday){
              System.out.println(birthday);
              return BaseRespVo.ok();
          }
          
          
          
          
          //localhost:8080/register4?hobyys=sing&hobbys=dance&hobbys=basketball&username=jingtian&age=25
          //数组数据,数据里有三个hobbys参数
          @RequestMapping("register4")
          public BaseRespVo register4(String username,Integer age,String[] hobbys){
              return BaseRespVo.ok(hobbys);
          }
      
          
      
      	//文件类型
          //请求参数名和handler方法的形参名(MultipartFile)一致
          @RequestMapping("file/upload")
          public BaseRespVo fileUpload(MultipartFile myfile){
              String name = myfile.getName();//接收请求参数名,即myfile
              String originalFilename = myfile.getOriginalFilename(); //上传文件时选择该文件的文件名
              String contentType = myfile.getContentType(); //上传文件时该文件的文件类型
              long size = myfile.getSize(); //上传文件时该文件的文件大小,单位是kb
      
              //保存目录
              File path = new File("D:\\stone\\spring");
              //构造一个file来接收multipartFile
              File file = new File(path, originalFilename);//以第二个参数的文件类型来保存上传的文件
      
              try {
                  //将multipartFile转换为file
                  myfile.transferTo(file);
              } catch (IOException e) {
                  e.printStackTrace();
              }
      
              return BaseRespVo.ok();
          }
          
          
          //文件也可以按数组形式接收
          //请求参数名和handler方法的形参名(MultipartFile)一致
          @RequestMapping("files/upload")
          public BaseRespVo filesUpload(MultipartFile[] myfiles){
              for (MultipartFile myfile : myfiles) {
                  String name = myfile.getName();//请求参数名,即myfile
                  String originalFilename = myfile.getOriginalFilename(); //上传时选择的文件名
                  String contentType = myfile.getContentType(); //文件类型
                  long size = myfile.getSize();
      
                  //save
                  File path = new File("D:\\stone\\spring");
                  //构造一个file来接收multipartFile
                  File file = new File(path, originalFilename);//你想要以什么文件保存,第二个参数就写什么
      
                  try {
                      //将multipartFile转换为file
                      myfile.transferTo(file);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
      
              return BaseRespVo.ok();
          }
      }
      
    • 创建一个文件上传的jsp表单,用于演示表单功能
      <%--
        Created by IntelliJ IDEA.
        User: stone
        Date: 2021/4/2
        Time: 11:36
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      <h1>文件上传</h1>
      <form action="/file/upload" enctype="multipart/form-data" method="post">
          <!-- name属性会体现为请求参数名,必须和handler方法中的形参名一致 -->
          <input type="file" name="myfile">
              <input type="submit">
      </form>
      <hr>
      <h1>多个文件上传</h1>
      <form action="/files/upload" enctype="multipart/form-data" method="post">
          <!-- name属性会体现为请求参数名 -->
          <input type="file" multiple name="myfiles">
              <input type="submit">
      </form>
      </body>
      </html>
      
  • JavaBean封装url参数:上述形参封装为JavaBean中的成员变量,同理成员变量名也要和请求参数名一致,其实就是调用该类的无参构造方法以及set方法封装

    • 如果遇到类似Boolean类型的形参,那么同样也是使用转换器来转换
    • 创建一个JavaBean
      @Data
      public class User {
          String username;
          String password;
          Integer age;
      
          //@DateTimeFormat //请求参数封装过程中的转换
          //也可以使用自定义转换器,已经在上述案例中定义过了,SpringMVC会自动调用
          @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")   //响应结果json格式的限定并设置时区
          Date birthday;
          String[] hobbys;
      
          //如果请求数据是这样的,可以使用复杂类型封装,但是不建议这样请求
          //localhost:8080/javabean/register?username=jingtian&userDetail.mobile=100&userDetail.email=cskaoyan@qq.com
          UserDetail userDetail;
      
          
          //同理如果前端请求数据是这样的,同样要使用复杂类型,但是同样不建议这样请求
          //为了分清每组的请求数据,orders与price数据对应,要给数据分组,但是请求参数要使用uri编码,如下
          //localhost:8080/javabean/register?username=jingtian&
          // orders[0].name=lanqiu&orders[0].price=50&
          // orders[1].name=tiaowuji&orders[1].price=5000
      
          //[]需要使用到uri编码,[ 表示为 %5B , ] 表示为 %5D
          //http://localhost:8080/javabean/registerusername=jingtian&orders%5B0%5D.name=lanqiu&
         	//	orders%5B0%5D.price=50&orders%5B1%5D.name=tiaowuji&orders%5B1%5D.price=5000&birthday=2021-04-02
          List<Order> orders;
          
          @Data
          private static class UserDetail {
              String mobile;
              String email;
          }
          
          @Data
          private static  class Order {
              String name;
              Double price;
          }
      
      
      }
      
    • controller层
      @RestController
      public class JavaBeanController {
      
          //localhost:8080/javabean/register?username=jingtian&password=niupi&
          //	age=25&birthday=2021-04-02&hobbys=sing&hobbys=dance
          @RequestMapping("javabean/register")
          public BaseRespVo register(User user){
              return BaseRespVo.ok(user);
          }
      
          //不建议这样来接收
          @RequestMapping("javabean/register2")
          public BaseRespVo register(HttpServletRequest request){
              String username = request.getParameter("username");
              String password = request.getParameter("password");
              String age = request.getParameter("age");
              return null;
          }
      }
      
  • Json请求体数据封装

    • 请求方法:Post
    • 请求头:
      • Content-Type:application/json
      • data:json格式的字符串
    • controller层
      @RestController
      public class JsonController {
      
          //json数据的样式
          //{
          //  "username":"jingtian",
          //  "password":"niupi"
          // }
          //接收请求体中的json数据,并封装为User
          @RequestMapping("json/login")
          public BaseRespVo login(@RequestBody User user){
              return BaseRespVo.ok(user);
          }
      
          /**	注意格式:
           * 		user:String hobbys,字符串格式
           * 		{
           *     		"hobbys":"[sing,dance,rap]"
           * 		}
           * 		user:String[] hobbys,字符串数组格式
           * 		{
           *     		"hobbys":["sing","dance","rap"]
           * 		}
           */
      }
      //也可以使用map来接收,但是获取参数需要用get方法,比较麻烦
      
  • Handler方法的其他形参

    • HttpRequest、HttpResponse:上述例子中已经写过
    • Model:返回值为String的时候,上述例子中已经写过
    • Session:Cookie不能直接写在形参中,也可以在浏览器的开发者工具中添加,Session可以直接写,也可以通过Request.getSession()方法获取,
      @RestController
      public class CookieSessionController {
      
          //需要通过Request来获取Cookie,不能直接写在形参中
          @RequestMapping("fetch/cookie")
          public BaseRespVo fetchCookie(HttpServletRequest request){
              Cookie[] cookies = request.getCookies();
              for (Cookie cookie : cookies) {
                  System.out.println(cookie.getName() + " = " + cookie.getValue());
              }
              return BaseRespVo.ok();
          }
      
          //放入Session
          @RequestMapping("put/session")
          public BaseRespVo putSession(String username,HttpSession session){
              session.setAttribute("username",username);
              return BaseRespVo.ok();
          }
      
          //取出Session
          @RequestMapping("fetch/session")
          public BaseRespVo fetchSession(HttpSession session) {
              Object username = session.getAttribute("username");
              return BaseRespVo.ok(username);
          }
          //也可以通过request获取
          @RequestMapping("fetch/session2")
          public BaseRespVo fetchSession2(HttpServletRequest request) {
              HttpSession session = request.getSession();
              return BaseRespVo.ok();
          }
      
      }
      
4.4.RESTful风格的接口
  • 根据请求方法的不同,使用不同的handler方法处理,可以实现同一个url映射到不同的方法上
  • 动态@ResultMapping:设计请求url中的值,拼接相同部分+不同部分的请求url
    • 导入依赖
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.cskaoyan</groupId>
          <artifactId>demo2-restful</artifactId>
          <version>1.0-SNAPSHOT</version>
      
          <packaging>war</packaging>
          <!--会帮我们生成一个artifact,dependency里的内容发生变化的时候,lib会自动更新-->
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.2.10.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>3.0-alpha-1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.11.3</version>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>1.18.18</version>
              </dependency>
          </dependencies>
      
      </project>
      
    • 配置application.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <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:aop="http://www.springframework.org/schema/aop"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="
              http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
              http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          <context:component-scan base-package="com.cskaoyan"/>
          <mvc:annotation-driven/>
      
      </beans>
      
    • 创建WEBINF目录下的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">
          <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:application.xml</param-value>
              </init-param>
          </servlet>
          <servlet-mapping>
              <servlet-name>dispatcherServlet</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
    • 创建VO
      @Data
      public class BaseRespVo<T> {
          T data;
          String message;
          long errno;
      
          public static BaseRespVo ok(){
              BaseRespVo baseRespVo = new BaseRespVo();
              baseRespVo.setMessage("成功");
              baseRespVo.setErrno(0);
              return baseRespVo;
          }
          public static  BaseRespVo ok(Object data){
              BaseRespVo ok = BaseRespVo.ok();
              ok.setData(data);
              return ok;
          }
      }
      
    • 创建controller层
      @RestController
      public class RestfulController {
      
          //@PathVariable注解的value属性值对应占位符的名字
          //@PathVariable注解对应的形参就可以获得对应的占位符的url的值
          @RequestMapping("{usernamez}/article/details/{idz}")
          public BaseRespVo articleDetails(@PathVariable("usernamez") String username,
                                           @PathVariable("idz") Integer id){
              return BaseRespVo.ok(username + ":" + id);
          }
      
          //获取请求参数作为形参,封装给形参,没必要这样写
          //localhost:8080/login?username=jingtian&password=niupi
          @RequestMapping("login")
          public BaseRespVo login(@RequestParam("username") String parameter1,
                                  @RequestParam("password") String parameter2){
              return BaseRespVo.ok();
          }
      
          //获取特定请求头的值
          @RequestMapping("header")
          public BaseRespVo header(@RequestHeader("Accept") String[] accept,
                                   @RequestHeader("Host")String host){
              for (String s : accept) {
                  System.out.println(s);
              }
              System.out.println(host);
              return BaseRespVo.ok();
          }
      
          //获取指定name的cookie对应的value值
          @RequestMapping("cookie/value")
          public BaseRespVo cookieValue(@CookieValue("jingtian")String value){
              return BaseRespVo.ok(value);
          }
      
          //向username这个session的attribute中放入一个value
          @RequestMapping("put/session/{username}")
          public BaseRespVo putSession(@PathVariable("username")String value, HttpSession session){
              session.setAttribute("username",value);
              return BaseRespVo.ok();
          }
      
          //从session的指定attribute中取出对应value
          @RequestMapping("session/attribute")
          public BaseRespVo sessionAttribute(@SessionAttribute("username")String value){
          return BaseRespVo.ok(value);
          }
      }
      
4.5.静态资源处理
  • 复制静态资源,如三张图片,复制到工程目录下,使该工程结构如下
    • src
      • main
        • java
        • resource
        • webapp
          • jpg
            • 2.jpg
          • WEB-INF
            • web.xml
            • 3.jpg
          • 1.jpg
    • 导入依赖
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.cskaoyan</groupId>
          <artifactId>demo3-static-resource</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>war</packaging>
          <!--会帮我们生成一个artifact,dependency里的内容发生变化的时候,lib会自动更新-->
      
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.2.10.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>3.0-alpha-1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.11.3</version>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>1.18.18</version>
              </dependency>
          </dependencies>
      
      </project>
      
    • 创建配置文件application.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <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:aop="http://www.springframework.org/schema/aop"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="
              http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
              http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          <context:component-scan base-package="com.cskaoyan"/>
          <mvc:annotation-driven/>
      
          
          <!-- 方式二:增加一个默认的handler标签,只要是webapp根路径下的资源,都可以访问到
      		localhost:8080/1.jpg 可以访问到
      		localhost:8080/jpg/2.jpg 需要手动复制到target文件夹内的web资源路径下才可以访问到
      		WEB-INF路径下的资源被屏蔽,不可直接访问到
       	-->
          <!--<mvc:default-servlet-handler/>-->
          
          
          
          <!--方式三:静态资源映射,ResourceHandler-->
          <!--
              1.jpg:localhost:8080/pic1/1.jpg
              2.jpg:localhost:8080/pic1/jpg/2.jpg
      
              请求url:mapping中的值 + 静态资源相对于location的位置
          -->
          <mvc:resources mapping="/pic1/**" location="/"/>
      
          <!--
              访问3.jpg:localhost:8080/pic2/3.jpg
          -->
          <mvc:resources mapping="/pic2/**" location="/WEB-INF/"/>
          
          <!-- 访问服务器里的本地路径的静态资源 -->
          <!--
      		location:
                  classpath路径: classpath:/
                  文件路径: file:文件路径
          -->
          <mvc:resources mapping="/pic3/**" location="file:D:/stone/spring/"/>
      
          <!--注意:
              mapping属性:最左侧/   ** : 匹配多级url
              location属性:最右侧/
           -->
      </beans>
      
    • 创建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">
          <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:application.xml</param-value>
              </init-param>
          </servlet>
          
          
          <!--
      		方式一:配置默认请求,用于处理.jpg的访问请求,拦截dispatcherServlet
      		localhost:8080/1.jpg可以访问到webapp根路径下的1.jpg资源
       	-->
          <!--<servlet-mapping>
              <servlet-name>default</servlet-name>
              <url-pattern>*.jpg</url-pattern>
          </servlet-mapping>-->
          
          
          <servlet-mapping>
              <servlet-name>dispatcherServlet</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
4.6.Filter
4.6.1.CharacterEncodingFilter
  • 通过过滤器解决中文乱码问题
  • 导入依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.cskaoyan</groupId>
        <artifactId>demo1-character-encoding-filter</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0-alpha-1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.18</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.11.3</version>
            </dependency>
        </dependencies>
    
    
    </project>
    
  • 创建application.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <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:aop="http://www.springframework.org/schema/aop"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <context:component-scan base-package="com.cskaoyan"/>
        <mvc:annotation-driven/>
    
    </beans>
    
  • 创建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">
        <filter>
            <filter-name>characterEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <!--调用set方法-->
                <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>
        <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:application.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 在webapp根路径下创建index.jsp登录页面,用于验证中文是否乱码
    <%--
      Created by IntelliJ IDEA.
      User: stone
      Date: 2021/4/3
      Time: 9:07
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <form action="login" method="post">
        用户:<input type="text" name="username"><br>
        密码:<input type="text" name="password"><br>
        <input type="submit">
    </form>
    </body>
    </html>
    
  • 创建bean
    @Data
    public class BaseRespVo<T> {
        T data;
        String message;
        int errno;
    
        public static BaseRespVo ok(){
            BaseRespVo baseRespVo = new BaseRespVo();
            baseRespVo.setMessage("成功");
            baseRespVo.setErrno(0);
            return baseRespVo;
        }
    
        public static BaseRespVo ok(Object data){
            BaseRespVo baseRespVo = new BaseRespVo();
            baseRespVo.setData(data);
            baseRespVo.setMessage("成功");
            baseRespVo.setErrno(0);
            return baseRespVo;
        }
    }
    
    
    
    @Data
    public class User {
        String username;
        String password;
    }
    
  • 创建登录逻辑
    @RestController
    public class UserController {
    
        @RequestMapping("login")
        public BaseRespVo login(User user){
            return BaseRespVo.ok(user);
        }
    }
    
4.6.2.HandlerInterceptor
  • 功能类似于BeanPostProcessor。通过HandlerMapping会生成一个HandlerExecutionChain(执行链)调用List Handler方法
  • HandlerInterceptor中的方法
    • boolean preHandle(预处理):返回值决定是否能继续流程,返回值为true才能继续执行
    • void postHandle(后处理):handler方法执行完响应的ModelAndView,如果响应的是json,那么这里的modelAndView就是null,这个方法主要用于对ModelAndView做额外的处理
    • void afterCompletion:如果当前的HandlerInterceptor的preHandle方法返回值结果为true,一定可以执行到对应的afterCompletion
  • HandlerInterceptor的作用范围
    • 全局:使用bean标签注册或ref标签的bean属性
    • 指定方法:mvc:interceptor标签指定方法
  • 导入依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.cskaoyan</groupId>
        <artifactId>demo2-handler-interceptor</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0-alpha-1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.18</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.11.3</version>
            </dependency>
        </dependencies>
    
    </project>
    
  • 创建application.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <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:aop="http://www.springframework.org/schema/aop"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <context:component-scan base-package="com.cskaoyan"/>
        <mvc:annotation-driven/>
    
        <!--mvc:interceptors-->
        <mvc:interceptors>
            <!--
                如果使用bean标签或ref标签的话,作用范围是全局
                全局:DispatcherServlet作用范围下的全局
            -->
            <!--<ref bean="customHandlerInterceptor"/>-->
            <!--<bean class="com.cskaoyan.interceptor.CustomHandlerInterceptor"/>-->
            <mvc:interceptor>
                <!--
                    /hello → hello这个请求
                    /hello* → helloxxx请求
                    /hello/* → hello/xxx请求
                    /hello/** → hello以及hello的所有多级请求 /hello/aaa/bbb/ccc
                -->
                <mvc:mapping path="/hello/**"/>
                <ref bean="customHandlerInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
    
    
    </beans>
    
  • 创建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">
        <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:application.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 创建两个页面用于前端展示
    <!-- helloworld.jsp -->
    <%--
      Created by IntelliJ IDEA.
      User: stone
      Date: 2021/4/3
      Time: 10:08
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1>Hello world页面</h1>
    </body>
    </html>
    
    
    <!--postHandler.jsp -->
    <%--
      Created by IntelliJ IDEA.
      User: stone
      Date: 2021/4/3
      Time: 10:08
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body
    <h1>后处理</h1>
    </body>
    </html>
    
  • 创建interceptor接口的实现类
    @Component
    public class CustomHandlerInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            if (modelAndView != null){
                modelAndView.setViewName("/postHandle.jsp");
    
            }
            System.out.println("postHandle");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion");
        }
    }
    
  • 创建controller层
    //@RestController("hello")//组件id
    @Controller
    @RequestMapping("hello")//窄化请求
    public class HelloController {
    
        //localhost:8080/hello/world
        @RequestMapping("world")
        @ResponseBody
        public String hello(){//因为有@RestController,所以响应的是字符串而不是视图名
            System.out.println("hello world");
            return "helloworld";
        }
        //localhost:8080/hello/world2,访问该url响应的是postHandle.jsp
        @RequestMapping("world2")
        public String hello2(){//因为有@RestController,所以响应的是字符串而不是视图名
            System.out.println("hello world");
            //return "helloworld"; //hello/helloworld
            return "/helloworld.jsp"; //helloworld.jsp
        }
    }
    
4.6.3.多个HandlerInterceptor
  • 多个HanlderInterceptor的执行流程:
    1. 有三个HandlerInterceptor,执行流程应该是preHandler1—preHandler2—preHandler3—Handler方法—postHandler3—postHandler2—postHandler1—afterCompletion3—afterCompletion2—afterCompletion1
    2. 如果有某个preHandler方法返回值为false,那么会中断后续除其余afterCompletion方法外的所有流程,也会中断本身的afterCompletion
  • 引入依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.cskaoyan</groupId>
        <artifactId>demo3-many-handler-interceptor</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0-alpha-1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.18</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.11.3</version>
            </dependency>
        </dependencies>
    
    </project>
    
  • 创建application.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <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:aop="http://www.springframework.org/schema/aop"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <context:component-scan base-package="com.cskaoyan"/>
        <mvc:annotation-driven/>
    
        <mvc:interceptors>
            <!--顺序和书写顺序相关-->
            <ref bean="handlerInterceptor1"/>
            <ref bean="handlerInterceptor2"/>
            <ref bean="handlerInterceptor3"/>
        </mvc:interceptors>
    
    </beans>
    
  • 创建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">
        <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:application.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 创建三个Intereptor
    @Component
    public class HandlerInterceptor1 implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle1");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle1");
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion1");
    
        }
    }
    
    
    
    @Component
    public class HandlerInterceptor2 implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle2");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle2");
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion2");
    
        }
    }
    
    
    
    
    @Component
    public class HandlerInterceptor3 implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("preHandle3");
            return false;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("postHandle3");
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("afterCompletion3");
    
        }
    }
    
  • 创建controller层
    @RestController
    public class HelloController {
    
        @RequestMapping("hello")
        public String hello(){
            System.out.println("hello world");
            return "hello world";
        }
    }
    
  • 访问对应url,可以看到控制台打印结果
4.7.异常处理
  • 方式一:全局处理

    • 实现该接口HandlerExceptionResolver以后,只要出现异常,全部由该实现类处理
    • 导入依赖
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.cskaoyan</groupId>
          <artifactId>demo4-handler-exception-resolver</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>war</packaging>
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.2.10.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>3.0-alpha-1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>1.18.18</version>
              </dependency>
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.11.3</version>
              </dependency>
          </dependencies>
      
      </project>
      
    • 创建application.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <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:aop="http://www.springframework.org/schema/aop"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="
              http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
              http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
              http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          <context:component-scan base-package="com.cskaoyan"/>
          <mvc:annotation-driven/>
      
      </beans>
      
    • 创建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">
          <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:application.xml</param-value>
              </init-param>
          </servlet>
          <servlet-mapping>
              <servlet-name>dispatcherServlet</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
    • 创建hello.jsp
      <%--
        Created by IntelliJ IDEA.
        User: stone
        Date: 2021/4/3
        Time: 11:21
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      <h1>hello world</h1>
      </body>
      </html>
      
    • 创建两个异常展示页面,放在WEB-INF路径下
      <!-- 敏感词异常,sensitive.jsp -->
      <%--
        Created by IntelliJ IDEA.
        User: stone
        Date: 2021/4/3
        Time: 11:38
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      <h1> ${messagez},敏感词 ${word} 不可使用 </h1>
      </body>
      </html>
      
      
      <!-- 除0异常,exception.jsp -->
      <%--
        Created by IntelliJ IDEA.
        User: stone
        Date: 2021/4/3
        Time: 11:29
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      <h1>程序员正在维护,请稍后重试</h1>
      </body>
      </html>
      
    • 创建两个异常处理类
      //新建一个敏感词异常类
      public class SensitiveWordException extends Exception{
          String word;
      
          public SensitiveWordException(String word, String message) {
              super(message);
              this.word = word;
          }
      
          public String getWord() {
              return word;
          }
      
          public void setWord(String word) {
              this.word = word;
          }
      }
      
      
      
      //异常处理
      /**
       * 只需要增加@Component则生效(只需要注册到容器中)
       * handler方法向上抛出异常,则会执行到resovleException方法
       */
      @Component
      public class CustomHandlerExceptionResolver implements HandlerExceptionResolver {
          /**
           *
           * @param handler → Handler方法
           * @param exception → 向上抛出的异常对应
           * @return ModelAndView → 最后处理后的ModelAndView
           */
          @Override
          public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
                                               Object handler, Exception exception) {
              ModelAndView modelAndView = new ModelAndView("/WEB-INF/exception.jsp");
      
              //根据抛出的异常不同,做个性化的处理 → 异常类型的不同
              if (exception instanceof SensitiveWordException) {
                  SensitiveWordException sensitiveWordException = (SensitiveWordException) exception;
                  String word = sensitiveWordException.getWord();//从handler方法中抛出的异常对象封装的
                  String message = sensitiveWordException.getMessage();
                  modelAndView.setViewName("/WEB-INF/sensitive.jsp");
                  modelAndView.addObject("word", word);
                  modelAndView.addObject("messagez", message);
              }
      
              return modelAndView;
          }
      }
      
    • controller层
      @Controller
      public class HelloController {
      
          @RequestMapping("hello/{username}")
          public String hello(@PathVariable("username")String username) throws SensitiveWordException {
              if ("shenlan".equals(username)){
                  int i = 1 / 0;
              } else if ("fenghua".equals(username) || "manwu".equals(username)) {
                  throw new SensitiveWordException(username, "小子,扣工资");
              }
              return "/hello.jsp";
          }
      }
      
  • 方式二:映射(ExceptionHandler)

    • 在异常处理类上添加注解@ControllerAdvice,在方法上增加@ExceptionHandler注解,其value值为一个或多个异常类
    • 在方式一的工程不变化的基础上,只需删除CustomHandlerExceptionResolver类即可
    • 重新创建一个ExceptionController类
      @ControllerAdvice //使用该注解,才能够使用ExceptionHandler
      //@RestControllerAdvice = RequestBody + ControllerAdvice,该注解下的类相应结果都是json数据
      public class ExceptionController {
      
          @ExceptionHandler(ArithmeticException.class)  //处理除零异常
          public String exception(ArithmeticException exception){ //ModelAndView
              return "/WEB-INF/exception.jsp";
          }
      
          @ExceptionHandler(SensitiveWordException.class)  //处理敏感词异常
          @ResponseBody
          public BaseRespVo sensitive(SensitiveWordException exception){ //json
              String message = exception.getMessage();
              return BaseRespVo.fail(message);
          }
          
          @Data
          private static class BaseRespVo<T> {
              T data;
              String message;
              int errno;
              public static BaseRespVo fail(String message){
                  BaseRespVo baseRespVo = new BaseRespVo();
                  baseRespVo.setMessage(message);
                  baseRespVo.setErrno(500);
                  return baseRespVo;
              }
          }
      }
      
4.8.Hibernate Validator(参数校验)
  • 引入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.cskaoyan</groupId>
        <artifactId>demo1-validator</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0-alpha-1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.18</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.11.3</version>
            </dependency>
            <dependency>
                <groupId>org.hibernate.validator</groupId>
                <artifactId>hibernate-validator</artifactId>
                <version>6.1.6.Final</version>
            </dependency>
        </dependencies>
    
    </project>
    
  • 创建application.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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:aop="http://www.springframework.org/schema/aop"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <context:component-scan base-package="com.cskaoyan"/>
        <mvc:annotation-driven validator="validator"/>
    
        <!-- 注册Validator -->
        <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
            <!--提供一个工厂类-->
            <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
        </bean>
    </beans>
    
  • 创建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">
        <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:application.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 在bean上添加验证

    @Data
    public class User {
    
        @Length(min = 6,message = "长度最小为6")
        String username;
        @Length(min = 6,max = 8,message = "password length must between 6 and 8")
        String password;
        @Min(value = 18,message = "未成年人禁止进入")
        @Max(value = 150,message = "活不了这么大吧")
        Integer age;
    }
    
  • 创建VO

    @Data
    public class BaseRespVo<T> {
        T data;
        String msg;//告诉前端请求的消息
        long errno;//自己的前后端应用 : 自定义的状态码 → 通常前端根据该状态码做不同的处理
    
        public static BaseRespVo ok(){
            BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
            baseRespVo.setErrno(0);
            baseRespVo.setMsg("成功");
            return baseRespVo;
        }
        public static BaseRespVo ok(Object data){
            BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
            baseRespVo.setData(data);
            baseRespVo.setErrno(0);
            baseRespVo.setMsg("成功");
            return baseRespVo;
        }
        public static BaseRespVo ok(Object data, String msg){
            BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
            baseRespVo.setData(data);
            baseRespVo.setErrno(0);
            baseRespVo.setMsg(msg);
            return baseRespVo;
        }
        public static BaseRespVo fail(){
            BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
            baseRespVo.setErrno(500);
            baseRespVo.setMsg("失败");
            return baseRespVo;
        }
        public static BaseRespVo fail(String msg){
            BaseRespVo<Object> baseRespVo = new BaseRespVo<>();
            baseRespVo.setErrno(500);
            baseRespVo.setMsg(msg);
            return baseRespVo;
        }
    }
    
  • 创建controller层

    @RestController
    public class UserController {
    
        /*@RequestMapping("login")
        public BaseRespVo login(String username, String password) {
            //校验的逻辑是写在controller层
            if (username == null || username.length() <= 5) {
                return BaseRespVo.fail();
            }
            if (password == null || password.length() <= 5) {
                return BaseRespVo.fail();
            }
            return BaseRespVo.ok();
        }*/
        //通过@Valid或@Validated注解,声明该请求参数需要增加校验
        //bindingResult → 校验结果
        @RequestMapping("login")
        public BaseRespVo login(@Valid User user, BindingResult bindingResult) {
            //请求参数是否全部都通过校验
            if (bindingResult.hasFieldErrors()) {
                //获得请求参数所对应的成员变量的错误
                FieldError fieldError = bindingResult.getFieldError();
                //有错误的成员变量名 → 请求参数名 → 哪一个请求参数有问题
                String field = fieldError.getField();
                String defaultMessage = fieldError.getDefaultMessage();
                String message = field + "出问题了:" + defaultMessage;
                return BaseRespVo.fail(message);
            }
            return BaseRespVo.ok();
        }
    
        @RequestMapping("register")
        public BaseRespVo register(String username, String password) {
            //校验的逻辑是写在controller层
            if (username == null || username.length() <= 5) {
                return BaseRespVo.fail();
            }
            if (password == null || password.length() <= 5) {
                return BaseRespVo.fail();
            }
            return BaseRespVo.ok();
        }
    
    }
    
  • 其他常见的注解(Bean Validation中内置的constraint)

    • @Null被注释的元素必须为null
    • @NotNull被注释的元素必须不为null
    • @Size(max=, min=)被注释的元素的大小必须在指定的范围内
    • @AssertTrue被注释的元素必须为true
    • @AssertFalse被注释的元素必须为false
    • @Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    • @Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    • @DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    • @DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    • @Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
    • @Past被注释的元素必须是一个过去的日期Date
    • @Future被注释的元素必须是一个将来的日期
    • @Pattern(regex=,flag=)被注释的元素必须符合指定的正则表达式Hibernate Validator附加的constraint
    • @NotBlank(message =)验证字符串非null,且长度必须大于0
    • @Email被注释的元素必须是电子邮箱地址
    • @Length(min=,max=)被注释的字符串的大小必须在指定的范围内
    • @NotEmpty被注释的字符串的必须非空
    • @Range(min=,max=,message=)被注释的元素必须在合适的范围内
4.9.JavaConfig
4.9.1.容器关系
  • SpringMVC的容器依赖于Spring容器,即Spring为父容器,SpringMVC为子容器
  • 父容器不能使用子容器的组件,子容器可以使用父容器的组件
4.9.2.spring、springMVC
  • 引入依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.cskaoyan</groupId>
        <artifactId>demo1-validator</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>3.0-alpha-1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.18</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.11.3</version>
            </dependency>
            <dependency>
                <groupId>org.hibernate.validator</groupId>
                <artifactId>hibernate-validator</artifactId>
                <version>6.1.6.Final</version>
            </dependency>
        </dependencies>
    
    </project>
    
  • 创建spring的配置文件application.xml,创建springMVC的配置文件application-mvc.xml
    <!-- application.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <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:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- bean definitions here -->
        <!--排除掉controller相关组件 → 注解Controller-->
        <context:component-scan base-package="com.cskaoyan">
            <!-- 只让组件实例化一次,把controller层的Controller注解全部排除掉 -->
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
    </beans>
    
    
    
    
    <!-- application-mvc.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <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:aop="http://www.springframework.org/schema/aop"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <context:component-scan base-package="com.cskaoyan.controller"/>
        <mvc:annotation-driven/>
    
    </beans>
    
  • 创建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">
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application.xml</param-value>
        </context-param>
        <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:application-mvc.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    
  • 创建controller层
    @RestController
    public class HelloController {
    
        @RequestMapping("hello")
        public String hello(){
            return "hello spring and springmvc";
        }
    
        public HelloController() {
            System.out.println("controller component init");
    
        }
    }
    
4.9.3.JavaConfig
  • 在Spring、SpringMVC项目中,通常需要三个以上的配置文件,可以分别用 Java 配置类来代替配置文件
    • 导入依赖
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>com.cskaoyan</groupId>
          <artifactId>demo3-java-config</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>war</packaging>
          <dependencies>
              <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-webmvc</artifactId>
                  <version>5.2.10.RELEASE</version>
              </dependency>
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>3.0-alpha-1</version>
                  <scope>provided</scope>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <version>1.18.18</version>
              </dependency>
              <dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.11.3</version>
              </dependency>
              <dependency>
                  <groupId>commons-fileupload</groupId>
                  <artifactId>commons-fileupload</artifactId>
                  <version>1.4</version>
              </dependency>
              <dependency>
                  <groupId>org.hibernate.validator</groupId>
                  <artifactId>hibernate-validator</artifactId>
                  <version>6.1.6.Final</version>
              </dependency>
          </dependencies>
      
      </project>
      
    • web.xml
      //web.xml的配置类
      public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
          //加载Spring的配置类
          @Override
          protected Class<?>[] getRootConfigClasses() {
              return new Class[]{SpringConfiguration.class};
          }
          //加载mvc的配置类
          @Override
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{MvcConfiguration.class};
          }
          //DispatcherServlet的作用范围
          @Override
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
      
          //Filter的配置函数,解决中文乱码问题
          @Override
          protected Filter[] getServletFilters() {
              CharacterEncodingFilter filter = new CharacterEncodingFilter();
              filter.setEncoding("utf-8");
              return new Filter[]{filter};
          }
      }
      
    • application.xml
      @Configuration
      @ComponentScan(value = "com.cskaoyan",
                     excludeFilters = @ComponentScan.Filter(value = {Controller.class, EnableWebMvc.class}))
      //可以不写type属性,因为type只有一个默认值,同理,要将SpringMVC配置类组件排除在外
      //excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class))
      public class SpringConfiguration {
      
          //可以是@Bean注册组件
      
      }
      
    • application-mvc.xml
      @EnableWebMvc //也包含了@Configuration功能,即类里可以使用@Bean
      @ComponentScan("com.cskaoyan.controller")  //实现该接口提供了mvc标签开头的功能
      public class MvcConfiguration implements WebMvcConfigurer {
      
          //mvc配置类
          //multipartResolver组件,文件上传组件
          @Bean
          public CommonsMultipartResolver multipartResolver(){//方法名作为组件默认id,该id为固定值
              return new CommonsMultipartResolver();
          }
      
          //ResourceHandlers,静态资源映射的配置
          @Override
          public void addResourceHandlers(ResourceHandlerRegistry registry) {
              //       mapping                                    location
              registry.addResourceHandler("/pic1/**").addResourceLocations("/");
              registry.addResourceHandler("/pic2/**").addResourceLocations("classpath:/");
              registry.addResourceHandler("/pic3/**").addResourceLocations("file:d:/stone/spring/");
          }
      
          //Interceptors配置,功能类似于BeanPostProcessor
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              //作用范围 组件是哪个 interceptor之间的顺序
              registry.addInterceptor(new CustomInterceptor1());//作用范围是全局
              registry.addInterceptor(new CustomInterceptor2()).addPathPatterns("/hello/**");
              registry.addInterceptor(new CustomInterceptor3()).addPathPatterns("/hello/**");
          }
          
          //converter组件,用于请求参数和JavaBean成员变量之间的类型转换,实现converter接口完成转换
         	//方式一:通过conversionService,比较繁琐
          //1.在mvc配置类中取出ConversionService
          @Autowired
          ConfigurableConversionService conversionService;
      	//2.在组件到达可用之前,利用其生命周期方法
          @PostConstruct
          public void addConverter() {
              conversionService.addConverter(new String2DateConverter());
          }
      	//3.使用bean注解来注册组件
          @Bean
          @Primary  //优先去找这个组件
          public ConfigurableConversionService conversionService(){
              return conversionService;
          }
      
          //方式二:通过WebMvcConfigurer提供的addFormatters方法
          @Override
          public void addFormatters(FormatterRegistry registry) {
              //传入一个继承了converter接口的对象
              registry.addConverter(new String2DateConverter());
          }
      
          //Validator组件,参数校验
          @Override
          public Validator getValidator() {
              LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
              localValidatorFactoryBean.setProviderClass(HibernateValidator.class);
              return localValidatorFactoryBean;
          }
      }
      
4.10.SpringMVC防止表单重复提交
  1. 通过重定向
    • 采取请求转发的方式完成表单内容的添加会造成内容的重复插入。
    • 当向Servlet发送一条增加记录的请求后,servlet首先向数据库增加一条记录,然后又从数据库中查询出所有数据,接着转发到另一个页面,这时,页面上浏览器的地址显示的是servlet的地址,当用户刷新页面时,又会向servlet发送一条添加请求,这样会导致数据库中重复数据不断增加。
    • 解决办法:采用重定向的方式添加数据不会导致数据的重复插入或删除。
    • 向servlet发送一个添加请求时,这个servlet只执行添加操作,然后重定向到另一个servlet进行数据的查询,最后转发到显示页面。
  2. 通过Session Token(Session令牌)
    • 当客户端第一次向服务器端发送请求的时候,服务器会通过Token标签,并且会将这个字符串放到session中,然后将这个字符串发送给客户端,在提交之前页面上就有了一个字符串,服务器端也有一个字符串,两个字符串的内容是一样的,当提交的时候,服务器会比较两个字符串是不是一样的,如果是一样的,就是第一次提交,并且更新服务器端的字符串;如果此时再次重复提交,服务器端的字符串已经发生改变而页面中的那个字符串还没有变,这时,你提交的时候两个字符串就不匹配了,服务器端就会认为是第二次提交,这样,服务器就不会再让提交了,进而转向invalid.token那所指向的页面。
    • 其实就是第二次与第一次jsp页面向服务器提交的内容和第一次一模一样,当在浏览器上返回前一页时,表单中提交的内容和第一次也是易语言的,所以这种情况下提交也会失败,当返回前面一夜然后刷新,刷新相当于向服务器发送了一次请求,所以这样提交就可以成功。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181044.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!