【前置内容】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发回到前端

2、SpringMVC入门案例

2.1 注意事项

  • SpringMVC是基于Spring的,在pom.xml只导入了spring-webmvcjar包的原因是它会自动依赖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 相关知识点

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

2.5.2 思路分析

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

2.5.3 环境准备

2.5.4 设置 bean 加载控制

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 环境准备

3.1.2 问题分析

3.1.3 设置映射路径

3.2 请求参数

3.2.1 环境准备

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

Get请求与参数:

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

POST请求与参数:

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

3.3 五种类型参数传递

3.3.1 普通参数

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

3.3.2 POJO 数据类型

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

3.3.3 嵌套 POJO 类型参数

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

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

3.3.4 数组类型参数

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

3.3.5 集合类型参数

3.3.6 相关知识点:@RequestParam

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

3.4 JSON 数据传输参数

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

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

3.4.2 三种参数传输格式

3.4.2.1 json普通数组
3.4.2.2 json对象
  • 若 JSON 对象中的 key 与实体类中的 setter 名称(标准书写)不能匹配时,不执行 setter ,实体类中的数据不变(不进行其他操作时默认为零假空)
  • 同理,若不传递某一属性的值,实体类中的数据不变(不进行其他操作时默认为零假空)
3.4.2.3 json对象数组

3.4.3 相关知识点

3.5 日期类型参数传递

3.6 响应

3.6.1 环境准备

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

4、REST风格

4.1 REST 简介

4.2 RESTful 入门案例

4.2.1 环境准备

4.2.2 思路分析

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

4.2.3 修改 RESTFUL 风格

4.2.3.1 各项操作
4.2.3.2 相关知识点:@PathVarlable
名称 @PathVariable
类型 形参注解
位置 SpringMVC控制器方法形参定义前面
作用 绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
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 后台接口开发

@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 页面访问处理