gpt4 book ai didi

SpringMVC学习笔记-第一章-工作流程、Bean加载控制、请求与响应(参数接收与内容返回)、RESTful

转载 作者:我是一只小鸟 更新时间:2023-01-26 22:31:58 25 4
gpt4 key购买 nike

【前置内容】Spring 学习笔记全系列传送门:

  • Spring学习笔记 - 第一章 - IoC(控制反转)、IoC容器、Bean的实例化与生命周期、DI(依赖注入) 。

  • Spring学习笔记 - 第二章 - 注解开发、配置管理第三方Bean、注解管理第三方Bean、Spring 整合 MyBatis 和 Junit 案例 。

  • Spring学习笔记 - 第三章 - AOP与Spring事务 。

SpingMVC 学习笔记全系列传送门:

  • 【本章】SpringMVC学习笔记 - 第一章 - 工作流程、Bean加载控制、请求与响应(参数接收与内容返回)、RESTful

目录
  • 1、SpringMVC概述
  • 2、SpringMVC入门案例
    • 2.1 注意事项
    • 2.2 案例制作
    • 2.3 相关知识点
    • 2.4 工作流程解析
      • 2.4.1 启动服务器初始化过程
      • 2.4.2 单次请求过程
    • 2.5 bean 加载控制
      • 2.5.1 问题分析
      • 2.5.2 思路分析
      • 2.5.3 环境准备
      • 2.5.4 设置 bean 加载控制
      • 2.5.5 相关知识点: @ComponentScan
  • 3、请求与相应
    • 3.1 设置请求映射路径
      • 3.1.1 环境准备
      • 3.1.2 问题分析
      • 3.1.3 设置映射路径
    • 3.2 请求参数
      • 3.2.1 环境准备
      • 3.2.2 参数传递及中文乱码处理方案
    • 3.3 五种类型参数传递
      • 3.3.1 普通参数
      • 3.3.2 POJO 数据类型
      • 3.3.3 嵌套 POJO 类型参数
      • 3.3.4 数组类型参数
      • 3.3.5 集合类型参数
      • 3.3.6 相关知识点: @RequestParam
    • 3.4 JSON 数据传输参数
      • 3.4.1 JSON 数据传输参数分类与准备工作
      • 3.4.2 三种参数传输格式
        • 3.4.2.1 json普通数组
        • 3.4.2.2 json对象
        • 3.4.2.3 json对象数组
      • 3.4.3 相关知识点
    • 3.5 日期类型参数传递
    • 3.6 响应
      • 3.6.1 环境准备
      • 3.6.2 响应页面(了解)
      • 3.6.3 返回文本数据(了解)
      • 3.6.4 响应 JSON 数据
        • 3.6.4.1 响应 POJO 对象
        • 3.6.4.2 响应 POJO 集合对象
        • 3.6.4.3 相关知识点: @ResponseBody
  • 4、REST风格
    • 4.1 REST 简介
    • 4.2 RESTful 入门案例
      • 4.2.1 环境准备
      • 4.2.2 思路分析
      • 4.2.3 修改 RESTFUL 风格
        • 4.2.3.1 各项操作
        • 4.2.3.2 相关知识点: @PathVarlable
        • 4.2.3.3 相关知识点:三种接收参数的注解
    • 4.3 RESTFUL 快速开发
      • 4.3.1 开发简化
      • 4.3.2 相关知识点
    • 4.4 RESTFUL 案例
      • 4.4.1 需求分析
      • 4.4.2 环境准备
      • 4.4.3 后台接口开发
      • 4.4.4 页面访问处理

1、SpringMVC概述

  • SpringMVC是一种基于Java实现MVC模型的轻量级Web框架 。

  • 优点 。

    • 使用简单、开发便捷(相比于Servlet)
    • 灵活性强
  • SpringMVC主要负责的就是 。

    • controller如何接收请求和数据
    • 如何将请求和数据转发给业务层
    • 如何将响应数据转换成json发回到前端
  • 三层架构与MVC模式 。

    三层架构与MVC模式

    • 浏览器发送一个请求给后端服务器,后端服务器现在是使用Servlet来接收请求和数据 。

      如果所有的处理都交给Servlet来处理的话,所有的东西都耦合在一起,对后期的维护和扩展极为不利 。

    • 将后端服务器Servlet拆分成三层,分别是 web 、 service 和 dao 。

      • web层主要由servlet来处理,负责页面请求和数据的收集以及响应结果给前端
      • service层主要负责业务逻辑的处理
      • dao层主要负责数据的增删改查操作

      servlet处理请求和数据的时候,存在的问题是一个servlet只能处理一个请求 。

    • 针对web层进行了优化,采用了MVC设计模式,将其设计为 controller 、 view 和 Model 。

      • controller负责请求和数据的接收,接收后将其转发给service进行业务处理
      • service根据需要会调用dao对数据进行增删改查
      • dao把数据处理完后将结果交给service,service再交给controller
      • controller根据需求组装成Model和View,Model和View组合起来生成页面转发给前端浏览器
      • 这样做的好处就是controller可以处理多个请求,并对请求进行分发,执行不同的业务操作。

    三层架构与MVC模式传递

    • 随着互联网的发展,上面的模式因为是同步调用,性能慢慢的跟不是需求,所以异步调用慢慢的走到了前台,是现在比较流行的一种处理方式 。

      • 因为是异步调用,所以后端不需要返回view视图,将其去除
      • 前端如果通过异步调用的方式进行交互,后台就需要将返回的数据转换成json格式进行返回

2、SpringMVC入门案例

2.1 注意事项

  • SpringMVC是基于Spring的,在pom.xml只导入了 spring-webmvc jar包的原因是它会自动依赖spring相关坐标
  • AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类
  • AbstractDispatcherServletInitializer提供了三个接口方法供用户实现
    • createServletApplicationContext方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围
    • getServletMappings方法,设定SpringMVC对应的请求映射路径,即SpringMVC拦截哪些请求
    • createRootApplicationContext方法,如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行,使用方式和createServletApplicationContext相同。
    • createServletApplicationContext用来加载SpringMVC环境
    • createRootApplicationContext用来加载Spring环境

2.2 案例制作

  1. 创建 Maven-webapp 项目,整理包结构 。

    image-20221228060317972

  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>priv.dandelion</groupId>
      <artifactId>01_quickstart</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.2.10.RELEASE</version>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <configuration>
              <port>80</port>
              <path>/</path>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    
    
                                
                              
  3. 创建 Controller 。

                                
                                  // 定义Controller,声明为Spring的bean
    @Controller
    public class UserController {
    
        // 设置当前操作的访问路径
        @RequestMapping("/save")
        // 设置当前操作的返回值类型
        @ResponseBody
        public String save() {
            System.out.println("user----save");
            // 相应的内容直接返回
            return "{'hello':'springmvc'}";
        }
    }
    
                                
                              
  4. 创建配置类 。

                                
                                  // 创建SpringMVC的配置文件,加载controller对应的bean
    @Configuration
    @ComponentScan("priv.dandelion.controller")
    public class SpringMvcConfig {
    }
    
                                
                              
  5. 定义 Servlet 容器启动的配置类( 代替 web.xml ) 。

                                
                                  // 定义一个servlet容器启动的配置类,在此处加载spring配置
    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    
        // 加载SpringMVC容器配置
        @Override
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            // 注册配置
            ctx.register(SpringMvcConfig.class);
            // tomcat服务器启动时就可以加载到SpringMvcConfig.class
            return ctx;
        }
    
        // 设置那些请求归属于SpringMVC处理
        @Override
        protected String[] getServletMappings() {
            // 将所有请求交给SpringMVC处理
            return new String[]{"/"};
        }
    
        // 加载Spring容器配置,此处暂时未用到
        @Override
        protected WebApplicationContext createRootApplicationContext() {
            return null;
        }
    }
    
                                
                              

