小白学习笔记(SpringMVC)

整体流程:

SpringMVC 六大核心组件

SpringMVC 所有功能都靠这 6 个组件配合,只有 Controller 是我们写的,其余都是框架自带

  1. DispatcherServlet(前端控制器) 核心大脑 / 总调度 所有浏览器请求,第一个到达的就是它,统一分配任务,不做具体业务。
  2. HandlerMapping(处理器映射器) 找路工具 根据请求的 URL,找到对应的Controller处理方法。
  3. HandlerAdapter(处理器适配器) 执行工具统一调用我们写的 Controller 方法(适配不同写法的 Controller)。
  4. Handler/Controller(处理器 / 控制器) 业务核心 我们自己编写:接收参数、调用 Service、处理业务、返回数据 / 视图。
  5. ViewResolver(视图解析器) 找页面工具 把逻辑视图名(如index)转换成真实的页面路径(如/WEB-INF/index.jsp)。
  6. View(视图) 渲染工具把数据填充到页面,返回给浏览器展示。

SpringMVC 完整执行流程

这是 SpringMVC 的工作原理,一步一步通俗讲解:

复制代码
浏览器  →  请求  → DispatcherServlet(总控)
            ↓
1. 总控 询问 HandlerMapping:这个URL对应哪个Controller?
2. 映射器 返回 对应Controller的方法
            ↓
3. 总控 命令 HandlerAdapter:去执行这个方法!
4. 适配器 调用 我们写的Controller(处理业务)
5. Controller 返回 ModelAndView(数据 + 视图名)给适配器
            ↓
6. 适配器 把结果还给 总控
            ↓
7. 总控 交给 ViewResolver:解析视图名,找到真实页面
8. 总控 交给 View:把数据渲染到页面上
            ↓
9. 渲染后的页面 → 响应给浏览器

一句话总结DispatcherServlet 统一调度,映射器找方法,适配器执行业务,解析器找页面,视图渲染结果

体验:

注解类:

复制代码
@Configuration
@ComponentScan("com.atguigu.controller")
public class MvcConfig {
 
    @Bean
    public RequestMappingHandlerMapping handlerMapping(){
        return new RequestMappingHandlerMapping();
    }
    
    @Bean
    public RequestMappingHandlerAdapter handlerAdapter(){
        return new RequestMappingHandlerAdapter();
    }
    

}

public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{MvcConfig.class};//在这里面写要加载的配置文件,因为这个方法的父类的父类已经创建了ioc容器,所以这里直接写要加载的配置文件就可以了
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

controller层:

复制代码
@Controller
public class HelloController {
    @RequestMapping("springmvc/hello")//对外访问的地址 到handlerMapping注册的解析
    @ResponseBody//直接返回字符串给前端,不要找视图解析器
    public String hello(){
        System.out.println("hello");
        return "springmvc/hello";
    }


}

路径设置注解:

@RequestMapping

pringMVC 中设置请求路径的核心注解只有两个体系:

  1. 通用注解@RequestMapping(最基础、功能最全)
  2. 简化注解@GetMapping/@PostMapping/@PutMapping/@DeleteMapping/@PatchMapping(专用、语义化)

作用:将浏览器的 URL 请求,绑定到 Controller 的类 / 方法上,是 Web 开发的「入口注解」,必须彻底吃透!


一、核心总览

|-------------------|-------------------|---------------------|
| 注解 | 作用 | 适用场景 |
| @RequestMapping | 通用路径映射,支持所有请求方法 | 类上定义统一前缀、需要灵活配置请求方式 |
| @GetMapping | 仅绑定 GET 请求 | 查询数据、页面跳转 |
| @PostMapping | 仅绑定 POST 请求 | 提交表单、新增数据 |
| @PutMapping | 仅绑定 PUT 请求 | 全量修改数据 |
| @DeleteMapping | 仅绑定 DELETE 请求 | 删除数据 |
| @PatchMapping | 仅绑定 PATCH 请求 | 局部修改数据 |


二、基础用法(最常用)

1. 注解位置:类 + 方法 组合使用

  • 类上 :定义统一路径前缀(模块化、避免重复)

  • 方法上 :定义具体接口路径

    @Controller
    // 类前缀:所有方法路径都自动拼接 /user
    @RequestMapping("/user")
    public class UserController {

    复制代码
      // 最终访问路径:/user/list
      @RequestMapping("/list")
      public String userList() {
          return "userList";
      }
    
      // 最终访问路径:/user/add
      @RequestMapping("/add")
      public String addUser() {
          return "addUser";
      }

    }


三、@RequestMapping 全属性详解

@RequestMapping万能注解,支持 6 个核心属性,精准控制请求匹配规则:

1. value / path(路径,等价)

  • 唯一必写属性,指定请求 URL

  • 支持字符串数组:一个方法绑定多个路径

    // 访问 /test1 或 /test2 都能执行该方法
    @RequestMapping(value = {"/test1", "/test2"})
    public void test() {}

2. method(限制请求方法)

指定仅允许的 HTTP 请求方式(GET/POST/PUT/DELETE)

复制代码
// 仅允许 POST 请求访问
@RequestMapping(value = "/save", method = RequestMethod.POST)
public void save() {}

3. params(限制请求参数)

要求请求必须携带 / 不携带指定参数,否则 404 报错

复制代码
// 必须携带 id 参数
@RequestMapping(value = "/get", params = "id")
// 必须携带 id=1 参数
@RequestMapping(value = "/get", params = "id=1")
// 不能携带 name 参数
@RequestMapping(value = "/get", params = "!name")

4. headers(限制请求头)

要求请求头必须满足指定条件(常用于接口鉴权、格式限制)

复制代码
// 请求头必须包含 Content-Type=application/json
@RequestMapping(value = "/json", headers = "Content-Type=application/json")

5. consumes(限制请求数据类型)

指定接收的请求体格式(前端传参格式)

复制代码
// 仅接收 JSON 格式请求
@RequestMapping(value = "/add", consumes = "application/json")

6. produces(限制响应数据类型)

指定返回给前端的数据格式

复制代码
// 返回 JSON 格式数据
@RequestMapping(value = "/get", produces = "application/json;charset=utf-8")

简化版注解

Spring 4.3 推出专用请求注解 ,替代 @RequestMapping(method=xxx),代码更简洁、可读性更高:

等价关系

复制代码
// 原始写法
@RequestMapping(value = "/list", method = RequestMethod.GET)

// 简化写法(完全等价)
@GetMapping("/list")

完整示例(RESTful 标准接口)

