Spring Validation 使用总结

1. 概述及常用注解

数据的校验是交互式网站一个不可或缺的功能,前端的 JS 校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用 HTTP 工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中

常用校验

1、SR303/JSR-349

JSR303 是一项标准,只提供规范不提供实现,规定一些校验规范即校验注解,如 @Null,@Pattern,位于 javax.validation.constraints 包下。JSR-349 是其的升级版本,添加了一些新特性

  • @Null:被注释的元素必须为 null
  • @NotNull :被注释的元素必须不为 null
  • @AssertTrue:被注释的元素必须为 true
  • @AssertFalse:被注释的元素必须为 false
  • @Min(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Max(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @DecimalMin(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @DecimalMax(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Size(max, min):被注释的元素的大小必须在指定的范围内
  • @Digits (integer, fraction):被注释的元素必须是一个数字,其值必须在可接受的范围内
  • @Past:被注释的元素必须是一个过去的日期
  • @Future:被注释的元素必须是一个将来的日期
  • @Pattern(value):被注释的元素必须符合指定的正则表达式

2、Hibernate Validation

Hibernate Validation 是对这个规范的实现,并增加了一些其他校验注解,如 @Email,@Length,@Range 等等

  • @Email:被注释的元素必须是电子邮箱地址
  • @Length:被注释的字符串的大小必须在指定的范围内
  • @NotEmpty:被注释的字符串的必须非空
  • @Range:被注释的元素必须在合适的范围内

3、Spring Validation

Spring Validation 对Hibernate Validation 进行了二次封装,在 SpringMVC 模块中添加了自动校验,并将校验信息封装进了特定的类中

注解 含义
空值判断 @Null 验证对象是否为NULL
@NotNull 验证对象是否不为NULL,但可以为 EMPTY("", " ", " "),无法查检长度为 0 的字符串
@NotBlank 验证String 对象是否不为 NULL,还有被 Trim 的长度是否大于 0,只能用在 String 字符串类型上,且会去掉前后空格
@NotEmpty 验证对象是否不为NULL 或者是 EMPTY(""),长度必须大于 0 (" ", " ")
布尔检查 @AssertTrue 验证 Boolean 对象是否为 True
@AssertFalse 验证 Boolean 对象是否为 False
长度检查 @Size(min, max) 验证对象(Array, Collection , Map, String)长度是否在给定的范围之内
@Length(min, max) 验证字符串长度是否介于 min 和 max 之间
日期检查 @Past 验证 Date 和 Calendar 对象是否在当前时间之前,即过去的日期
@Future 验证 Date 和 Calendar 对象是否在当前时间之前,即过去的日期
正则检查 @Pattern(regexp, flags) 验证 String 对象是否符合正则表达式的规则
  • regexp:正则表达式
  • flags:指定 Pattern.Flag 的数组,表示正则表达式的相关选项
数值检查
(建议使用在 String,Integer 类型
不建议使用在 int 类型上
因为表单值为 "" 时无法转换为 int
但可以转换为 String 为 ""
Integer 为 NULL)
@Min(val) 验证 Number 和 String 对象是否大等于指定的值
@Max(val) 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax(val) 被标注的值必须不大于约束中指定的最大值,这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示 .小数 存在精度
@DecimalMin(val) 被标注的值必须不小于约束中指定的最小值,这个约束的参数是一个通过 BigDecimal 定义的最小值的字符串表示 .小数 存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer, fraction) 验证字符串是否是符合指定格式的数字,integer 指定整数精度,fraction 指定小数精度
@Range(min, max) 被指定的元素必须在合适的范围内
@Email 验证是否是邮件地址,如果为 NULL,不进行验证,算通过验证
@CreditCardNumber 信用卡验证
@ScriptAssert(lang, script, alias)
@URL(protocol, host, port, regexp, flags)
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个 Map,则对其中的值部分进行校验.(是否进行递归验证)

2. @Valid 和 @Validated 注解

@Valid、@Validated 注解都可以实现数据的验证,表示开启数据验证

1、包位置不同

  • @Valid:位于 javax.validation.Valid
  • @Validated:位于 org.springframework.validation.annotation.Validated,是 @Valid 的一次封装,Spring 提供的校验机制使用

在这里插入图片描述

2、Spring Validation 验证框架提供了 @Validated 注解对参数进行验证,符合 Spring's JSR-303 规范;而 @Valid 注解是 javax 提供的,符合标准的 JSR-303 规范

3、当使用仅是注解字段属性并验证规范,@Validated 和 @Valid 注解的功能是相同的

4、@Validated 注解可以用于方法、构造函数、方法参数上;而 @Valid 还可以用于成员属性(字段)之上

5、@Validated 注解可以使用分组校验的功能,为同一个对象属性提供不同分组,并根据分组来校验属性参数;而 @Valid 注解不支持分组验证

6、@Valid 注解支持嵌套验证,当类的属性是一个复杂对象时,可以使用 @Valid 对该属性对象中的属性同时进行校验;@Validated 并不支持在属性上使用

3. 使用

3.1 POM

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>${spring.boot.version}</version>
</dependency>

3.2 简单参数校验

服务接口接收单个简单参数时,可以在方法参数中直接使用校验注解。单参数校验时,还需要在 Controller 层控制器类中使用 @Validated 标注才会生效

@RestController
@Validated
public class ValidateController {

    @PostMapping("/simple")
    public Result simple(@RequestParam("validate") @NotBlank(message = "用户编码不能为空") String validate) {
        System.out.println(validate + "参数值");

        return Result.success("成功");
    }
}

在这里插入图片描述

在这里插入图片描述

传入多个单参数为空时:

@RestController
@Validated
public class ValidateController {

    @PostMapping("/simple")
    public Result simple(@RequestParam("validate") @NotBlank(message = "用户编码不能为空") String validate,
                         @RequestParam("id") @NotBlank(message = "ID 不能为空") String id) {
        System.out.println(validate + "参数值" + id);

        return Result.success("成功");
    }
}

在这里插入图片描述

在这里插入图片描述

3.3 实体类校验

在实体类中使用校验注解标注需要校验的字段后,还需要在请求层接收参数时开启参数校验,只需要在 Controller 接口层的参数中使用 @Validated 标注,在接口接收到请求参数时会自动进行校验

校验时可以使用 BindingResult 返回错误信息(注:添加了 BindingResult 就不会报错了),需配合 @RequestBodyRequestPart 一起使用,同时请求参数要在请求体里(重点是这个),否则会报 IllegalStateException 异常

在这里插入图片描述

@RestController
public class ValidateController {

    @PostMapping("/getUser")
    public Result getUser(@Validated @RequestBody User user, BindingResult result) {

        if (result.hasErrors()) {
            return Result.fail("校验失败" + result.getFieldError().getDefaultMessage());
        }
        return Result.success("success");
    }
}

实体类得加上 @Data 注解,即 getter/setter 方法,不然校验不到

@Data
public class User {

    @NotNull(message = "id 不能为空")
    private Integer id;

    @NotBlank(message = "姓名不能为空")
    private String name;

    private String gender;

    @Pattern(regexp = "^((?:19[2-9]\\d{1})|(?:20(?:(?:0[0-9])|(?:1[0-8]))))\\-((?:0?[1-9])|(?:1[0-2]))\\-((?:0?[1-9])|(?:[1-2][0-9])|30|31)$")
    private String birthday;

    @DecimalMin("0")
    private BigDecimal balance;

    @Valid
    private List<Pet> pets;
}

@Data
class Pet {

    @Min(0)
    private double weight;

    private String name;
}

在这里插入图片描述

在这里插入图片描述

3.4 全局异常

使用 Validation 校验异常后,当参数发生异常时,会抛出 MethodArgumentNotValidException 类型的异常,为了程序报错更通俗易懂以及方便,无需在每个接口都手动返回异常信息,可以定义全局异常来捕获该类型的异常,并统一返回结果信息

在这里插入图片描述

@RestControllerAdvice
//@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    //    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result notValidException(MethodArgumentNotValidException exception) {
        String message = exception.getBindingResult().getFieldError().getDefaultMessage();
        log.error("参数校验异常: {}", message);

        return Result.fail(message);
    }
}

在这里插入图片描述

在这里插入图片描述

当参数传递异常时,可能还会出现 BindingException,使用简单参数校验时,会出现 ConstraintViolationException,可根据实际情况定义全局异常

posted @ 2022-12-21 13:53  凡223  阅读(191)  评论(0编辑  收藏  举报