2.3 相关知识点

  • @Controller 。

    名称 @Controller
    类型 类注解
    位置 SpringMVC控制器类定义上方
    作用 设定SpringMVC的核心控制器bean
  • @RequestMapping 。

    名称 @RequestMapping
    类型 类注解或方法注解
    位置 SpringMVC控制器类或方法定义上方
    作用 设置当前控制器方法请求访问路径
    相关属性 value(默认),请求访问路径
  • @ResponseBody 。

    名称 @ResponseBody
    类型 类注解或方法注解
    位置 SpringMVC控制器类或方法定义上方
    作用 设置当前控制器方法响应内容为当前返回值,无需解析

2.4 工作流程解析

包含关系:

  • Web容器
    • ServletContext
      • WebApplicationContext
        • UserController
          • /save -> save() 【SpringMVC 的映射并不是放在 bean 中管理的】

2.4.1 启动服务器初始化过程

  1. 服务器启动,执行 web 服务器配置类 ServletContainersInitConfig,初始化web容器 。

    • 功能类似于以前的web.xml
  2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象(存在于 ServletContext 中) 。

    • 该方法加载SpringMVC的配置类SpringMvcConfig来初始化SpringMVC的容器 。

                                        
                                          // 加载SpringMVC容器配置
      @Override
      protected WebApplicationContext createServletApplicationContext() {
          AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
          // 注册配置
          ctx.register(SpringMvcConfig.class);
          // tomcat服务器启动时就可以加载到SpringMvcConfig.class
          return ctx;
      }
      
                                        
                                      
  3. 加载SpringMvcConfig配置类,以在下一步加载所需的bean 。

                                  
                                    // 创建SpringMVC的配置文件,加载controller对应的bean
    @Configuration
    @ComponentScan("priv.dandelion.controller")
    public class SpringMvcConfig {
    }
    
                                  
                                
  4. 执行@ComponentScan加载对应的bean 。

    扫描指定包及其子包下所有类上的注解,如Controller类上的@Controller注解 。

  5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法 。

    • 此时就建立了 /save 和 save() 方法的对应关系 。

                                        
                                          // 定义Controller,声明为Spring的bean
      @Controller
      public class UserController {
                      
          // 设置当前操作的访问路径
          @RequestMapping("/save")
          // 设置当前操作的返回值类型
          @ResponseBody
          public String save() {
              System.out.println("user----save");
              // 相应的内容直接返回
              return "{'hello':'springmvc'}";
          }
      }
      
                                        
                                      
  6. 执行getServletMappings方法,设定SpringMVC拦截请求的路径规则 。

    • / 代表所拦截请求的路径规则,只有被拦截后才能交给SpringMVC来处理请求 / 代表所拦截请求的路径规则,只有被拦截后才能交给SpringMVC来处理请求 。

                                        
                                          // 设置那些请求归属于SpringMVC处理
      @Override
      protected String[] getServletMappings() {
          // 将所有请求交给SpringMVC处理
          return new String[]{"/"};
      }
      
                                        
                                      

2.4.2 单次请求过程

  1. 发送请求 http://localhost/save 。

  2. web容器发现该请求满足SpringMVC拦截规则,将请求交给 SpringMVC 处理 。

  3. 解析请求路径 /save 。

  4. 由 /save 匹配执行对应的方法 save() 。

    • 上面的第五步已经将请求路径和方法建立了对应关系,通过 /save 就能找到对应的save方法
  5. 执行 save() 。

  6. 检测到有 @ResponseBody 直接将 save() 方法的返回值作为响应体返回给请求方 。

2.5 bean 加载控制

2.5.1 问题分析

问题:

  • 哪些 bean 交给 SpringMVC 管理,哪些包交给 Spring 管理
  • 因为功能不同,如何避免 Spring 错误加载到 SpringMVC 的 bean
  • 包结构 。

    • config目录存入的是配置类,本篇和前面的内容已经写过的配置类有

      • ServletContainersInitConfig
      • SpringConfig
      • SpringMvcConfig
      • JdbcConfig
      • MybatisConfig
    • controller 目录存放的是 SpringMVC 的 controller 类 。

    • service 目录存放的是 service 接口和实现类 。

    • dao 目录存放的是 dao/Mapper 接口 。

  • 管理 。

    • SpringMVC加载其相关bean
      • 表现层 bean(Controller),也就是controller包下的类
    • Spring控制的bean
      • 业务 bean(Service)
      • 功能 bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)

2.5.2 思路分析

加载Spring控制的bean的时候排除掉 SpringMVC 控制的 bean 。

  • 方式一:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
  • 方式二:Spring加载的bean设定扫描范围为priv.dandelion,排除掉controller包中的bean
  • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]

2.5.3 环境准备

  • 创建 Web 的 Maven 项目,删除 web.xml 配置文件 。

  • 依赖 。

                                
                                  <?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>priv.dandelion</groupId>
        <artifactId>02_bean_load</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.6</version>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
                                
                              
  • 创建对应的配置类 。

    • 替代 web.xml 的 web 服务器配置类 ServletContainersInitConfig 。

                                      
                                        public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
          protected WebApplicationContext createServletApplicationContext() {
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringMvcConfig.class);
              return ctx;
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected WebApplicationContext createRootApplicationContext() {
              return null;
          }
      }
      
                                      
                                    
    • SpringMVC 配置类 。

                                      
                                        @Configuration
      @ComponentScan("priv.dandelion.controller")
      public class SpringMvcConfig {
      }
      
                                      
                                    
    • Spring 配置类 。

                                      
                                        @Configuration
      @ComponentScan("priv.dandelion")
      public class SpringConfig {
      }
      
                                      
                                    
  • 实体类 。

                                
                                  public class User {
        private Integer id;
        private String name;
        private Integer age;
        // Getter
        // Settrt
        // toString
    }
    
                                
                              
  • Dao 接口 。

                                
                                  public interface UserDao {
        @Insert("insert into tbl_user(name,age)values(#{name},#{age})")
        public void save(User user);
    }
    
                                
                              
  • Service 实现类 (接口不表) 。

                                
                                  @Service
    public class UserServiceImpl implements UserService {
        public void save(User user) {
            System.out.println("user service ...");
        }
    }
    
                                
                              
  • Controller 。

                                
                                  @Controller
    public class UserController {
    
        @RequestMapping("/save")
        @ResponseBody
        public String save(){
            System.out.println("user save ...");
            return "{'info':'springmvc'}";
        }
    }
    
                                
                              

