后端使用JSR303对数据进行校验

在前后端分离项目中,前端通过制定rules校验数据,能最早的让用户发现输入错误,如果使用postman发送数据,就会跳过前端校验,因此需要后端同样需要做验证。
步骤

1.给bean添加校验注解

导入 javax.validation.constraints,并定义自己的message提示

 	@NotBlank(message = "账号不能为空")
    private String account;

    @NotBlank(message = "密码不能为空")
    private String password;

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

    @NotBlank(message = "身份证不能为空")
    @Pattern(regexp="^(\\d{18,18}|\\d{15,15}|(\\d{17,17}[x|X]))$", message="身份证格式错误")
    private String identityCard;
   
   //注意NotBlank不能作用于integer   @NotNull可以
    @NotNull(message = "角色不能为空")
    private Integer role; 

2.在Controller层开启@Valid验证注解

效果:传入的数据校验失败会返回错误信息

    //添加用户   @Valid
    @PostMapping("/addUser")
    public RtnResult addUser(@Valid @RequestBody ClaimUser claimUser){
        return  claimUserService.addUser(claimUser);
    }

3.统一异常处理

给controller后的需要校验的bean后加一个BindingResult类就可以获得校验的结果,
但是在大项目中一般使用统一异常处理校验结果,返回json格式,如下所示

    //后端校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public  RtnResult handValidException(MethodArgumentNotValidException e){
        BindingResult bindingResult = e.getBindingResult();
        Map map = new HashMap<>();
        bindingResult.getFieldErrors().forEach(fieldError -> {
            map.put(fieldError.getField(),fieldError.getDefaultMessage());
        });
        return RtnResult.fail(map);
    }

4.分组校验(多场景的复杂校验)

分组校验应用场景:添加和更新需要不同的校验规则时
步骤1:先创建添加和更新的接口
作用:仅仅是多场景的一个标识,接口内容为空即可

步骤2:在上述 @NotBlank(message = “密码不能为空”)后加上groups
作用:给校验注解标注什么情况下需要校验(添加/更新)

//AddGroup.class是添加的标识组,可以有多个
    @NotBlank(message = "密码不能为空", groups = {AddGroup.class})
    private String password;

	@NotBlank(message = "姓名不能为空", groups = {AddGroup.class,UpdateGroup.class})
    private String name;

步骤3:替换controller层原来的@Valid注解,使用mvc提供的@Validated注解,否则不生效

    //添加用户   @Validated指定哪个操作使用校验
    @PostMapping("/addUser")
    public RtnResult addUser(@Validated(AddGroup.class) @RequestBody ClaimUser claimUser){
        return  claimUserService.addUser(claimUser);
    }

注意:如果使用分组校验,校验注解没有使用groups,则校验不生效,一定要使用groups

5. 自定义校验注解、自定义校验器

场景:当显示和隐藏的属性showStatus只能时0或1,需要自定义校验注解和自定义校验器

1.在需要校验的属性上添加自定义注解

//	@NotBlank(message = "开关状态不能为空") 不再使用非空,使用@ListValue自定义校验注解

    @ListValue(vals={0,1},message = "开关状态只能是0或1")
    private Integer showStatus;

2.导入依赖

        
        
            javax.validation
            validation-api
            2.0.1.Final
        

3.编写自定义校验注解
自定义校验注解可根据其他注解,例如@NotBlank进行编写

//自定义校验注解ListValue 
@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class}) //关联自定义校验器,可以适配多个校验器,一个注解完成多种校验
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})  //可标注位置
@Retention(RetentionPolicy.RUNTIME) //运行环境
public @interface ListValue {
    String message() default "{com.atguigu.common.valid.ListValue.message}"; //错误信息从这个配置文件中取  可以使用配置文件,也可直接使用message

    Class[] groups() default {};

    Class[] payload() default {};

     int[]  vals() default {};  //标注在属性上的vals={0,1}
}

4.编写自定义校验器

//自定义校验器 必须实现ConstraintValidator
//ConstraintValidator中的 泛型1:绑定的泛型注解   泛型2:校验的数据类型
public class ListValueConstraintValidator implements ConstraintValidator {

    private Set set = new HashSet<>();

    //初始化方法,获取在Entity类的属性上标注的符合条件的Integer的值:{0,1}
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    //判断是否校验成功方法
    //integer:传进来的值
    //判断依据:看integer是否在初始化方法的数组中
    @Override
    public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
        if (set.contains(integer)) {
            return true;
        }
        return false;
    }
}

5.校验测试
后端使用JSR303对数据进行校验_第1张图片
完毕!

你可能感兴趣的:(java)