图解
个人整理Xind图片导出:
参数校验:
简单例子
Java API 规范(JSR303)定义了 Bean 校验的标准 validation-api,但没有提供实现。Hibernate Validation 是对这个规范的实现,并增加了校验注解如 @Email、@Length等。Spring Validation 是对 Hibernate Validation 的二次封装,用于支持 Spring MVC 参数自动校验。接下来,我们以 spring-boot 项目为例,介绍 Spring Validation 的使用。
导入依赖:
如果 spring-boot 版本小于 2.3.x,spring-boot-starter-web 会自动传入 hibernate-validator 依赖。如果 spring-boot 版本大于2.3.x,则需要手动引入依赖:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.1.Final</version>
</dependency>
正常情况:
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<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>
</dependencies>
编写controller:
/**
* @Author zsl
* @Date 2021/12/2 22:12
*/
@RestController
public class DemoController {
@RequestMapping("add")
public Map<String, Object> add(@RequestBody @Validated(AddGroup.class) Admin admin, BindingResult bindingResult) {
System.out.println(admin);
HashMap<String, Object> data = new HashMap<>();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
Integer i = 0;
for (FieldError fe : fieldErrors) {
data.put(fe.getField(), fe.getDefaultMessage());
}
return data;
}
@RequestMapping("edit")
public String edit() {
return "success";
}
}
编写实体类:
/**
* @Author zsl
* @Date 2021/12/2 22:13
*/
@Data
public class Admin {
@NotNull(message = "用户id不能为空", groups = {EditGroup.class})
@Null(message = "用户id必须为空", groups = {AddGroup.class})
private Long id;
@Pattern(regexp = "^[a-zA-Z0-9_-]{4,16}$", message = "用户名必须由字母开头数字下划线组成,且长度4-16", groups = {AddGroup.class, EditGroup.class})
@NotBlank(message = "用户名不能为空", groups = {AddGroup.class, EditGroup.class})
private String username;
@GenderAnno(contains = {0, 1, 2}, message = "性别必须是0、1、2", groups = {AddGroup.class, EditGroup.class})
@NotNull(message = "性别不能为空", groups = {AddGroup.class, EditGroup.class})
private Integer gender;
@Pattern(regexp = "^.*(?=.{6,})(?=.*\\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$", message = "密码最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符", groups = {AddGroup.class, EditGroup.class})
@NotBlank(message = "密码不能为空", groups = {AddGroup.class, EditGroup.class})
private String password;
@Email(message = "邮箱格式不正确", groups = {AddGroup.class, EditGroup.class})
@NotBlank(message = "邮箱不能为空", groups = {AddGroup.class, EditGroup.class})
private String email;
@Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$", message = "手机格式不正确", groups = {AddGroup.class, EditGroup.class})
@NotBlank(message = "手机不能为空", groups = {AddGroup.class, EditGroup.class})
private String phone;
@Past(message = "生日必须是一个过去的时间", groups = {AddGroup.class, EditGroup.class})
@NotNull(message = "生日不能为空", groups = {AddGroup.class, EditGroup.class})
private LocalDateTime birthday;
@Pattern(regexp = "^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$", message = "身份证格式不正确", groups = {AddGroup.class, EditGroup.class})
@NotNull(message = "身份证不能为空", groups = {AddGroup.class, EditGroup.class})
private String cardCode;
}
自定义注解:
/**
* @Author zsl
* @Date 2021/12/2 22:50
*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = {MyConstraintValidator.class})
public @interface GenderAnno {
int[] contains() default { };
String message() default "";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
自定义注解实现规则:
/**
* @Author zsl
* @Date 2021/12/2 22:52
*/
public class MyConstraintValidator implements ConstraintValidator<GenderAnno, Integer> {
private List<Integer> contains;
/**
* 初始化 将注解需要包含的值保存到 当前对象中
*/
@Override
public void initialize(GenderAnno constraintAnnotation) {
ArrayList<Integer> ints = new ArrayList<>();
int[] contains = constraintAnnotation.contains();
for (int i = 0; i < contains.length; i++) {
ints.add(contains[i]);
}
this.contains = ints;
}
/**
* 校验是否包含
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return contains.contains(value);
}
}
当然表单验证失败时,会抛异常,而异常会统一在异常处理中解决,详情请看全局统一异常处理文章
表单校验异常
抛出异常,在全局异常控制管理中进行处理。
/**
* 处理表单校验异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseResult<String> handlerFormValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
...
return ResponseResult.error(...);
}