2.5.4 设置 bean 加载控制

  • web服务器启动时加载配置类的相关配置 。

    • 标准方式 。

      • 方式
        • 修改 createRootApplicationContext() 方法中的内容
          • 与 createServletApplicationContext() 基本相同但是加载 SpringConfig.class
      • 说明
        • createServletApplicationContext() 加载的是 SpringMVC 环境配置
        • createRootApplicationContext() 加载的是 Spring 环境配置
                                      
                                        public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
          protected WebApplicationContext createServletApplicationContext() {
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringMvcConfig.class);
              return ctx;
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected WebApplicationContext createRootApplicationContext() {
              AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
              ctx.register(SpringConfig.class);
              return ctx;
          }
      }
      
                                      
                                    
    • 简化方式 。

      说明:

      • AbstractDispatcherServletInitializer 类包含一个子类 AbstractAnnotationConfigDispatcherServletInitializer 可以简化配置
      • 方法名中包含 RootConfig 的是 Spring 的配置,包含 ServletConfig 的是对 SpringMVC 的配置,与标准方式中的相同
                                      
                                        public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          @Override
          protected Class<?>[] getRootConfigClasses() {
              return new Class[]{SpringConfig.class};
          }
      
          @Override
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
      
          @Override
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
      }public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          @Override
          protected Class<?>[] getRootConfigClasses() {
              return new Class[]{SpringConfig.class};
          }
      
          @Override
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
      
          @Override
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
      }
      
                                      
                                    
  • bean 加载控制方式 。

    • 方案一:修改Spring 配置类,精准扫描 。

      说明:

      • 此处使用了MyBatis技术且是自动代理,所以可以不扫Dao
      • 但是建议按照标准开发规则书写,通用性强
                                      
                                        @Configuration
      @ComponentScan({"priv.dandelion.service","priv.dandelion.dao"})
      public class SpringConfig {
      }
      
                                      
                                    
    • 方案二 。

      说明:

      • 扫描所有的包 。

      • 但是使用过滤器进行排除 。

        • 过滤的类型是按注解过滤,过滤Controller注解

      使用到的属性:

      • excludeFilters属性:设置扫描加载bean时,排除的过滤规则 。

      • type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除 。

        • ANNOTATION:按照注解排除
        • ASSIGNABLE_TYPE:按照指定的类型过滤
        • ASPECTJ:按照Aspectj表达式排除,基本上不会用
        • REGEX:按照正则表达式排除
        • CUSTOM:按照自定义规则排除

        大家只需要知道第一种ANNOTATION即可 。

      • classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean 。

                                      
                                        @Configuration
      @ComponentScan(
              value = "priv.dandelion",
              excludeFilters = @ComponentScan.Filter(
                      type = FilterType.ANNOTATION,
                      classes = Controller.class
              )
      )
      public class SpringConfig {
      }
      
                                      
                                    
    • 方式三(不区分 Spring 与 SpringMVC 的环境)【此处不做详细说明】 。

2.5.5 相关知识点: @ComponentScan

名称 @ComponentScan
类型 类注解
位置 类定义上方
作用 设置spring配置类扫描路径,用于加载使用注解格式定义的bean
相关属性 excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)和具体项(classes)
includeFilters:加载指定的bean,需要指定类别(type)和具体项(classes)

3、请求与相应

3.1 设置请求映射路径

本小节注意:

  • 当类上和方法上都添加了 @RequestMapping 注解,前端发送请求的时候,要和两个注解的value值相加匹配才能访问到。
  • @RequestMapping注解value属性前面加不加 / 都可以

3.1.1 环境准备

  • 依赖 。

                                
                                  <?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>priv.dandelion</groupId>
        <artifactId>03_request_mapping</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
                                
                              
  • 配置类 。

    • Spring 配置类(此处未使用到) 。

                                      
                                        @Configuration
      @ComponentScan(value = "priv.dandelion",
              excludeFilters = @ComponentScan.Filter(
                      type = FilterType.ANNOTATION,
                      classes = Controller.class
              )
      )
      public class SpringConfig {
      }
      
                                      
                                    
    • SpringMVC 配置类 。

                                      
                                        @Configuration
      @ComponentScan("priv.dandelion.controller")
      public class SpringMvcConfig {
      }
      
                                      
                                    
    • web服务器配置类 (简化配置) 。

                                      
                                        public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected Class<?>[] getRootConfigClasses() {
              return new Class[0];
          }
      }
      
                                      
                                    
  • Controller 。

    • UserController 。

                                      
                                        @Controller
      public class UserController {
      
          @RequestMapping("/save")
          @ResponseBody
          public String save(){
              System.out.println("user save ...");
              return "{'module':'user save'}";
          }
      
          @RequestMapping("/delete")
          @ResponseBody
          public String delete(){
              System.out.println("user delete ...");
              return "{'module':'user delete'}";
          }
      }
      
                                      
                                    
    • BookController 。

                                      
                                        @Controller
      public class BookController {
      
          @RequestMapping("/save")
          @ResponseBody
          public String save(){
              System.out.println("book save ...");
              return "{'module':'book save'}";
          }
      }
      
                                      
                                    

3.1.2 问题分析

  • 以上环境准备完成后,启动服务器时会报错 。

                                  
                                    [INFO] Initializing Servlet 'dispatcher'
    [WARNING] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'userController' method 
    priv.dandelion.controller.UserController#save()
    to { /save}: There is already 'bookController' bean method
    priv.dandelion.controller.BookController#save() mapped.
    [ERROR] Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'userController' method 
    priv.dandelion.controller.UserController#save()
    to { /save}: There is already 'bookController' bean method
    priv.dandelion.controller.BookController#save() mapped.
        at ...
        at ...
        ...
    
                                  
                                
  • 从错误信息可知 。

    • UserController有一个save方法,访问路径为 http://localhost/save
    • BookController也有一个save方法,访问路径为 http://localhost/save
    • 当访问 http://localhost/saved 的时候,到底是访问 UserController 还是 BookController,就会出现冲突
  • 解决方案:为不同模块设置模块名作为请求路径前置 。

    • 对于Book模块的save,将其访问路径设置 http://localhost/book/save
    • 对于User模块的save,将其访问路径设置 http://localhost/user/save

3.1.3 设置映射路径

  • 方案一(耦合度高不推荐):对每一个资源的 RequestMapping 进行修改 。

    • UserController 。

                                      
                                        @Controller
      public class UserController {
      
          @RequestMapping("/user/save")
          @ResponseBody
          public String save(){
              System.out.println("user save ...");
              return "{'module':'user save'}";
          }
      
          @RequestMapping("/user/delete")
          @ResponseBody
          public String delete(){
              System.out.println("user delete ...");
              return "{'module':'user delete'}";
          }
      }
      
                                      
                                    
    • BookController(不表) 。

  • 方案二:为 Controller 添加一个整体的 RequestMapping(称为 请求路径前缀 ),其他不变 。

    • UserController 。

                                      
                                        @Controller
      @RequestMapping("/user")
      public class UserController {
      
          @RequestMapping("/save")
          @ResponseBody
          public String save(){
              System.out.println("user save ...");
              return "{'module':'user save'}";
          }
      
          @RequestMapping("/delete")
          @ResponseBody
          public String delete(){
              System.out.println("user delete ...");
              return "{'module':'user delete'}";
          }
      }
      
                                      
                                    
    • BookController(不表) 。

3.2 请求参数

3.2.1 环境准备

  • 依赖、配置类见 3.1.1 。

  • 实体类 。

    • Address 。

                                      
                                        public class Address {
          private String province;
          private String city;
          
          // Getter,Setter,toString不表
      }
      
                                      
                                    
    • User 。

                                      
                                        public class User {
          private String name;
          private int age;
      
          // Getter,Setter,toString不表
      }
      
                                      
                                    
  • Controller 。

                                
                                  @Controller
    public class UserController {
    
        @RequestMapping("/commonParam")
        @ResponseBody
        public String commonParam(){
            return "{'module':'commonParam'}";
        }
    }
    
                                
                              

3.2.2 参数传递及中文乱码处理方案

Get请求与参数

                          
                            http://localhost/commonParam?name=dandelion&age=18

                          
                        