复制代码
@RestController
@RequestMapping("/user")
public class UserController {
    // 查询:GET
    @GetMapping("/{id}")
    public User getById(@PathVariable Integer id) {}

    // 新增:POST
    @PostMapping
    public void add(@RequestBody User user) {}

    // 修改:PUT
    @PutMapping("/{id}")
    public void update(@PathVariable Integer id, @RequestBody User user) {}

    // 删除:DELETE
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Integer id) {}
}

Ant 风格通配符路径

支持 3 种通配符,适配模糊路径,非常实用:

|---------|------------------|------------|---------------|-------------|
| 通配符 | 含义 | 示例 | 匹配 | 不匹配 |
| ? | 匹配单个字符 | /user/? | /user/1 | /user/10 |
| * | 匹配任意字符(单层路径) | /user/* | /user/list | /user/a/b |
| ** | 匹配任意多层路径 | /user/** | /user/a/b/c | 无 |

复制代码
// 匹配 /user/info、/user/abc、/user/123
@GetMapping("/user/*")

// 匹配 /user/list、/user/a/list、/user/a/b/list
@GetMapping("/user/**/list")

RESTful 路径变量

配合 {变量名} 定义动态路径 ,用 @PathVariable 绑定参数:

1. 基础用法

复制代码
// 路径:/user/100 → id=100
@GetMapping("/user/{id}")
public User getById(@PathVariable Integer id) {
    return userService.getById(id);
}

2. 多个路径变量

复制代码
// 路径:/user/100/order/200 → userId=100, orderId=200
@GetMapping("/user/{userId}/order/{orderId}")
public Order getOrder(@PathVariable Integer userId, @PathVariable Integer orderId) {}

3. 路径变量别名

复制代码
// 路径变量名和参数名不一致时
@GetMapping("/user/{uid}")
public User getById(@PathVariable("uid") Integer id) {}

路径匹配优先级

当多个路径匹配同一个请求时,SpringMVC 按精确优先规则匹配:

  1. 精确匹配 > 通配符匹配
  2. 通配符优先级:? > * > **

