spring-mvc - validation - 数据验证

类似JDBC规范,Java提出Jsr-303规范用于数据校验hivernate-validatorJsr303规范的实现

Spring-mvc集成了hibernate-valdator,支持自动校验

🌳JSR-303 - 校验注解

Jsr-303提供了很多校验注解,如下

注解说明
@NotNull不是null
@NotEmpty不为空
@Lengthstr长度
@Min、@DecimalMin数值最大值
@Max、@DecimalMax数值最小值
@Range、@DecimalRange数值范围
@Size集合大小
@Emailemail
@Past过去date
@Feature未来date
@Pattern正则格式

另外,还有@Valid@Validated@Constraint

注解作用
@Valid用在param上,表示校验(不支持分组校验)。用在Field上,表示嵌套校验
@Validated用在param上,表示校验(支持分组校验)。用在Controller上,表示校验基本类型
@Constraint自定义校验注解指定ConstraintValidator

🌾基本类型 - 校验

对于基本类型校验,步骤如下

  1. 配置MethodValidationPostProcessor后置处理器
  2. Controller上使用@Validated注解(参数上不加@Valid或者@Validated)

1️⃣ 配置MethodValidationPostProcessor

<!--- 数据校验 -  MethodValidationPostProcessor - 用于支持基本类型校验 -->
<bean id="methodValidationPostProcessor"
      class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor" />

2️⃣ 在Controllter上添加@Validated。

/*
* 数据验证 - JSR303
* */
@Controller
@Validated
public class ValidateController {
    
    /*
    * MARK 基本类型验证  - 解决方案 - 配置MethodValidationPostProcessor
    *
    * 1. 配置MethodValidationPostProcessor - MethodValidation后置处理器
    * 2. 在Controller上添加@Validated
    * */
    @GetMapping("/validate2")
    @ResponseBody
    public String validate1(@RequestParam("username") @Length(min = 7,message = "name min is {0}") String username){
        return "基本类型验证";
    }
}

🍀 Pojo类型 - 校验

Pojo类型校验,直接在Param上添加@Valid或者@Validated,对于校验结果

  • 可以使用BindingResult接收校验结果
  • 不用BindingResult,校验出错,抛出400错误
/*
    * MARK 实体类校验 - @Valid
    * MARK 嵌套校验
    *
    * @Valid - 用在requestMapping方法上
    * @Valid - 用在Field上,表示嵌套校验 (@Valided不能用在Field)
    * BindResult - 接收校验结果
    *   - hasErrors()
    *   - getFieldErrors()
    *   - getField()、getRejectedValue()、getDefaultMessage()、getCode()
* */
@GetMapping("/validate1")
@ResponseBody
public String validate2(@Valid User user,BindingResult bindingResult){
    printBindResult(bindingResult);
    return "验证成功";
}

private void printBindResult(BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();

        for (FieldError fieldError : fieldErrors) {
            System.out.println(fieldError.getField()); // 字段名称
            System.out.println(fieldError.getRejectedValue()); // 提供的值
            System.out.println(fieldError.getDefaultMessage()); // 错误信息
            System.out.println(fieldError.getCode()); // 错误信息
            System.out.println("===================================");
        }
    }
}

🌱 嵌套校验

对于嵌套校验,把对应Pojo的Field使用@Valid标注,就可以实现嵌套校验

@Data
public class User {
    @Valid
    private Car car;
}

🌴分组校验

分组校验步骤如下

  1. Pojo类提供校验组。对于通用校验写一个BaseGroup.class,然后不同的组去继承BaseGroup
  2. 校验时,给@Validated提供groups属性

1️⃣ 给Pojo提供校验注解校验组

@Data
public class User {
    
    /*
    * 分组校验 - 组别
    * */
    public interface InsertGroup extends AllGroup{}
    public interface UpdateGroup extends AllGroup {}
    public interface AllGroup{}

    /*
    * 分组验证测试 - 分组验证
    * */
    @Min(value = 12,message = "最小是#{value}",groups = InsertGroup.class)
    @NotNull(groups = InsertGroup.class)
    private Integer id;
	
    /*
    * 所有验证 - 因为InsertGroup和UpdateGrop实现了AllGroup,对于@Validated(InserGroup)会验证该Field
    * */
    @Min(value = 1000, message = "{Min}",groups = AllGroup.class)
    private Double salary;

    /*
    * 不属于任何组 - 只有@Validated({}) 或者 @Validated 可以验证
    **/
    @Length(min = 7,message = "长度最少是{0}")
    private String username;

}

2️⃣ 给@validated提供groups属性

/*
 * MARK 分组校验 - @Validated
 *
 * 1. 分组 - 对于通用验证,卸一个Default.class,然后其他组继承Default.class
 * 2. @Validated({Group.class}) 指定组
 * */
@GetMapping("/validInsert")
@ResponseBody
public String validInsert(@Validated({User.InsertGroup.class}) User user, BindingResult bindingResult){
    printBindResult(bindingResult);
    return "基本类型验证";
}
@GetMapping("/validUpdate")
@ResponseBody
public String validUpdate(@Validated({User.UpdateGroup.class}) User user,BindingResult bindingResult){
    printBindResult(bindingResult);
    return "基本类型验证";
}

🍃 自定义校验 - 自定义校验注解

我们可以提供自定义校验注解,步骤如下

  1. 提供自定义校验注解(需要提供groupspayload属性),使用@Constraint指定Validator
  2. 提供校验器(Validator)实现ConstraintValidator

1️⃣ 自定义校验注解

/*
* 验证 值是 value中的 - 类似mysql的check约束
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ColorCheckValidator.class) // 哪个了Validator验证
public @interface ColorCheck {

    // values
    String[] value() default {};

    // errorMessage
    String message() default "颜色不符合";

    // group - 分组校验
    Class<?>[] groups() default {};

    // payload - 承载信息
    Class<? extends Payload>[] payload() default {};

}

2️⃣ 实现ConstraintValidator

/*
* ConstraintValidator - 约束验证
* */
public class ColorCheckValidator implements ConstraintValidator<ColorCheck,String> {

    private HashSet<String> colorSet = new HashSet<>();
    @Override
    public void initialize(ColorCheck constraintAnnotation) {
        // 可以根据 payload 承载的信息 - 进行 - 初始化
        for (String color : constraintAnnotation.value()) {
            colorSet.add(color);
        }
    }

    /*
    * true  = 通过
    * false = 不通过
    * */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return colorSet.contains(value);
    }
}

使用校验注解

@Data
public class Cat {

    @ColorCheck(value = {"red","green","blue"})
    private String color;
}

进行校验

/*
    * MARK 自定义 - 校验注解 - @
    *
    * 1. 定义校验注解 - groups表示分组验证,payload用于承载信息
    * 2. @Constraint - 指定Validator
    * 3. 实现Validator - 继承ConstraintValidator
    *
    *
    * 如果 自定义校验 和 基本属性校验一起,也就是 在Controller上用了@Validated,那么对于自定义校验,
    *  - 使用@Valid,无法使用BindingResult - 直接跑出500.
    *  - 应该用@Validated
    *
    * */
    @GetMapping("/validCustom")
    @ResponseBody
    public String validCustom(@Valid Cat cat,BindingResult bindingResult) {
        printBindResult(bindingResult);

        if(bindingResult.hasErrors()) {
            return "Cat颜色错误";
        }
        return "验证Cat成功";
    }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值