POST请求与参数

  • 发送Post请求时,参数放在请求体中,若使用PostMan工具,参数需要写在Body模块中,发送表单数据时使用 x-www-from-urlencoded form-data 除了发送表单之外还可以发送文件)
  • GET请求 。

    • 接收参数 。

                                      
                                        @Controller
      public class UserController {
      
          @RequestMapping("/commonParam")
          @ResponseBody
          public String commonParam(String name, int age){
              System.out.println("普通参数name:"+ name);
              System.out.println("普通参数age:"+ age);
              return "{'module':'commonParam'}";
          }
      }
      
                                      
                                    
    • GET中文乱码:配置pom.xml 。

      Tomcat8.5以后的版本已经处理了中文乱码的问题,但是IDEA中的Tomcat插件目前只到Tomcat7,所以需要修改pom.xml来解决GET请求中文乱码问题 。

                                      
                                        <build>
          <plugins>
              <plugin>
                  <groupId>org.apache.tomcat.maven</groupId>
                  <artifactId>tomcat7-maven-plugin</artifactId>
                  <version>2.1</version>
                  <configuration>
                      <port>80</port><!--tomcat端口号-->
                      <path>/</path> <!--虚拟目录-->
                      <uriEncoding>UTF-8</uriEncoding><!--访问路径编解码字符集-->
                  </configuration>
              </plugin>
          </plugins>
      </build>
      
                                      
                                    
  • POST请求 。

    • 接收参数 。

      POST请求接收参数代码与GET请求一致 。

    • POST中文乱码问题:设置过滤器 。

      • 在web服务器配置类 ServletContainersInitConfig 中重写 getServletFilters() 方法,创建所需的过滤器对象,并设置编码字符集为 UTF-8 。

      • CharacterEncodingFilter 是在 spring-web 包中,所以用之前需要导入对应的 jar 包 。

                                              
                                                import org.springframework.web.filter.CharacterEncodingFilter;
        
                                              
                                            
                                      
                                        @Override
      protected Filter[] getServletFilters() {
          CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
          characterEncodingFilter.setEncoding("UTF-8");
          return new Filter[]{characterEncodingFilter};
      }
      
                                      
                                    

3.3 五种类型参数传递

3.3.1 普通参数

普通参数的基本使用已经实现过,详见 3.2.2 参数传递及中文乱码处理方案 。

  • 解决请求中的参数名称和 Controller 方法的参数不一致问题 。

    • 当出现请求中的参数名称和Controller中方法的参数名不匹配时,无法正常接收到参数
    • 使用 @RequestPaam() 注解修饰不一致的参数,为其指定需要匹配的请求参数
                                
                                  @Controller
    public class UserController {
    
        // `http://localhost/commonParam?username=dandelion&age=12`
        @RequestMapping("/commonParam")
        @ResponseBody
        public String commonParam(@RequestParam("username") String name, int age){
            System.out.println("普通参数name:"+ name);
            System.out.println("普通参数age:"+ age);
            return "{'module':'commonParam'}";
        }
    }
    
                                
                              

3.3.2 POJO 数据类型

  • 直接使用一个实体类作为形参,框架会使用 setter 自动将数据进行写入
  • 实体类中的属性名称需要和请求参数的名称保持一致,否则接收不到
  • 若实体类中没有对应的 setter 可以和请求参数的参数名匹配,则默认零假空(未进行写入),可以使用该特性在实际开发中减少工作量
  • 实体类 。

                                
                                  public class User {
        private String name;
        private int age;
    
        // Getter,Setter,toString不表
    }
    
                                
                              
  • Controller 。

                                
                                  @Controller
    public class UserController {
    
        @RequestMapping("/pojoParam")
        @ResponseBody
        public String pojoParam(User user){
            System.out.println("POJO参数:"+ user);
            return "{'module':'pojoParam'}";
        }
    }
    
                                
                              

3.3.3 嵌套 POJO 类型参数

对于嵌套的POJO类型,在进行参数传递时,也要使用嵌套的形式来书写请求参数名称 。

http://localhost/pojoParam?name=dandelion&age=12&address.province=hubei&address.city=wuhan 。

  • 实体类 。

    • User 。

                                      
                                        public class User {
          private String name;
          private int age;
          
          private Address address;
      
          // Getter,Setter,toString不表
      }
      
                                      
                                    
    • Address 。

                                      
                                        public class Address {
          private String province;
          private String city;
          
          // Getter,Setter,toString不表
      }
      
                                      
                                    
  • Controller 。

    Controller 部分代码与 3.3.3 嵌套 POJO 类型参数一致 。

3.3.4 数组类型参数

  • 请求参数为数组时,不同的数组元素使用相同的请求参数名称
  • 接收请求参数时,使用数组作为形参
  • 请求 。

                                
                                  http://localhost/arrayParam?person=zhangsan&person=lisi&person=wangwu
    
                                
                              
  • 接收 。

                                
                                  @Controller
    public class UserController {
    
        @RequestMapping("/arrayParam")
        @ResponseBody
        public String arrayParam(String[] person){
            System.out.println("数组参数:"+ Arrays.toString(person));
            return "{'module':'arrayParam'}";
        }
    }
    
                                
                              

3.3.5 集合类型参数

  • 请求 。

    与数组参数的请求方式相同 。

  • 接收 。

    • 错误案例 。

      以下代码段运行时会报错: NoSuchMethodException: java.util.List.<init>() ,缺少构造,(内心:废话 List 接口哪来的构造) 。

                                        
                                          严重: Servlet.service() for servlet [dispatcher] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface java.util.List] with root cause
      java.lang.NoSuchMethodException: java.util.List.<init>()
      
                                        
                                      
                                      
                                        @Controller
      public class UserController {
      
          @RequestMapping("/listParam")
          @ResponseBody
          public String listParam(List<String> person){
              System.out.println("集合参数:"+ person);
              return "{'module':'listParam'}";
          }
      }
      
                                      
                                    
    • 原因及解决方案 。

      • 问题原因 。

        SpringMVC 将 List 看做是一个 POJO 对象来处理,将其创建一个对象并准备把前端的数据封装到对象中,但是 List 是一个接口无法创建对象,所以报错.

      • 解决方案:使用 @RequestParam 注解 。

        • 集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam 绑定参数关系
        • 显而易见,对于简单数据类型使用数组会比集合更简单些。
                                            
                                              @Controller
        public class UserController {
        
            @RequestMapping("/listParam")
            @ResponseBody
            public String listParam(@RequestParam List<String> person){
                System.out.println("集合参数:"+ person);
                return "{'module':'listParam'}";
            }
        }
        
                                            
                                          

3.3.6 相关知识点: @RequestParam

名称 @RequestParam
类型 形参注解
位置 SpringMVC控制器方法形参定义前面
作用 绑定请求参数与处理器方法形参间的关系
相关参数 required:是否为必传参数
defaultValue:参数默认值

3.4 JSON 数据传输参数

  • 参数放在请求体中,若使用 PostMan 工具,参数需要写在Body模块中,发送表单数据时使用 raw ,并将数据格式修改为 JSON

3.4.1 JSON 数据传输参数分类与准备工作

  • 参数分类 。

                                
                                  // json普通数组
    ["value1","value2","value3",...]
    // json对象
     {"key1":"value1","key2":"value2",...}
    // json对象数组
    [{"key11":"value11",...},{"key21":"value21",...}]
    
                                
                              
  • 准备工作 。

    • 添加依赖 。

                                      
                                        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.0</version>
      </dependency>
      
                                      
                                    
    • 开启SpringMVC注解驱动,用于开启 json 数据类型自动转换: @EnableWebMvc 。

                                      
                                        @Configuration
      @ComponentScan("priv.dandelion.controller")
      @EnableWebMvc
      public class SpringMvcConfig {
      }
      
                                      
                                    
    • 参数前添加@RequestBody 。

      • 使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
      • 区别于 @RequestParam,本小节总结部分会进行说明
      • 区别于 @ResponseBody,书写要正确
      • 下文中展示

3.4.2 三种参数传输格式

3.4.2.1 json普通数组
  • JSON 。

                                
                                  ["zhangsan","lisi","wangwu"]
    
                                
                              
  • 接收 。

                                
                                  @RequestMapping("/listParamForJson")
    @ResponseBody
    // //使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
    public String listParamForJson(@RequestBody List<String> person){
        System.out.println("list common(json)参数传递 list:" + person);
        return "{'module':'list common for json param'}";
    }
    
                                
                              