示例:

  • 请求 /user/1
  • 匹配顺序:/user/1(精确)> /user/? > /user/* > /user/**

关键注意事项

1. 斜杠 / 可加可不加

Spring 自动处理,以下写法完全等价:

复制代码
@RequestMapping("user")
@RequestMapping("/user")

2. 禁止重复路径

同一个项目中,相同路径 + 相同请求方法 会直接启动报错!

3. 类上注解不写 method

类上仅定义前缀,不要写 method,否则所有方法都会被限制请求方式。

4. 静态资源不冲突

路径注解仅拦截 Controller 请求,静态资源(css/js/img)需单独配置放行。'

区别param和json:

@RequestParam (普通 Param 参数) VS JSON (@RequestBody)

核心一句话先记住:Param 是键值对表单参数;JSON 是请求体结构化对象参数,靠请求头 Content-Type****区分。

分水岭:Content-Type(

1. Param 参数(@RequestParam)

前端请求头固定:

复制代码
Content-Type: application/x-www-form-urlencoded

这是浏览器表单默认格式

2. JSON 参数(@RequestBody)

前端请求头必须手动设置:

复制代码
Content-Type: application/json

前后端分离、Vue/React 项目专用。

详细对比

|------------|------------------------------|-------------------|
| 对比维度 | Param 键值对参数 | JSON 对象参数 |
| 传参位置 | URL 地址后 / 表单请求体 | 纯请求 Body 内部 |
| 后端注解 | @RequestParam | @RequestBody |
| 数据格式 | key=value&key2=value2 扁平键值 | {json键值对象} 结构化 |
| 复杂嵌套 | 不支持嵌套对象 | 完美支持多级嵌套、数组 |
| GET 请求 | 完全支持 | GET 无请求体,禁止使用 |
| 编码处理 | 自动 URL 编码转义 | 原生 JSON 格式,不自动编码 |

Param 参数 完整演示

前端传参形式

方式 1:URL 拼接

复制代码
http://localhost/user/login?username=zhangsan&password=123

方式 2:form 表单提交(默认格式)

后端接收写法

复制代码
// 简单参数接收
@PostMapping("/login")
public String login(
    @RequestParam String username,
    @RequestParam String password
){
    System.out.println(username + password);
    return "success";
}

// 也可以直接封装简单实体类(扁平属性)
@PostMapping("/login")
public String login(User user){}

特点:属性必须扁平,不能嵌套复杂对象

四、2. JSON 参数 完整演示

前端传参形式(Vue/Axios)

请求头:Content-Type: application/json请求体 raw JSON:

复制代码
{
  "username":"zhangsan",
  "password":"123",
  "address":{
    "city":"杭州"
  }
}

后端接收写法

复制代码
@PostMapping("/login")
// 必须加 @RequestBody
public String login(@RequestBody User user){
    System.out.println(user.getUsername());
    return "success";
}

特点:支持嵌套对象、数组、复杂结构,前后端分离标配。

五、高频易错坑

坑 1:GET 请求不能用 @RequestBody

HTTP 规范:GET 没有请求体 GET 只能用:@RequestParam GET 写 @RequestBody 直接报错

坑 2:注解不能混用

  • 表单 param:不能加@RequestBody
  • JSON 请求:必须加@RequestBody,不加接收不到数据

坑 3:JSON 必须严格匹配字段名

JSON 键名 和 Java 实体类属性名 大小写完全一致,否则为 null;Param 参数匹配宽松,只要 key 同名即可。

坑 4:文件上传不属于这两类

文件上传 Content-Type 是 multipart/form-data,单独用MultipartFile接收。

param参数接收参数:

最基础:单个基本参数接收

1. 无注解直接接收

参数名 = 请求的 key 名,自动匹配赋值

复制代码
@GetMapping("/test1")
public String test1(String username, Integer age) {
    System.out.println(username); // 接收 ?username=张三
    System.out.println(age);      // 接收 ?age=20
    return "success";
}

✅ 前端传参:http://localhost:8080/test1?username=张三&age=20

2. 带 @RequestParam 注解

手动绑定参数,可控性更强

复制代码
@PostMapping("/test2")
public String test2(
    @RequestParam String username,
    @RequestParam Integer age
) {
    return "success";
}

二、@RequestParam 三大核心属性

解决参数名不一致、必传、默认值问题

复制代码
@RequestParam(
    value = "name",    // 前端传的 key 名
    required = true,   // 是否必传(默认 true,不传报错 400)
    defaultValue = "游客" // 不传时的默认值
)

实战示例

复制代码
@GetMapping("/user")
public String getUser(
    // 前端传 name,后端用 username 接收
    @RequestParam(value = "name") String username,
    // 非必传,默认 18
    @RequestParam(required = false, defaultValue = "18") Integer age
) {
    return "success";
}

前端传参:/user?name=张三 → age 自动 = 18

三、进阶:数组 / 集合参数接收

1. 数组接收

前端传同名多个参数

复制代码
@GetMapping("/hobby")
public String hobby(@RequestParam String[] hobby) {
    // 接收 ?hobby=篮球&hobby=足球&hobby=游戏
    return "success";
}

2. List 集合接收(必须加 @RequestParam)

不加注解会报错! Spring 无法直接封装 List

复制代码
@GetMapping("/hobbyList")
public String hobbyList(@RequestParam List<String> hobby) {
    return "success";
}

四、最常用:POJO 实体类自动封装

前端传多个参数,Spring 自动封装成 Java 对象,不用一个个接收!

1. 实体类

复制代码
public class User {
    private String username;
    private Integer age;
    // getter/setter
}

2. 后端接收(零注解,直接写实体类

复制代码
@PostMapping("/addUser")
public String addUser(User user) { // 自动封装所有参数
    System.out.println(user.getUsername());
    System.out.println(user.getAge());
    return "success";
}

前端传参:?username=张三&age=20 → 自动封装到 User 对象

五、高级:嵌套 POJO 接收

Param 也支持嵌套对象 ,前端传参格式:对象.属性

1. 嵌套实体

复制代码
public class User {
    private String username;
    private Address address; // 嵌套对象
}
public class Address {
    private String city;
}

2. 后端接收

复制代码
@PostMapping("/addUserAddr")
public String addUserAddr(User user) {
    System.out.println(user.getAddress().getCity());
    return "success";
}

前端传参:?username=张三&address.city=北京

关键区别:不加注解 vs 加 @RequestParam

|---------------------------------|----------|---------------|---------------|
| 写法 | 自动匹配 | 参数必传 | 参数名不匹配 |
| String username | ✅ 是 | ❌ 非必传(为 null) | ❌ 无法接收 |
| @RequestParam String username | ✅ 是 | ✅ 必传(默认) | ✅ 可用 value 指定 |

总结

  • 简单参数、非必传 → 不加注解
  • 必传、改名、默认值 → 必须加 @RequestParam

高频避坑

  1. GET/POST 都能用 ParamGET 放 URL 后,POST 放请求体,格式完全一样。
  2. Param 不能接收 JSON! JSON 必须用 @RequestBody,Param 只认 key=value。
  3. 基本类型不能为 null int age 必传,否则报错;用 Integer age 可空。
  4. 中文乱码问题POST 请求中文乱码 → 配置 Spring 编码过滤器。
  5. List 必须加 @RequestParam数组不用,List 必须加!

路径传参:

先分清:路径参数 和 普通 Param 参数

1. 普通 Param 参数

地址:/user?**id=100&name=张三**特点:问号拼接,键值对,用@RequestParam接收

2. 路径参数(REST 专用)

地址:/user/**100/张三**特点:直接嵌在 URL 路径里,无问号 ,用{变量名}占位 + @PathVariable接收核心注解:@PathVariable

二、最基础:单个路径参数接收

1. 写法模板

  1. 映射路径写占位符:/{参数名}
  2. 形参添加:@PathVariable

2. 完整代码示例

访问地址:http://localhost/user/20

复制代码
@Controller
@RequestMapping("/user")
public class UserController {

    // {id} 是路径占位符
    @GetMapping("/{id}")
    public String getUser(
        // 绑定路径里的 id
        @PathVariable Integer id
    ){
        System.out.println("路径参数id:" + id); // 输出20
        return "success";
    }
}

规则:占位符名字 和 形参名字一致,直接绑定

三、变量名不一致:别名绑定

路径占位名 和 Java 参数名不一样时,手动指定映射:访问:/user/105

复制代码
// 路径占位:uid
@GetMapping("/{uid}")
public String getById(
    // 绑定 uid 给 id变量
    @PathVariable("uid") Integer id
){
    System.out.println(id); //105
    return "success";
}

四、多个路径参数

路径里可以放多个{}占位符:访问地址:/order/10/2026

复制代码
@GetMapping("/order/{userId}/{year}")
public String getOrder(
    @PathVariable Integer userId,
    @PathVariable Integer year
){
    System.out.println(userId + " " + year);
    return "success";
}

五、@PathVariable 三个核心属性

复制代码
@PathVariable(
    value = "uid",       // 绑定路径占位名
    required = true,     // 是否必填(默认true,不填404)
    name = "uid"         // 和value完全等价
)

示例(非必填):

复制代码
@GetMapping("/info/{name}")
public String info(
    @PathVariable(required = false) String name
){
    return "success";
}

六、进阶:正则限制路径参数格式

防止非法参数,给占位符加正则约束:语法:{变量名:正则表达式}

复制代码
// id必须是纯数字
@GetMapping("/detail/{id:\\d+}")
public String detail(@PathVariable Integer id){
    return "success";
}
  • 访问 /detail/99 ✅ 正常匹配
  • 访问 /detail/abc ❌ 404 匹配失败

常用正则:

  • \\d+:只能数字
  • [a-zA-Z0-9]+:字母 + 数字

七、路径参数直接封装实体类

SpringMVC 自动把路径参数注入 POJO 属性:实体类:

复制代码
public class User {
    private Integer id;
    private String username;
    // get/set
}

接口:访问:/user/88/lisi

复制代码
@GetMapping("/user/{id}/{username}")
public String getUser(User user){
    System.out.println(user.getId()); //88
    System.out.println(user.getUsername()); //lisi
    return "success";
}

不用逐个注解,自动匹配属性名!

高频避坑

坑 1:GET/POST 都能用路径参数

REST 风格里:

  • 查询 GET + 路径参数
  • 删除 DELETE + 路径参数完全通用

坑 2:路径参数不能省略(默认必填)

required=true,少一段路径直接 404

坑 3:不要和普通 Param 搞混

  • /user?name=xxx@RequestParam
  • /user/xxx@PathVariable

坑 4:中文路径参数乱码

Tomcat 默认编码问题,配置server.xml URIEncoding="UTF-8" 解决

坑 5:不能搭配 @RequestBody

路径参数是 URL 里的,JSON 请求体才用@RequestBody,两者互不干扰,可以共存但不要混用理解

对比

|-------------|--------------|-----------------|----------------------|
| 类型 | URL 样式 | 注解 | 使用场景 |
| 普通 Param 参数 | /user?id=1 | @RequestParam | 传统表单、查询筛选 |
| 路径参数 | /user/1 | @PathVariable | RESTful 接口、主键查询 / 删除 |

json传参:

核心定调

JSON 传参 = 前端传 JSON 格式字符串 → 放在 HTTP 请求体中 → 后端用 @RequestBody****接收 ✅ 专用场景:Vue/React/ 小程序等前后端分离项目✅ 唯一限制:GET 请求不能用(HTTP 规范中 GET 无请求体)

二、JSON 传参 3 个核心前提

  1. 传参位置 :HTTP 请求体(Body) 中,不在 URL、不在表单

  2. 请求头:必须设置

    Content-Type: application/json; charset=utf-8

  3. 后端注解@RequestBody(SpringMVC 接收 JSON 的唯一注解)

三、环境依赖(零配置)

  • 纯 SpringMVC :自动依赖 jackson-databind(JSON 转换工具)
  • SpringBoot :引入 spring-boot-starter-web完全自动配置,不用管任何配置

四、基础用法(4 种最常用场景)

场景 1:接收普通实体对象(开发 90% 的用法)

前端传参(JSON 格式)

json

复制代码
{
  "username": "张三",
  "age": 20,
  "email": "123@qq.com"
}
后端代码
  1. 实体类

    public class User {
    // JSON键名 必须 = 实体类属性名(大小写一致)
    private String username;
    private Integer age;
    private String email;
    // getter/setter/toString
    }

  2. Controller

    @RestController
    @RequestMapping("/user")
    public class UserController {
    /**
    * @RequestBody 作用:
    * 1. 读取请求体中的JSON字符串
    * 2. 自动转换为Java User对象
    */
    @PostMapping("/add")
    public String addUser(@RequestBody User user) {
    System.out.println(user);
    return "新增成功";
    }
    }


