SpringBoot实现数据格式校验

一、简单使用

1.1 准备

JSR303检验协议,javax.validation.constraints包下注解实现。
导包:


      javax.validation
      validation-api
      1.1.0.Final
    

1.2 实现

  1. 给bean添加校验注解:javax.validation.constraints,并定义自己的message提示。
@NotBlank(message = "若不满足返回的错误描述")
private String name;
  1. 控制层开启校验功能,若不加@Validated,则实体类上的校验注解无效。
    @RequestMapping("/save")
    public R save(@Validated @RequestBody BrandEntity brand){
        //业务处理
        return R.ok();
    }

1.3 注解扩展

@NotNull(message = "字段值不能为空,Map 和 Array 对象不能是 null, 但可以是空集(size = 0)")
@NotEmpty(message = "Map 和 Array 对象不能是 null 并且相关对象的 size 大于 0")
@NotBlank(message = "String 不是 null 且去除两端空白字符后的长度(trimmed length)大于 0")
@Max(value = 20,message = "最大长度为20,相应的还有@Min(value)")
@Size(max=10,min=5,message = "字段长度要在5-10之间")
@Pattern(regexp = "正则表达式",message = "不满足正则表达式")
@AssertTrue(message = "字段为true才能通过,针对布尔类型")
@Future(message = "时间在当前时间之后才可以通过,相应的还有@Past")
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Digits(integer,fraction)  被注释的元素必须是一个数字,其值必须在可接受的范围内
@Email 被注释的元素必须是电子邮件地址
@Length 被注释的字符串的大小必须在指定的范围内
@Range  被注释的元素必须在合适的范围内

二、接受返回的错误信息

  1. 给校验的bean后紧跟一个BindingResult,就可以获取到校验的结果。
    @RequestMapping("/save")
    public R save(@Validated @RequestBody BrandEntity brand,BindingResult result){
        //业务处理
        return R.ok();
    }
  1. 对错误结果进行处理
    @RequestMapping("/save")
    public R save(@Validated @RequestBody BrandEntity brand,BindingResult result){
        if (result.hasErrors()){
            Map errmap = new HashMap<>();
            //.getFieldErrors()方法获取错误的校验结果
            result.getFieldErrors().forEach((item)->{
                //item为FieldError类对象,getDefaultMessage获取错误描述
                String message = item.getDefaultMessage();
                //获取错误的属性的名字
                String field = item.getField();
                errmap.put(field,message);
            });
            return R.error(400,"输入数据不合法").put("data",errmap);
        }else {
            //业务处理 
        }
        return R.ok();
    }

三、统一的异常处理

3.1 准备

  1. 导入依赖
        
            org.springframework
            spring-web
            5.3.3
            compile
        
  1. @ControllerAdvice注解
    ControllerAdvice是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理

3.2 使用

  1. 设置需要作用的包
@ControllerAdvice(basePackages = "com.fangk.mall.product.controller")
public class FangkmallExceptionContrpllerAdvice {
}
  1. 普通controller层方法不处理数据校验错误返回信息,直接向上抛出
    @RequestMapping("/save")
    public R save(@Validated @RequestBody BrandEntity brand/*,BindingResult result*/){
        //只有业务处理了,简洁清晰
        return R.ok();
    }
  1. 书写controllerAdvice代码
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.fangk.mall.product.controller")
@RestControllerAdvice(basePackages = "com.fangk.mall.product.controller")
public class FangkmallExceptionContrpllerAdvice {
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleVaildException(MethodArgumentNotValidException e){
        log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        Map errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((item)->{
            errorMap.put(item.getField(),item.getDefaultMessage());
        });
        return R.error(400,"数据校验出现问题").put("data",errorMap);
    }
}
  • Controller里面的方法抛出了MethodArgumentNotValidException异常就会执行上面的这个方法来进行异常处理。
  • 该controller中可以有多个处理不同异常的方法,按照顺序匹配。兜底的可以选择Exception。
  • ResponseBody和ControllerAdvice注解可以合并为RestControllerAdvice。
  1. 业务代码实现中,controller中可以根据场景向上抛出不同的异常供active进行处理。

四、枚举定时码值映射

public enum BizCodeEnume {
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VAILD_EXCEPTION(10001,"参数格式校验失败");
    private int code;
    private String msg;
    BizCodeEnume(int code,String msg){
        this.code = code;
        this.msg = msg; }
    public int getCode() { return code; }
    public String getMsg() { return msg; }
}
//这样使用
return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),
BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap);

五、分组校验

5.1 为什么要用

一个实体类bean可能会需要应对不同的接口请求,每个接口对于字段的格式校验会出现不同要求。比如id字段,新增时因为自增序列所以不需要传输,而修改时则必传。
为了不重复创建相同字段而校验注解不同的bean,所以javax.validation.constraints的格式校验注解中为我们提供了groups参数。

5.2 如何使用

  1. 校验注解中加入groups参数
    @NotEmpty(groups={AddGroup.class})
    @Pattern(regexp="^[a-zA-Z]$",message = "检索首字母必须是一个字母",groups={AddGroup.class,UpdateGroup.class})
    private String firstLetter;
  • AddGroup新增时,需要校验非空和正则。
  • UpdateGroup更新时,只需校验正则。
  • groups参数格式为Class[] groups() default { };,故定义个空接口即可。
  1. 业务层增加@Validated
    @RequestMapping("/save")
    public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand/*,BindingResult result*/){
        //只有业务处理了,简洁清晰
        return R.ok();
    }
  • 默认没有指定分组校验的注解,在分组校验情况下不生效。
  • Validated({AddGroup.class},只有校验注解中有AddGroup的才会生效,其他不生效。

六、自定义校验注解

6.1 编写一个自定义的校验注解

@Documented
//指定校验器,此处若不指定,则需在初始化时指定
@Constraint(validatedBy = { ListValueConstraintValidator.class })
//表明注解可以使用的地方
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
    String message() default "{com.atguigu.common.valid.ListValue.message}";
    Class[] groups() default { };
    Class[] payload() default { };
    int[] vals() default { };
}

6.2 编写一个自定义的校验器

public class ListValueConstraintValidator implements ConstraintValidator {
    private Set set = new HashSet<>();
    //初始化方法
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }
    //判断是否校验成功
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return set.contains(value);
    }
}

6.3 关联自定义的校验注解和校验器

@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class【可以指定多个不同的校验器,适配不同类型校验】 })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)

你可能感兴趣的:(SpringBoot实现数据格式校验)