3.4.2.2 json对象
  • 若 JSON 对象中的 key 与实体类中的 setter 名称(标准书写)不能匹配时,不执行 setter ,实体类中的数据不变(不进行其他操作时默认为零假空)
  • 同理,若不传递某一属性的值,实体类中的数据不变(不进行其他操作时默认为零假空)
  • JSON 。

                                
                                  // 单个POJO
    {
    	"name":"dandelion",
    	"age":12
    }
    
    // 嵌套POJO
    {
    	"name1":"dandelion",
    	"age":12,
        "address":{
            "province":"provinceName",
            "city":"cityName"
        }
    }
    
                                
                              
  • 实体类 。

    见 3.3.3 。

  • 接收 。

                                
                                  @RequestMapping("/pojoParamForJson")
    @ResponseBody
    public String pojoParamForJson(@RequestBody User user){
        System.out.println("pojo(json)参数传递 user:"+user);
        return "{'module':'pojo for json param'}";
    }
    
                                
                              
3.4.2.3 json对象数组
  • JSON 。

                                
                                  [
        {"name":"dandelion","age":15,"address":{"province":"provinceName","city":"cityName"}},
        {"name":"dandelion000","age":12}
    ]
    
                                
                              
  • 接收 。

                                
                                  @RequestMapping("/listPojoParamForJson")
    @ResponseBody
    public String listPojoParamForJson(@RequestBody List<User> list){
        System.out.println("list pojo(json)参数传递 list:"+list);
        return "{'module':'list pojo for json param'}";
    }
    
                                
                              

3.4.3 相关知识点

  • 知识点1: @EnableWebMvc 。

    名称 @EnableWebMvc
    类型 配置类注解
    位置 SpringMVC配置类定义上方
    作用 开启SpringMVC多项辅助功能
  • 知识点2: @RequestBody 。

    • 整理 。

      名称 @RequestBody
      类型 形参注解
      位置 SpringMVC控制器方法形参定义前面
      作用 将请求中请求体所包含的数据传递给请求参数,此注解一个处理器方法只能使用一次
    • @RequestBody与@RequestParam区别 。

      • 区别 。

        • @RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】
        • @RequestBody用于接收json数据【application/json】
      • 应用 。

        • 后期开发中,发送json格式数据为主,@RequestBody应用较广
        • 如果发送非json格式数据,选用@RequestParam接收请求参数

3.5 日期类型参数传递

  • 接收案例 。

    • 请求 。

                                      
                                        http://localhost/dataParam?date=2022/02/22
      
                                      
                                    
    • 接收 。

                                      
                                        @RequestMapping("/dataParam")
      @ResponseBody
      public String dataParam(Date date, Date date1){
          System.out.println("参数传递 date:"+date);
          System.out.println("参数传递 date1:"+date1);
          return"{'module':'data param'}";
      }
      
                                      
                                    
    • 结果 。

      • 发送请求后会发现该部分代码会报错,但若请求参数中只有date而没有date1时则正常接收 。

      • 报错信息:

        方法参数类型不匹配,在将 String 转换为 Date 时出现问题,转换失败 。

                                            
                                              [WARNING] Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2022-02-22'; nested exception is java.lang.IllegalArgumentException]
        
        
                                            
                                          
  • 解决方案(接收任意日期格式的方法):使用 @DateTimeFormat 指定日期格式 。

    • 请求 。

                                      
                                        http://localhost/dataParam?date=2022/02/22&date1=22-02-2022&date2=2022-02-22 22:22:22
      
                                      
                                    
    • 接收 。

                                      
                                        @RequestMapping("/dataParam")
      @ResponseBody
      public String dataParam(Date date,
                              @DateTimeFormat(pattern = "dd-MM-yyyy") Date date1,
                              @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date2){
          System.out.println("参数传递 date:"+ date);
          System.out.println("参数传递 date1(dd-MM-yyyy):"+ date1);
          System.out.println("参数传递 date2(yyyy-MM-dd HH:mm:ss):"+ date2);
          return"{'module':'data param'}";
      }
      
                                      
                                    
  • 相关知识点 。

    • @DateTimeFormat 。

      名称 @DateTimeFormat
      类型 形参注解
      位置 SpringMVC控制器方法形参前面
      作用 设定日期时间型数据格式
      相关属性 pattern:指定日期时间格式字符串
    • 内部实现原理 。

      SpringMVC中提供了很多类型转换接口和实现类,其中有 Converter 接口 。

      • Converter 接口 。

        • Converter所属的包为 org.springframework.core.convert.converter 。

        • 框架中有提供很多对应Converter接口的实现类,用来实现不同数据类型之间的转换,如

        • 请求参数年龄数据(String→Integer) 。

        • 日期格式转换(String → Date) 。

                                            
                                              /**
        *	S: the source type
        *	T: the target type
        */
        public interface Converter<S, T> {
            @Nullable
            //该方法就是将从页面上接收的数据(S)转换成我们想要的数据类型(T)返回
            T convert(S source);
        }
        
                                            
                                          
      • HttpMessageConverter 接口 。

        该接口是实现对象与 JSON 之间的转换工作, 使用时在SpringMVC的配置类把@EnableWebMvc当做标配配置上去,不省略 。

3.6 响应

3.6.1 环境准备

  • 依赖 。

                                
                                  <?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>priv.dandelion</groupId>
        <artifactId>05_response</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.0</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
                                
                              
  • 配置类 。

    • 服务器配置类 。

                                      
                                        public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected Class<?>[] getRootConfigClasses() {
              return new Class[0];
          }
      
          @Override
          protected Filter[] getServletFilters() {
              CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
              characterEncodingFilter.setEncoding("UTF-8");
              return new Filter[]{characterEncodingFilter};
          }
      }
      
                                      
                                    
    • SpringMVC 配置类 。

                                      
                                        @Configuration
      @ComponentScan("priv.dandelion.controller")
      public class SpringMvcConfig {
      }
      
                                      
                                    
  • 实体类 。

                                
                                  public class User {
        private String name;
        private int age;
        //getter...setter...toString省略
    }
    
                                
                              
  • webapp下创建页面 page.jsp 。

                                
                                  <html>
    <body>
    <h2>Hello Spring MVC!</h2>
    </body>
    </html>
    
                                
                              
  • Controller 。

                                
                                  @Controller
    public class UserController {
    
    }
    
                                
                              

3.6.2 响应页面(了解)

  • 注意此处不能使用@ResponseBody,否则会将返回值内容作为字符串返回给前端
  • 注意进行页面跳转时,返回值为页面名称,返回值类型为字符串
                        
                          @RequestMapping("/toJumpPage")
public String toJumpPage() {
    System.out.println("跳转页面");
    return "page.jsp";
}

                        
                      

3.6.3 返回文本数据(了解)

  • 注意此处 @ResponseBody 注解就不能省略
  • 如果省略了会把 response text 当前页面名称去查找,如果没有回报404
                        
                          @RequestMapping("/toText")
@ResponseBody
public String toText() {
    System.out.println("返回纯文本数据");
    return "response text";
}

                        
                      

3.6.4 响应 JSON 数据

准备工作:

  • 开启SpringMVC注解驱动,用于开启 json 数据类型自动转换: @EnableWebMvc 。

                                  
                                    @Configuration
    @ComponentScan("priv.dandelion.controller")
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    
                                  
                                
3.6.4.1 响应 POJO 对象
                        
                          @RequestMapping("/toJsonPOJO")
@ResponseBody
public User toJsonPOJO() {
    System.out.println("返回JSON数据对象");
    User user = new User();
    user.setName("dandelion");
    user.setAge(12);
    return user;
}

                        
                      
3.6.4.2 响应 POJO 集合对象