场景 2:接收 Map 集合(无需建实体类,灵活)

适合临时接口、参数不固定的场景

复制代码
@PostMapping("/test")
public String testMap(@RequestBody Map<String, Object> map) {
    System.out.println(map.get("username"));
    System.out.println(map.get("age"));
    return "测试成功";
}

场景 3:接收数组 / List 集合(批量数据)

前端传 JSON 数组
复制代码
[1,2,3,4,5]
后端接收
复制代码
@PostMapping("/batch")
public String batchDelete(@RequestBody List<Integer> ids) {
    System.out.println(ids); // [1,2,3,4,5]
    return "批量删除成功";
}

场景 4:接收嵌套 JSON 对象(复杂数据)

前端嵌套 JSON
复制代码
{
  "username": "张三",
  "address": {
    "city": "北京",
    "detail": "朝阳区"
  }
}
后端嵌套实体
复制代码
// 地址实体
public class Address {
    private String city;
    private String detail;
}
// 用户实体
public class User {
    private String username;
    private Address address; // 嵌套对象
}

// 直接接收,自动封装嵌套数据
@PostMapping("/save")
public String save(@RequestBody User user) {
    return user.getAddress().getCity(); // 北京
}

高级用法:混合传参(JSON + 路径参数)

RESTful 接口最常用组合:路径参数定位资源,JSON 传修改数据

复制代码
@PutMapping("/user/{id}")
public String update(
    // 路径参数:定位用户
    @PathVariable Integer id,
    // JSON参数:用户新数据
    @RequestBody User user
) {
    System.out.println("修改用户id:" + id);
    System.out.println("新数据:" + user);
    return "修改成功";
}

@RequestBody 核心规则(避坑关键)

  1. 必填性 默认 required = true,前端必须传 JSON 请求体 ,否则报 400 错误;非必填:@RequestBody(required = false)
  2. 唯一限制 一个 Controller 方法最多只能有 1 个 @RequestBody(请求体只有一个)
  3. 自动转换 框架通过 消息转换器 自动完成:JSON字符串 ↔ Java对象
  4. 字段匹配 JSON 键名 ≠ Java 属性名 → 赋值为null(必须严格一致)

踩坑

坑 1:GET 请求用 @RequestBody → 直接报错

@GetMapping + @RequestBody

正确:JSON 传参只能用 POST/PUT/PATCH/DELETE

坑 2:忘记加 @RequestBody → 接收不到数据

前端传 JSON,后端不加注解,所有属性都是null

坑 3:前端请求头错误

前端没设置 Content-Type: application/json,后端无法解析 JSON

坑 4:字段名大小写 / 拼写错误

JSON 写 userName,后端写 username → 接收为 null

坑 5:直接用基本类型接收

❌ 错误:@RequestBody String username✅ 正确:基本类型用Param / 路径参数 ,JSON 用对象 / Map / 集合

八、对比

|-------------|-----------------|------------------|----------|----------|----------------|
| 传参类型 | URL 样式 | 核心注解 | 传参位置 | 支持请求 | 适用场景 |
| 普通 Param | /user?name=张三 | @RequestParam | URL / 表单 | GET/POST | 简单参数、表单 |
| 路径参数 | /user/100 | @PathVariable | URL 路径 | 全部 | RESTful 定位资源 |
| JSON 传参 | /user | @RequestBody | 请求体 | POST/PUT | 前后端分离、复杂对象 |

九、总结

  1. JSON 传参靠请求体 ,必须配 application/json 请求头;
  2. 后端唯一注解 @RequestBody,自动转 Java 对象;
  3. 支持对象、嵌套、集合、Map,复杂数据首选;
  4. GET 不能用,一个方法只能用一个;
  5. 和 Param、路径参数可以混合使用,互不冲突。

@EnableWebMvc 内部通过 @Import 导入了:WebMvcConfigurationSupport这个类会自动帮你创建 SpringMVC 所有核心组件

  • Handler 映射器、适配器
  • JSON 消息转换器(Jackson)👉支持@RequestBody
  • 日期格式化器
  • 参数校验器
  • 默认视图规则
  • 基础 MVC 适配全套配置

三、什么时候必须加?

场景 1:纯 SSM 无 XML 全注解开发

复制代码
@Configuration
@ComponentScan("com.controller")
@EnableWebMvc   // 必加!!
public class SpringMvcConfig implements WebMvcConfigurer{
    // 自定义视图解析器、拦截器...
}

不加后果:

  • @RequestMapping 失效
  • @RequestBody JSON 无法解析
  • 参数绑定、格式化全部失效整个 MVC 瘫痪。

