序言
控制器方法( handler )中负责请求参数校验。
传统的写法是在每个方法的开头对所有请求参数进行校验,如果存在参数不满足条件,则抛出异常,或者提前返回错误。
Validation API 提供了一系列的注解,通过将这些注解标记在 entity 类的属性上,Spring MVC 会根据这些注解的语义,自动完成请求参数校验。如果参数不满足条件,则抛出异常。这节省了开发者手动校验请求参数的麻烦。
负责自动参数校验的类实际上是由 Spring Boot 自动装配导入的,因此我们要使用对应的 starter 依赖。
案例演示
依赖
1 2 3 4 5 6 7 8 9 10 11 12 13
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
|
validation-api 是本次介绍的重点
项目结构
一个标准的 Spring Initializer 生成的 Spring Boot 项目
entity
User
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package org.gustav.springmvcvalidatordemo.entity;
import lombok.Data;
import javax.validation.constraints.*;
@Data public class User { @NotBlank @Size(max = 5, message = "名字不能超过5个字符") private String name;
@NotNull @Min(value = 0, message = "年龄不能小于0") @Max(value = 200, message = "年龄不能大于200") private Integer age; }
|
@NotBlank
:用在 CharSequence
类型的属性上,表示该字段非空,且长度至少为 1。简单来说,该字符串必须有内容
@Size
:用在CharSequence
和集合类的属性上,表示该字段的字符数/元素数目。max = 5
是数量的上界,不能超过该上界。当属性值不满足条件时,Spring MVC 会抛出异常,如果设置了message
属性,则异常内容中会包含 message
的值
@NotNull
:字面含义,字段非空
@Min
、@Max
:用在数值类型上,对数值的大小进行约束。
Pet
1 2 3 4 5 6 7 8 9 10 11 12 13
| package org.gustav.springmvcvalidatordemo.entity;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data public class Pet { @NotBlank private String type; @NotBlank private String name; }
|
UserAndPet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package org.gustav.springmvcvalidatordemo.entity;
import lombok.Data;
import javax.validation.Valid; import javax.validation.constraints.NotNull;
@Data public class UserAndPet { @NotNull @Valid private User user;
@NotNull @Valid private Pet pet; }
|
@Valid
注解告诉 Spring MVC,它标记的类上也有字段需要校验。
controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package org.gustav.springmvcvalidatordemo.Controller;
import org.gustav.springmvcvalidatordemo.entity.UserAndPet; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*;
@Controller public class DemoController { @PostMapping("/test") @ResponseBody public UserAndPet test(@Validated @RequestBody UserAndPet userAndPet) { System.out.println(userAndPet); return userAndPet; } }
|
@Validated
指示 Spring MVC:当前请求参数需要被校验
使用 Postman 发送请求
合法请求
请求体如下:
1 2 3 4 5 6 7 8 9 10
| { "user": { "name": "adam", "age": 15 }, "pet": { "type": "cat", "name": "east wind" } }
|
非法请求
故意使user.name
超过长度限制。请求体如下:
1 2 3 4 5 6 7 8 9 10
| { "user": { "name": "adam williams", "age": 15 }, "pet": { "type": "cat", "name": "east wind" } }
|
服务器返回了 400 错误
服务端抛出了MethodArgumentNotValidException
的异常。内容是user.name
为非法参数,同时展示了我们自己设置的 message
总结
通过使用 Validation 注解,我们可以便捷地实现请求参数校验,无需写很多代码。
试想,我们使用传统方式校验请求参数,光是校验 user.name
,就需要写很多代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @PostMapping("/test") @ResponseBody public UserAndPet test(@Validated @RequestBody UserAndPet userAndPet) { if (userAndPet == null) { throw new IllegalArgumentException(); } if (userAndPet.getUser() == null) { throw new IllegalArgumentException(); } String name = userAndPet.getUser().getName(); if (!(name != null && name.length() >= 1 && name.length() <= 5)) { throw new IllegalArgumentException(); } }
|
当然,方便快捷的 Validation 注解校验建立在 Spring MVC 和 Spring Boot 的基础上。Spring Boot 具体自动装配了哪些类,Spring MVC 又是如何使用这些类完成请求参数校验,就不在本文的讨论范围内了。有兴趣的读者可以自行阅读源码,或者阅读其他文章。