此处返回的是POJO的集合,基本数据类型的集合同理 。

                        
                          @RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList() {
    System.out.println("返回JSON数据对象");
    User user1 = new User();
    user1.setName("dandelion");
    user1.setAge(12);

    User user2 = new User();
    user2.setName("dandelion000");
    user2.setAge(15);

    List<User> users = new ArrayList<>();
    users.add(user1);
    users.add(user2);
    return users;
}

                        
                      
3.6.4.3 相关知识点: @ResponseBody
  • 整理 。

    名称 @ResponseBody
    类型 方法\类注解
    位置 SpringMVC控制器方法定义上方和控制类上
    作用 设置当前控制器返回值作为响应体,
    写在类上,该类的所有方法都有该注解功能
    相关属性 pattern:指定日期时间格式字符串
  • 说明 。

    • 该注解可以写在类上或者方法上 。

    • 写在类上就是该类下的所有方法都有@ReponseBody功能 。

    • 当方法上有@ReponseBody注解后 。

      • 方法的返回值为字符串,会将其作为文本内容直接响应给前端
      • 方法的返回值为对象,会将对象转换成JSON响应给前端
    • 此处又使用到了类型转换,内部还是通过Converter接口的实现类完成的,所以Converter除了前面所说的功能外,它还可以实现

      • 对象转Json数据(POJO -> json) 。

      • 集合转Json数据(Collection -> json) 。

4、REST风格

4.1 REST 简介

  • REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格 。

  • REST风格与传统风格的区别 。

    • 传统风格资源描述形式 。

      • http://localhost/user/getById?id=1 查询id为1的用户信息
      • http://localhost/user/saveUser 保存用户信息
    • REST风格描述形式 。

      • http://localhost/user/1
      • http://localhost/user
  • REST风格的优点 。

    • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
    • 书写简化
  • REST风格的使用 。

    • 按照REST风格访问资源时使用 行为动作 区分对资源进行了何种操作 。

      • GET(查询) http://localhost/users 查询全部用户信息
      • GET(查询) http://localhost/users/1 查询指定用户信息
      • POST(新增/保存) http://localhost/users 添加用户信息
      • PUT(修改/更新) http://localhost/users 修改用户信息
      • DELETE(删除) http://localhost/users/1 删除用户信息
    • 请求方式:按照不同的请求方式代表不同的操作类型 。

      • 发送GET请求是用来做查询
      • 发送POST请求是用来做新增
      • 发送PUT请求是用来做修改
      • 发送DELETE请求是用来做删除
  • 注意 。

    • 上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范
      • REST提供了对应的架构方式,按照这种架构设计项目可以降低开发的复杂性,提高系统的可伸缩性
      • REST中规定GET/POST/PUT/DELETE针对的是查询/新增/修改/删除,但是我们如果非要用GET请求做删除,这点在程序上运行是可以实现的
      • 但是如果绝大多数人都遵循这种风格,你写的代码让别人读起来就有点莫名其妙了。
    • 描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts......
  • RESTful 。

    • 根据REST风格对资源进行访问称为RESTful

4.2 RESTful 入门案例

4.2.1 环境准备

  • 依赖 。

                                
                                  <?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>priv.dandelion</groupId>
        <artifactId>06_rest</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.0</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
    
                                
                              
  • 配置类 。

    • 服务器配置类 。

                                      
                                        public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected Class<?>[] getRootConfigClasses() {
              return new Class[0];
          }
      
          @Override
          protected Filter[] getServletFilters() {
              CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
              characterEncodingFilter.setEncoding("UTF-8");
              return new Filter[]{characterEncodingFilter};
          }
      }
      
                                      
                                    
    • SpringMVC配置类,开启json数据类型自动转换 。

                                      
                                        @Configuration
      @ComponentScan("priv.dandelion.controller")
      @EnableWebMvc
      public class SpringMvcConfig {
      }
      
                                      
                                    
  • 实体类 。

    • User 。

                                      
                                        public class User {
          private String name;
          private int age;
          //getter...setter...toString省略
      }
      
                                      
                                    
    • Book 。

                                      
                                        public class Book {
          private String name;
          private double price;
           //getter...setter...toString省略
      }
      
                                      
                                    
  • Controller 。

    • UserController 。

                                      
                                        @Controller
      public class UserController {
          @RequestMapping("/save")
          @ResponseBody
          public String save(@RequestBody User user) {
              System.out.println("user save..."+user);
              return "{'module':'user save'}";
          }
      
          @RequestMapping("/delete")
          @ResponseBody
          public String delete(Integer id) {
              System.out.println("user delete..." + id);
              return "{'module':'user delete'}";
          }
      
          @RequestMapping("/update")
          @ResponseBody
          public String update(@RequestBody User user) {
              System.out.println("user update..." + user);
              return "{'module':'user update'}";
          }
      
          @RequestMapping("/getById")
          @ResponseBody
          public String getById(Integer id) {
              System.out.println("user getById..." + id);
              return "{'module':'user getById'}";
          }
      
          @RequestMapping("/findAll")
          @ResponseBody
          public String getAll() {
              System.out.println("user getAll...");
              return "{'module':'user getAll'}";
          }
      }
      
                                      
                                    
    • BookController 。

                                      
                                        @Controller
      public class BookController {
      
          @RequestMapping(value = "/books",method = RequestMethod.POST)
          @ResponseBody
          public String save(@RequestBody Book book){
              System.out.println("book save..." + book);
              return "{'module':'book save'}";
          }
      
          @RequestMapping(value = "/books/{id}",method = RequestMethod.DELETE)
          @ResponseBody
          public String delete(@PathVariable Integer id){
              System.out.println("book delete..." + id);
              return "{'module':'book delete'}";
          }
      
          @RequestMapping(value = "/books",method = RequestMethod.PUT)
          @ResponseBody
          public String update(@RequestBody Book book){
              System.out.println("book update..." + book);
              return "{'module':'book update'}";
          }
      
          @RequestMapping(value = "/books/{id}",method = RequestMethod.GET)
          @ResponseBody
          public String getById(@PathVariable Integer id){
              System.out.println("book getById..." + id);
              return "{'module':'book getById'}";
          }
      
          @RequestMapping(value = "/books",method = RequestMethod.GET)
          @ResponseBody
          public String getAll(){
              System.out.println("book getAll...");
              return "{'module':'book getAll'}";
          }
      
      }
      
                                      
                                    

4.2.2 思路分析

  • 将之前的增删改查替换成RESTful的开发方式
    • 修改前: 新增: /save ,修改: /update,删除 /delete...
  • 修改后:
    • 增删改查: /users
    • 根据GET查询、POST新增、PUT修改、DELETE删除对方法的请求方式进行限定

4.2.3 修改 RESTFUL 风格