四、它自动帮你开启的关键能力

  1. 自动注册 Jackson 转换器 → 支持 JSON @RequestBody
  2. 自动参数绑定 → 普通 Param 自动封装
  3. 日期转换器、格式校验自动生效
  4. 支持 REST 风格路径参数
  5. 开启拦截器、视图解析扩展能力

五、最最重要:SpringBoot 里千万不要乱加!!!

1. SpringBoot 默认自带 MVC 自动配置

WebMvcAutoConfiguration已经帮你自动开启了所有 MVC 功能 ,不用手写 @EnableWebMvc

2. 一旦你在 SpringBoot 加了 @EnableWebMvc

后果:

  1. 覆盖 Boot 自带自动配置
  2. 丢失默认 Jackson 全局配置
  3. 丢失日期自动格式化
  4. 静态资源默认放行失效
  5. JSON 乱码、时间格式报错、页面 404 全来

接收请求头和Cookie:

两个专属注解,和你之前学的 @RequestParam / @PathVariable 用法高度相似,一套逻辑直接吃透:

  • 接收请求头:@RequestHeader
  • 接收 Cookie:@CookieValue

一、通用前置:两个注解共享 3 个属性(一模一样)

复制代码
@RequestHeader(
    value = "头名称",       // 指定要获取的Header键名
    required = true,       // 是否必传,默认true(不传400报错)
    defaultValue = "默认值"// 无数据时兜底默认值
)

@CookieValue(属性完全同上)

@RequestParam语法完全一致,支持默认值 (这点和@PathVariable不一样)。

第一部分:@RequestHeader 接收请求头

1. 核心作用

获取浏览器 / 前端发过来的 HTTP 请求头信息 常见请求头:User-AgentHostReferertokenContent-Type

2. 基础入门示例

① 获取内置标准请求头

复制代码
@GetMapping("/headerTest")
public String getHeader(
    // 获取浏览器设备信息
    @RequestHeader("User-Agent") String userAgent,
    // 获取访问域名
    @RequestHeader("Host") String host
){
    System.out.println("浏览器信息:" + userAgent);
    System.out.println("访问主机:" + host);
    return "success";
}

② 非必传 + 设置默认值

避免请求头不存在直接报错:

复制代码
@GetMapping("/token")
public String getToken(
    @RequestHeader(value = "token", required = false, defaultValue = "guest-token") String token
){
    System.out.println("令牌:" + token);
    return "success";
}

③ 自定义前端请求头(接口鉴权常用)

前端自定义 Header:Authorization: Bearer 123456abc后端接收:

复制代码
@PostMapping("/login")
public String auth(@RequestHeader("Authorization") String authHeader){
    // 解析token做登录校验
    return "校验通过";
}

3. 小细节

请求头名称 不区分大小写user-agentUser-Agent 等效。

1. 核心作用

读取浏览器自动携带到后台的 Cookie 数据 最常用:JSESSIONID 会话 Cookie、自定义业务 Cookie

2. 基础示例 1:获取系统默认 JSESSIONID

java

运行

复制代码
@GetMapping("/cookie")
public String getSessionCookie(
    @CookieValue("JSESSIONID") String sessionId
){
    System.out.println("会话Cookie:" + sessionId);
    return "success";
}

前端种下 Cookie:username=lisi后端容错接收:

复制代码
@GetMapping("/userCookie")
public String getUserCookie(
    @CookieValue(value = "username", required = false, defaultValue = "匿名用户") String username
){
    System.out.println("Cookie用户名:" + username);
    return "success";
}

4. 常见坑:Cookie 拿不到原因

  1. Cookie 的 Path / 域名 和后台接口不匹配;
  2. 跨域场景没配置允许携带 Cookie;
  3. Cookie 设置了HttpOnly:Java 后端依然能读到,前端 JS 读不到。

第三部分:混合实战

5种传参全部混用

复制代码
@RestController
@RequestMapping("/api/user")
public class AllParamController {

    @PostMapping("/{id}/update")
    public Object allParam(
            // 1.路径参数
            @PathVariable Integer id,
            // 2.普通Param参数
            @RequestParam String phone,
            // 3.JSON请求体
            @RequestBody User user,
            // 4.请求头Token
            @RequestHeader(value = "token",defaultValue = "default123") String token,
            // 5.Cookie会话
            @CookieValue(value = "JSESSIONID",required = false) String jsessionId
    ){
        System.out.println("路径ID:"+id);
        System.out.println("手机号Param:"+phone);
        System.out.println("JSON用户:"+user);
        System.out.println("请求头Token:"+token);
        System.out.println("Cookie会话:"+jsessionId);
        return "全部接收成功";
    }
}

原生对象获取:

SpringMVC 完全兼容 Servlet 原生对象,直接把 HttpServletRequest/HttpServletResponse/HttpSession****写进 Controller 方法形参,框架自动注入,不用自己 new!

一、支持的所有原生对象(直接注入即可)

在 Controller 方法括号里直接写下面任意对象,Spring 自动帮你绑定当前请求:

  1. HttpServletRequest 请求对象(最常用)
  2. HttpServletResponse 响应对象
  3. HttpSession 会话对象
  4. ServletContext 全局上下文对象
  5. Cookie[] Cookie 数组

二、1. HttpServletRequest 请求对象 最全用法

基础注入

复制代码
@GetMapping("/req")
public void getRequest(HttpServletRequest request){
    // 所有原生Servlet写法完全通用
}

① 手动获取普通 Param 参数(替代 @RequestParam)

复制代码
// 等价:@RequestParam String username
String username = request.getParameter("username");
String ageStr = request.getParameter("age");

特点:只能拿key=value 表单 / URL 参数,拿不到 JSON。

② 获取请求头

复制代码
// 获取单个请求头
String userAgent = request.getHeader("User-Agent");

// 获取所有头名称枚举
Enumeration<String> headerNames = request.getHeaderNames();

注解只能拿单个 Cookie,原生可以遍历全部:

复制代码
Cookie[] cookies = request.getCookies();
if(cookies != null){
    for (Cookie cookie : cookies) {
        if("JSESSIONID".equals(cookie.getName())){
            System.out.println("sessionId:" + cookie.getValue());
        }
    }
}

④ 获取请求路径 / URI

复制代码
String uri = request.getRequestURI();
String url = request.getRequestURL().toString();
String method = request.getMethod(); // GET/POST

⑤ 请求域存取值

复制代码
// 存数据到request域
request.setAttribute("msg","原生存入数据");
// 取数据
String msg = (String) request.getAttribute("msg");

⑥ 设置编码(解决 POST 乱码)

复制代码
request.setCharacterEncoding("UTF-8");

三、2. HttpServletResponse 响应对象

基础注入

复制代码
@GetMapping("/resp")
public void responseDemo(HttpServletResponse response) throws IOException{

① 手动输出文本 / 页面内容(不走视图解析)

复制代码
// 设置编码
response.setContentType("text/html;charset=UTF-8");
// 获取输出流
PrintWriter writer = response.getWriter();
writer.write("<h1>原生响应内容</h1>");
writer.flush();
writer.close();

② 原生重定向

复制代码
// 重定向 两次请求
response.sendRedirect("/index.jsp");
复制代码
Cookie cookie = new Cookie("username","zhangsan");
cookie.setMaxAge(60*60); // 有效期1小时
response.addCookie(cookie);

四、3. HttpSession 会话对象

两种获取方式:

方式 1:直接形参注入(最简单推荐)

复制代码
@GetMapping("/session")
public void sessionDemo(HttpSession session){
    // 存值
    session.setAttribute("loginUser","admin");
    // 取值
    String user = (String) session.getAttribute("loginUser");
    // 销毁session
    session.invalidate();
}

方式 2:从 request 获取

复制代码
HttpSession session = request.getSession();

五、4. ServletContext 全局对象(整个项目共享)

复制代码
@GetMapping("/context")
public void contextDemo(ServletContext context){
    // 全局存取值
    context.setAttribute("appName","测试项目");
    // 获取项目根路径
    String path = context.getRealPath("/");
}

也可以从 request 获取:

复制代码
ServletContext context = request.getServletContext();

六、关键对比:注解接收 VS 原生 API 接收

|---------|----------------|--------------------------|
| 场景 | 注解方式(推荐) | 原生 Servlet API |
| 普通参数 | @RequestParam | request.getParameter() |
| 路径参数 | @PathVariable | 无法原生获取 |
| JSON 参数 | @RequestBody | 原生无法解析 JSON |
| 请求头 | @RequestHeader | request.getHeader() |
| Cookie | @CookieValue | request.getCookies () 遍历 |
| 域对象 | Model | request/session 域 |

共享域对象操作:

SpringMVC 只用 3 个核心域:

  1. Request 域(一次请求最小范围,最常用)
  2. Session 域(浏览器会话范围)
  3. Application 域 (ServletContext)(整个项目全局最大范围)
  4. Page 域:仅当前页面,SpringMVC 完全不用,直接忽略

一、域通用操作语法(所有域统一格式)

所有域存 / 取 / 删 方法一模一样:

复制代码
// 存数据
setAttribute("key", 数据);
// 取数据
getAttribute("key");
// 删除数据
removeAttribute("key");

第一部分:Request 域(90% 开发首选)

1. 作用范围

一次请求内有效

  • 转发:有效共享
  • 重定向:失效
  • 请求结束自动销毁

2. 两种操作方式

方式 1:原生 Servlet API 操作

复制代码
@GetMapping("/reqScope")
public String reqScope(HttpServletRequest request){
    // 存
    request.setAttribute("msg","Request域数据");
    // 取
    String msg = (String) request.getAttribute("msg");
    // 删
    request.removeAttribute("msg");

    return "success";
}

方式 2:SpringMVC 封装工具(推荐!更简洁)

Spring 封装了 3 个对象,本质都是操作 Request 域,完全等价Model / ModelMap / ModelAndView

① Model(最常用,极简推荐)

复制代码
@GetMapping("/model")
public String testModel(Model model){
    // 存入Request域
    model.addAttribute("username","张三");
    model.addAttribute("age",20);

    return "success"; // 视图可以直接取域中数据
}

② ModelMap

用法和 Model 完全一致:

复制代码
public String testMap(ModelMap map){
    map.addAttribute("info","测试数据");
    return "success";
}

③ ModelAndView(数据 + 视图绑定一体)

复制代码
@RequestMapping("/mav")
public ModelAndView testMav(){
    // 1. 创建对象 + 设置视图名
    ModelAndView mav = new ModelAndView("success");
    // 2. 存数据到Request域
    mav.addObject("name","李四");
    return mav;
}

✅ 总结:

Model / ModelMap / ModelAndView / request.setAttribute全部都是往 Request 域 放数据,底层完全一样

第二部分:Session 域(会话级别共享)

1. 作用范围

整个浏览器会话有效

  • 打开浏览器 → 访问多个接口 → 关闭浏览器前一直存在
  • 转发、重定向 都有效
  • 不同用户会话隔离

2. 两种操作方式

方式 1:原生 HttpSession 操作

复制代码
@GetMapping("/session")
public String sessionScope(HttpSession session){
    // 存
    session.setAttribute("loginUser","admin");
    // 取
    String user = (String) session.getAttribute("loginUser");
    // 删除单个
    session.removeAttribute("loginUser");
    // 销毁整个会话(退出登录)
    session.invalidate();

    return "success";
}

方式 2:Spring 专属注解 @SessionAttributes

作用:把 Model 中的数据 自动同步到 Session 域

使用步骤

  1. 类上加注解

    @Controller
    @SessionAttributes({"username","age"}) // 指定key存入session
    public class ScopeController {

    复制代码
     @GetMapping("/setSession")
     public String setData(Model model){
         // 先存入Model(Request域)
         model.addAttribute("username","王五");
         // 自动同步到Session域
         return "success";
     }

    }

⚠️ 致命坑点(必记)

  1. 只能同步 Model 里已有的 key,不能直接存 session

  2. 清除不能 remove,必须用 SessionStatus

    @GetMapping("/clear")
    public String clear(SessionStatus status){
    status.setComplete(); // 清除@SessionAttributes存的所有数据
    return "redirect:/";
    }


第三部分:Application 全局域(ServletContext)

1. 作用范围

整个项目全局共享,服务器启动存在,服务器关闭销毁

  • 所有用户、所有会话共享同一份数据
  • 慎用:并发多易线程安全问题

2. 原生操作

复制代码
@GetMapping("/context")
public String appScope(ServletContext context){
    // 全局存
    context.setAttribute("projectName","SpringMVC学习");
    // 全局取
    String name = (String) context.getAttribute("projectName");

    return "success";
}

也可以从 request 获取:

复制代码
ServletContext context = request.getServletContext();

第四部分:转发 & 重定向 域数据存活规则

1. 转发 forward

1 次请求:✅ Request 域:保留共享✅ Session 域:保留✅ Application 域:保留

2. 重定向 redirect

2 次新请求:❌ Request 域:全部丢失✅ Session 域:保留✅ Application 域:保留


第五部分:三大域完整对比表

|---------------|-----------|--------------|--------|---------|-------------|
| 域对象 | 作用范围 | 存活时长 | 转发 | 重定向 | 使用场景 |
| Request 域 | 单次请求 | 请求结束销毁 | ✅有效 | ❌失效 | 页面临时传值、视图渲染 |
| Session 域 | 单个用户浏览器会话 | 浏览器关闭 / 过期销毁 | ✅有效 | ✅有效 | 登录用户信息、购物车 |
| Application 域 | 整个项目所有用户 | 服务器启停 | ✅有效 | ✅有效 | 全局配置、项目常量 |

Spring响应式数据:

快速返回逻辑视图:

步骤:

1.先导依赖:

<!-- jsp需要依赖! jstl-->

<dependency>

<groupId>jakarta.servlet.jsp.jstl</groupId>

<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>

<version>3.0.0</version>

</dependency>

jsp页面创造:

建议创建在WEB-INF下,避免外部直接访问

复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
        <h1>${data}</h1>
</body>
</html>

${}这个里面写的就是在controller层里写的要加载的名字

配置jsp视图解析器:

复制代码
@Configuration
@ComponentScan("com.atguigu.jsp")
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    private static final Log log = LogFactory.getLog(MvcConfig.class);
    //视图解析器,指定前后缀
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        //registry可以快速添加前后缀
        registry.jsp("/WEB-INF/views/", ".jsp");//这里面可以快速指定前后缀,只要前后缀等于目标视图的完整路径就可以


    }

}