4.2.3.1 各项操作
  • 新增 。

    • 请求 。

                                      
                                        POST http://localhost/users
      
                                      
                                    
    • 接收 。

                                      
                                        @RequestMapping(value = "/users", method = RequestMethod.POST)
      @ResponseBody
      public String save(@RequestBody User user) {
          System.out.println("user save..."+user);
          return "{'module':'user save'}";
      }
      
                                      
                                    
  • 删除 。

    • 请求 。

                                      
                                        DELETE http://localhost/users/1
      
                                      
                                    
    • 接收 。

      • 使用REST风格时,参数写在请求路径中 。

      • 接收时对参数使用 @PathVariable 注解,在资源路径的参数位置使用 {} ,其中的值应和参数名称保持一致 。

      • 若参数名称和 {} 中的内容不一致,应手动进行绑定,使用 @PathVariable 注解的 value 属性,如下:

                                              
                                                @RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
        @ResponseBody
        public String delete(@PathVariable("id") Integer userId) {}
        
                                              
                                            
                                      
                                        @RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
      @ResponseBody
      public String delete(@PathVariable Integer id) {
          System.out.println("user delete..." + id);
          return "{'module':'user delete'}";
      }
      
                                      
                                    
  • 修改 。

    • 请求 。

                                      
                                        PUT http://localhost/users
      
                                      
                                    
    • 接收 。

                                      
                                        @RequestMapping(value = "/users", method = RequestMethod.PUT)
      @ResponseBody
      public String update(@RequestBody User user) {
          System.out.println("user update..." + user);
          return "{'module':'user update'}";
      }
      
                                      
                                    
  • 查询 。

    • 查询单个 。

      • 请求 。

                                            
                                              GET http://localhost/users/1
        
                                            
                                          
      • 接收 。

                                            
                                              @RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
        @ResponseBody
        public String getById(@PathVariable Integer id) {
            System.out.println("user getById..." + id);
            return "{'module':'user getById'}";
        }
        
                                            
                                          
    • 查询所有 。

      • 请求 。

                                            
                                              GET http://localhost/users
        
                                            
                                          
      • 接收 。

                                            
                                              @RequestMapping(value = "/users", method = RequestMethod.GET)
        @ResponseBody
        public String getAll() {
            System.out.println("user getAll...");
            return "{'module':'user getAll'}";
        }
        
                                            
                                          
4.2.3.2 相关知识点: @PathVarlable
名称 @PathVariable
类型 形参注解
位置 SpringMVC控制器方法形参定义前面
作用 绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
4.2.3.3 相关知识点:三种接收参数的注解
  • 区别 。

    • @RequestParam 用于接收url地址传参或表单传参
    • @RequestBody 用于接收json数据
    • @PathVariable 用于接收路径参数,使用{参数名称}描述路径参数
  • 应用 。

    • 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody 应用较广
    • 如果发送非 json 格式数据,选用 @RequestParam 接收请求参数
    • 采用 RESTful 进行开发,当参数数量较少时,例如1个,可以采用 @PathVariable 接收请求路径变量,通常用于传递id值

4.3 RESTFUL 快速开发

4.3.1 开发简化

  • 未简化代码 。

                                
                                  @Controller
    public class BookController {
    
        @RequestMapping(value = "/books",method = RequestMethod.POST)
        @ResponseBody
        public String save(@RequestBody Book book){
            System.out.println("book save..." + book);
            return "{'module':'book save'}";
        }
    
        @RequestMapping(value = "/books/{id}",method = RequestMethod.DELETE)
        @ResponseBody
        public String delete(@PathVariable Integer id){
            System.out.println("book delete..." + id);
            return "{'module':'book delete'}";
        }
    
        @RequestMapping(value = "/books",method = RequestMethod.PUT)
        @ResponseBody
        public String update(@RequestBody Book book){
            System.out.println("book update..." + book);
            return "{'module':'book update'}";
        }
    
        @RequestMapping(value = "/books/{id}",method = RequestMethod.GET)
        @ResponseBody
        public String getById(@PathVariable Integer id){
            System.out.println("book getById..." + id);
            return "{'module':'book getById'}";
        }
    
        @RequestMapping(value = "/books",method = RequestMethod.GET)
        @ResponseBody
        public String getAll(){
            System.out.println("book getAll...");
            return "{'module':'book getAll'}";
        }
    
    }
    
                                
                              
  • 简化过程(参见注释) 。

    1. 将请求路径中共同的部分抽取
    2. 将方法上@RequestMapping中不需要的value属性省略
    3. 将所有方法上的@ResponseBody抽取
    4. 存在@Controller和@ResponseBody,可以使用@RestController代替
    5. 使用@PostMapping、@DeleteMapping等注解代替@RequestMapping
                                
                                  // @Controller
    // 3.所有方法均需要@ResponseBody,抽取
    // @ResponseBody
    @RestController // 4.其中包含了@Controller和@ResponseBody
    // 1.以前缀的形式将请求路径中相同的内容抽取出来
    @RequestMapping("/books")
    public class BookController {
    
        // 2.value属性已经完全被抽取,可以省略
        // @RequestMapping(method = RequestMethod.POST)
        // 5.简化上一行代码,下同
        @PostMapping
        public String save(@RequestBody Book book){
            System.out.println("book save..." + book);
            return "{'module':'book save'}";
        }
    
        // @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
        @DeleteMapping("/{id}")
        public String delete(@PathVariable Integer id){
            System.out.println("book delete..." + id);
            return "{'module':'book delete'}";
        }
    
        // @RequestMapping(method = RequestMethod.PUT)
        @PutMapping
        public String update(@RequestBody Book book){
            System.out.println("book update..." + book);
            return "{'module':'book update'}";
        }
    
        // @RequestMapping(value = "/{id}",method = RequestMethod.GET)
        @GetMapping("/{id}")
        public String getById(@PathVariable Integer id){
            System.out.println("book getById..." + id);
            return "{'module':'book getById'}";
        }
    
        // @RequestMapping(method = RequestMethod.GET)
        @GetMapping
        public String getAll(){
            System.out.println("book getAll...");
            return "{'module':'book getAll'}";
        }
    }
    
                                
                              
  • 简化后代码 。

                                
                                  @RestController
    @RequestMapping("/books")
    public class BookController {
    
        @PostMapping
        public String save(@RequestBody Book book){
            System.out.println("book save..." + book);
            return "{'module':'book save'}";
        }
    
        @DeleteMapping("/{id}")
        public String delete(@PathVariable Integer id){
            System.out.println("book delete..." + id);
            return "{'module':'book delete'}";
        }
    
        @PutMapping
        public String update(@RequestBody Book book){
            System.out.println("book update..." + book);
            return "{'module':'book update'}";
        }
    
        @GetMapping("/{id}")
        public String getById(@PathVariable Integer id){
            System.out.println("book getById..." + id);
            return "{'module':'book getById'}";
        }
    
        @GetMapping
        public String getAll(){
            System.out.println("book getAll...");
            return "{'module':'book getAll'}";
        }
    }
    
                                
                              

4.3.2 相关知识点

  • 知识点1:@RestController 。

    名称 @RestController
    类型 类注解
    位置 基于SpringMVC的RESTful开发控制器类定义上方
    作用 设置当前控制器类为RESTful风格,
    等同于@Controller与@ResponseBody两个注解组合功能
  • 知识点2:@GetMapping @PostMapping @PutMapping @DeleteMapping 。

    名称 @GetMapping @PostMapping @PutMapping @DeleteMapping
    类型 方法注解
    位置 基于SpringMVC的RESTful开发控制器方法定义上方
    作用 设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,
    例如@GetMapping对应GET请求
    相关属性 value(默认):请求访问路径

4.4 RESTFUL 案例

4.4.1 需求分析

4.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>priv.dandelion</groupId>
        <artifactId>07_rest_case</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <dependencies>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.10.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.0</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <port>80</port>
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
                                
                              
  • 配置类 。

    • 服务器配置类 。

                                      
                                        public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
      
          protected Class<?>[] getServletConfigClasses() {
              return new Class[]{SpringMvcConfig.class};
          }
          protected String[] getServletMappings() {
              return new String[]{"/"};
          }
          protected Class<?>[] getRootConfigClasses() {
              return new Class[0];
          }
      
          @Override
          protected Filter[] getServletFilters() {
              CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
              characterEncodingFilter.setEncoding("UTF-8");
              return new Filter[]{characterEncodingFilter};
          }
      }
      
                                      
                                    
    • SpringMVC配置类 。

                                      
                                        @Configuration
      @ComponentScan("priv.dandelion.controller")
      @EnableWebMvc
      public class SpringMvcConfig {
      }
      
                                      
                                    
  • 实体类 。

                                
                                  public class Book {
        private Integer id;
        private String type;
        private String name;
        private String description;
        //setter...getter...toString略
    }
    
                                
                              
  • 控制器 。

                                
                                  @Controller
    public class BookController {
    
    }
    
                                
                              