@Configuration

@ComponentScan("com.atguigu.jsp")

@EnableWebMvc

写视图解析器的这个类要实现WebMvcConfigurer这个接口,

放到ioc容器里去,并设置拦截的请求:

复制代码
public class SpringMVCInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{MvcConfig.class};//把配置文件加载到在ioc容器中
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};//设置成拦截所有请求
    }
}

返回视图:

复制代码
@Controller
@RequestMapping("index")
public class JspController {
    @GetMapping("jsp")
    public String index(HttpServletRequest request) {
        request.setAttribute("data","hello jsp!!!");
        System.out.println("JspController.index");
        return "index";
    }
}

最后那个return要写的是jsp那个文件的名字:

转发和重定向:

在 Spring MVC 中,Handler 方法返回值来实现快速转发,可以使用 redirect 或者 forward 关键字来实现重定向。

复制代码
@RequestMapping("/redirect-demo")
public String redirectDemo() {
    // 重定向到 /demo 路径 
    return "redirect:/demo";
}

@RequestMapping("/forward-demo")
public String forwardDemo() {
    // 转发到 /demo 路径
    return "forward:/demo";
}

//注意: 转发和重定向到项目下资源路径都是相同,都不需要添加项目根路径!填写项目下路径即可!

总结:

  • 将方法的返回值,设置String类型
  • 转发使用forward关键字,重定向使用redirect关键字
  • 关键字: /路径
  • 注意:如果是项目下的资源,转发和重定向都一样都是项目下路径!都不需要添加项目根路径!

|-----------------------------|---------|-----|------|
| 写法 | 含义 | 地址栏 | 数据共享 |
| return "forward:/success" | 服务器内部转发 | 不变 | 共享 |
| return "redirect:/login" | 客户端重定向 | 改变 | 不共享 |

返回json数据:

前置准备:

导入依赖和添加json数据转换器:

导入jackson依赖

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

添加json数据转化器

@EnableWebMvc

复制代码
//TODO: SpringMVC对应组件的配置类 [声明SpringMVC需要的组件信息]

//TODO: 导入handlerMapping和handlerAdapter的三种方式
 //1.自动导入handlerMapping和handlerAdapter [推荐]
 //2.可以不添加,springmvc会检查是否配置handlerMapping和handlerAdapter,没有配置默认加载
 //3.使用@Bean方式配置handlerMapper和handlerAdapter
@EnableWebMvc  //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller") //TODO: 进行controller扫描

//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {


}

然后在类上加注解:

|-------------------------------------|---------|------------------------------------------------------|
| 注解 | 位置 | 作用 |
| @ResponseBody @Controller(这两个一起用) | 方法 / 类上 | 单独使用:标记方法返回值直接写入响应体,自动转为 JSON |
| @RestController | 类上 | 组合注解 = @Controller + @ResponseBody开发首选 |

复制代码
@ResponseBody
@Controller
//或者直接加@RestController
@RequestMapping("json")
public class JsonController {
    @GetMapping("data")
    public User data(){
        User user = new User();
        user.setAge(18);
        user.setName("妄竹");
        return user;//直接返回user,然后加一个@ResponseBody,这样就会直接返回一个json串
    }
    @GetMapping("data2")
    public List<User> data1(){
        User user = new User();
        user.setAge(18);
        user.setName("妄竹安");
        List<User> list = new ArrayList<>();
        list.add(user);
        return list;
    }
}

静态资源处理:

很简单就是开启寻找静态资源的开关:

在MvcConfig文件中:

复制代码
//开启静态资源查找
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

这个方法里面就是写了一个转发

RESTFul风格接口设置:

ESTful 的优势

万物皆资源 (用户、订单、商品都是资源),用名词 定义资源,用HTTP 方法表示操作:

复制代码
查询用户:GET    /users/1
新增用户:POST   /users
修改用户:PUT    /users/1
删除用户:DELETE /users/1

优点:见 URL 知含义、统一标准、前后端协作更高效。

核心三要素

  1. Resource(资源) :所有数据都是资源(用户、订单、图片),用名词复数 表示(/users/orders);
  2. URL(资源地址) :定位资源的唯一标识,无动词、无后缀
  3. HTTP Method(操作方式):用固定方法表示增删改查,不自定义操作名。

举例:

复制代码
@RestController
@RequestMapping("user")
public class UserController {
    @GetMapping
    public List<User> page(@RequestParam(required = false,defaultValue = "1") int page,@RequestParam(required = false,defaultValue = "10") int size){
        System.out.println("page:"+page + "size:"+size);
        return null;
    }
    @PostMapping
    public User save(@RequestBody User user){
        return user;
    }

    @GetMapping("{id}")
    public User detail(@PathVariable Integer id){
        return null;
    }


    @PutMapping
    public User updata(@RequestBody User user){
        return user;
    }

    @DeleteMapping("{id}")
    public User delete(@PathVariable Integer id){
        return null;
    }

    @GetMapping("seach")
    public List<User> seach(String keywork,
                            @RequestParam(required = false,defaultValue = "1") int page,
                            @RequestParam(required = false,defaultValue = "10") int size){
        return null;
    }

}

全局异常处理:

第一步:先定义一个全局异常处理类

第二步:在这个全局异常处理类中声明处理方法

复制代码
@ControllerAdvice//该注解的意思是:全局异常发生了,就会走此类的handler
@RestControllerAdvice  //这个注解的意思就是加了:@ControllerAdvice和@ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(ArithmeticException.class)//这个异常就是标识专门处理哪种异常,括号里写的就是要处理的异常
    public Object ArithmeticExceptionHandler(ArithmeticException e) {
            //自定义处理异常即可
        return null;
    }

    @ExceptionHandler(Exception.class)
    public Object ExceptionHandler(Exception e){
        String msg= e.getMessage();
        System.out.println(msg);
        return msg;
    }

}

拦截器的概念和基本使用:

拦截器的作用和javaweb的filter一模一样,只是它实在springmvc环境下使用的

创建一个拦截器:

复制代码
public class Myinterceptor implements HandlerInterceptor {

    //在执行handler前,调用的拦截器方法
    //编码格式处理,登录保护,权限处理

    /**
     * @param request   请求对象
     * @param response  响应对象
     * @param handler   handler就是我们要调用的方法对象
     * @return       true  放行   false  拦截
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            return true;

    }


    /**  当handler执行完毕后,就会触发的方法,此时已经没有拦截的机制了,而且此方法只有preHandler返回值是true时,才会触发
     *     对结果进行处理,敏感词汇检查
     * @param request  请求
     * @param response  响应
     * @param handler   handler方法
     * @param modelAndView  返回的视图和共享数据的对象
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Myinterceptor postHandle");
    }

    /** 整体处理完毕之后,才会触发的方法
     *
     * @param request
     * @param response
     * @param handler
     * @param ex        handler报错之后的异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Myinterceptor afterCompletion");
    }
}

把它注入到SpringMvc框架中去拦截请求

复制代码
@Configuration
@ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.error"})
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    private static final Log log = LogFactory.getLog(MvcConfig.class);

//    视图解析器,指定前后缀
//    @Override
//    public void configureViewResolvers(ViewResolverRegistry registry) {
//        //registry可以快速添加前后缀
//        registry.jsp("/WEB-INF/views/", ".jsp");//这里面可以快速指定前后缀,只要前后缀等于目标视图的完整路径就可以
//
//
//    }

    //开启静态资源查找
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();

    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置方案1:把这个拦截器注册到SpringMvc框架中去拦截请求,拦截全部请求
        registry.addInterceptor(new Myinterceptor());
    }
}

另外两种配置方案:

复制代码
//配置方案2:指定地址拦截  .addPathPatterns("/*/**")
// * 任意一层字符串   ** 任意多层字符串
registry.addInterceptor(new Myinterceptor()).addPathPatterns("/user/**");


//配置方案3:排除拦截     排除的地址应该在拦截地址内部
registry.addInterceptor(new Myinterceptor()).addPathPatterns("/user/**").excludePathPatterns("/user/data");

多个拦截器

1.拦截器的执行顺序由注册顺序决定:

  • preHandle正序执行(先注册先执行)
  • postHandle逆序执行(后注册先执行)
  • afterCompletion逆序执行(后注册先执行)

2. 正常流程(所有 preHandle 返回 true)

假设有 3 个拦截器:Interceptor1 → Interceptor2 → Interceptor3(注册顺序)

plaintext

复制代码
1→preHandle → 2→preHandle → 3→preHandle 
→ Controller执行 
→ 3→postHandle → 2→postHandle → 1→postHandle 
→ 视图渲染 
→ 3→afterCompletion → 2→afterCompletion → 1→afterCompletion

3. 中断流程(某个 preHandle 返回 false)

如果 Interceptor2preHandle 返回 false

plaintext

复制代码
1→preHandle(放行)→ 2→preHandle(拦截)
→ 直接执行 1→afterCompletion
→ 请求结束

✅ 结论:只有返回 true 的拦截器,才会执行 afterCompletion

参数校验注解:

举例:

实体类:

复制代码
public class User {
    //@Notnull 表示包装类不为空
    //@NotBlank 表示集合不为空


    @NotNull//这个注解表示,字符串不为空
    private String name;
    @Length(min = 6)
    private String password;
    @Min(1)
    private int age;
    @Email
    private String email;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

/**  步骤一:实体类属性添加校验注解
 * 步骤二:handler方法里 要再加一个@Validated注解
 * 步骤 : param | json 校验注解都有效果
 *              如果是json参数,还需要再加一个@RequestBody
 *
 * 捕捉错误绑定错误信息:
 *    1.handler(校验对象,BindingResult result) 要求:BindingResult 必须紧挨着校验对象
 *
 */

//接收用户数据,用户有校验注解
@PostMapping("register")
public Object register(@Validated User user, BindingResult result){
    if(result.hasErrors()){
        //如果有绑定错误,就不直接返回,自定义要返回的内容
        Map data = new HashMap();
        data.put("code",400);
        data.put("msg","校验参数异常");
        return  data;

    }

    System.out.println(user);
    return user;
}
相关推荐
tryqaaa_1 分钟前
学习日志(二)【linux全部命令,http请求头{有例题},Php语法学习】
linux·学习·http·php·web
sxjk198721 分钟前
WPS表格REGEXP公式提取车牌学习
学习·wps·表格·数据处理
yoona102024 分钟前
使用 Auto-Redbook-Skills 自动生成并发布redbook图文笔记
笔记·小红书·skills·redbook
m0_3771081441 分钟前
PCB学习
学习
U盘失踪了42 分钟前
Python 的 urljoin:告别手动拼接 URL 的烦恼
笔记·学习
南境十里·墨染春水1 小时前
C++笔记 STL——vector
开发语言·c++·笔记
智者知已应修善业1 小时前
【proteus78进制计数器与非门】2023-7-5
驱动开发·经验分享·笔记·硬件架构·硬件工程
思麟呀1 小时前
Epoll的学习,在select和poll的基础上
网络·数据库·sql·学习·tcp/ip
南境十里·墨染春水1 小时前
C++笔记 STL lterator迭代器
开发语言·c++·笔记
zjeweler1 小时前
宝藏网站推荐:云服务器特惠与网安学习资源的一站式聚合平台
运维·服务器·学习