4.4.3 后台接口开发

                        
                          @RestController
@RequestMapping("/books")
public class BookController {

    @PostMapping
    public String save(@RequestBody Book book) {
        System.out.println("book save ==> "+ book);
        return "{'module':'book save success'}";
    }

    @GetMapping
    public List<Book> getAll() {
        System.out.println("book getAll is running ...");
        List<Book> bookList = new ArrayList<Book>();

        Book book1 = new Book();
        book1.setType("计算机");
        book1.setName("SpringMVC1");
        book1.setDescription("123");
        bookList.add(book1);

        Book book2 = new Book();
        book2.setType("计算机");
        book2.setName("SpringMVC2");
        book2.setDescription("234");
        bookList.add(book2);

        Book book3 = new Book();
        book3.setType("计算机丛书");
        book3.setName("SpringMVC3");
        book3.setDescription("345");
        bookList.add(book3);

        return bookList;
    }
}

                        
                      

4.4.4 页面访问处理

  • 页面准备 。

    • 环境:vue.js + axios + elementui 。

    • 页面 。

                                      
                                        <!DOCTYPE html>
      
      <html>
          <head>
              <!-- 页面meta -->
              <meta charset="utf-8">
              <title>SpringMVC案例</title>
              <!-- 引入样式 -->
              <link rel="stylesheet" href="../plugins/elementui/index.css">
              <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css">
              <link rel="stylesheet" href="../css/style.css">
          </head>
      
          <body class="hold-transition">
      
              <div id="app">
      
                  <div class="content-header">
                      <h1>图书管理</h1>
                  </div>
      
                  <div class="app-container">
                      <div class="box">
                          <div class="filter-container">
                              <el-input placeholder="图书名称" style="width: 200px;" class="filter-item"></el-input>
                              <el-button class="dalfBut">查询</el-button>
                              <el-button type="primary" class="butT" @click="openSave()">新建</el-button>
                          </div>
      
                          <el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row>
                              <el-table-column type="index" align="center" label="序号"></el-table-column>
                              <el-table-column prop="type" label="图书类别" align="center"></el-table-column>
                              <el-table-column prop="name" label="图书名称" align="center"></el-table-column>
                              <el-table-column prop="description" label="描述" align="center"></el-table-column>
                              <el-table-column label="操作" align="center">
                                  <template slot-scope="scope">
                                      <el-button type="primary" size="mini">编辑</el-button>
                                      <el-button size="mini" type="danger">删除</el-button>
                                  </template>
                              </el-table-column>
                          </el-table>
      
                          <div class="pagination-container">
                              <el-pagination
                                  class="pagiantion"
                                  @current-change="handleCurrentChange"
                                  :current-page="pagination.currentPage"
                                  :page-size="pagination.pageSize"
                                  layout="total, prev, pager, next, jumper"
                                  :total="pagination.total">
                              </el-pagination>
                          </div>
      
                          <!-- 新增标签弹层 -->
                          <div class="add-form">
                              <el-dialog title="新增图书" :visible.sync="dialogFormVisible">
                                  <el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right" label-width="100px">
                                      <el-row>
                                          <el-col :span="12">
                                              <el-form-item label="图书类别" prop="type">
                                                  <el-input v-model="formData.type"/>
                                              </el-form-item>
                                          </el-col>
                                          <el-col :span="12">
                                              <el-form-item label="图书名称" prop="name">
                                                  <el-input v-model="formData.name"/>
                                              </el-form-item>
                                          </el-col>
                                      </el-row>
                                      <el-row>
                                          <el-col :span="24">
                                              <el-form-item label="描述">
                                                  <el-input v-model="formData.description" type="textarea"></el-input>
                                              </el-form-item>
                                          </el-col>
                                      </el-row>
                                  </el-form>
                                  <div slot="footer" class="dialog-footer">
                                      <el-button @click="dialogFormVisible = false">取消</el-button>
                                      <el-button type="primary" @click="saveBook()">确定</el-button>
                                  </div>
                              </el-dialog>
                          </div>
      
                      </div>
                  </div>
              </div>
          </body>
      
          <!-- 引入组件库 -->
          <script src="../js/vue.js"></script>
          <script src="../plugins/elementui/index.js"></script>
          <script type="text/javascript" src="../js/jquery.min.js"></script>
          <script src="../js/axios-0.18.0.js"></script>
      
          <script>
              var vue = new Vue({
      
                  el: '#app',
      
                  data:{
      				dataList: [],//当前页要展示的分页列表数据
                      formData: {},//表单数据
                      dialogFormVisible: false,//增加表单是否可见
                      dialogFormVisible4Edit:false,//编辑表单是否可见
                      pagination: {},//分页模型数据,暂时弃用
                  },
      
                  //钩子函数,VUE对象初始化完成后自动执行
                  created() {
                      this.getAll();
                  },
      
                  methods: {
                      // 重置表单
                      resetForm() {
                          //清空输入框
                          this.formData = {};
                      },
      
                      // 弹出添加窗口
                      openSave() {
                          this.dialogFormVisible = true;
                          this.resetForm();
                      },
      
                      //添加
                      saveBook () {
                          axios.post("/books",this.formData).then((res)=>{
      
                          });
                      },
      
                      //主页列表查询
                      getAll() {
                          axios.get("/books").then((res)=>{
                              this.dataList = res.data;
                          });
                      },
      
                  }
              })
          </script>
      </html>
      
                                      
                                    
  • 页面访问存在问题及解决方案 。

    • 存在问题:无法访问到页面 。

      • 报错内容 。

                                            
                                              [WARNING] Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
        [WARNING] No mapping for GET /pages/books.html
        
                                            
                                          
      • 原因 。

        现在发送请求 http://localhost/pages/books.html 访问这个页面,但是被SpringMVC拦截,认为应该有一个 Controller 中方法的 RequestMapping 叫这个名字 。

    • 解决方案 放行非SpringMVC的请求 。

      • 遇到这种情况 SpringMVC 应当放行,由 web 服务器进行处理
      • web 服务器配置类中 getServletMappings 拦截了所有的请求,交给 SpringMVC 处理,需要为 SpringMVC 的配置添加过滤,放行页面请求
      • 对页面的过滤一般单独抽成一个功能类
      • 功能类 SpringMvcSupport 。

        • 需要继承 WebMvcConfigurationSupport,覆写 addResourceHandlers ,操作 registry 属性
        • 添加 @Configuration 注解,以用于包扫描
                                            
                                              @Configuration
        public class SpringMvcSupport extends WebMvcConfigurationSupport {
        
            // 添加资源过滤
            @Override
            protected void addResourceHandlers(ResourceHandlerRegistry registry) {
                // 当访问页面时,如果请求的是/pages/**,不走MVC,走/pages目录下的内容
                registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
                registry.addResourceHandler("/js/**").addResourceLocations("/js/");
                registry.addResourceHandler("/css/**").addResourceLocations("/css/");
                registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
                // ...
            }
        }
        
                                            
                                          
      • 配置包扫描 。

                                            
                                              @Configuration
        @ComponentScan({"priv.dandelion.controller","priv.dandelion.config"})
        @EnableWebMvc
        public class SpringMvcConfig {
        }
        
                                            
                                          

最后此篇关于SpringMVC学习笔记-第一章-工作流程、Bean加载控制、请求与响应(参数接收与内容返回)、RESTful的文章就讲到这里了,如果你想了解更多关于SpringMVC学习笔记-第一章-工作流程、Bean加载控制、请求与响应(参数接收与内容返回)、RESTful的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com