Java后端技术-JSR303学习笔记

数据校验

数据校验一般分为前端校验,后端校验,绕过前端校验直接通过接口直接向后端发送请求,因此可以使用JSR303来实现后端的数据校验,只需要用简单的注解方式,即可完成数据校验,系统给定的校验注解如下,也可以指定自定义校验

image-20210523202355765

@NotBlank:带注释的元素不能为null,并且必须至少包含一个,只能作用在接收的String类型上,长度必须大于0

@NotNull:带注解的元素不能为null,接收任意类型,可以为""

@NotEmpty:带注解的元素不能为null或者其他空值,而且长度必须大于0,一般用在集合类上面

基本校验

在需要校验的属性上添加注解

@NotBlank(message = "名字不能为空")
private String name;
@URL(message = "logo必须合法")
private String logo;
@Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须为一个字母")
private String firstLetter;
@Min(value = 0, message = "排序必须大于0")
private Integer sort;

在controller上开启校验功能@Valid

@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand,BindingResult result) {
    if (result.hasErrors()) {
        Map<String, String> map = new HashMap<>();
        // 获取校验的结果
        result.getFieldErrors().forEach(item -> {
            String message = item.getDefaultMessage();
            String field = item.getField();
            map.put(field, message);
        });
        return R.error(400, "提交的数据不合法").put("data", map);
    }
    brandService.save(brand);
    return R.ok();
}

测试数据校验结果

image-20210523215134573

分组校验

声明接口分组类,无意义,仅作声明接口

// 添加分组
public interface AddGroup {}
// 修改分组
public interface UpdateGroup {}
// 查询分组
public interface QueryGroup {}

给校验的注解注明什么分组下需要进行校验

@NotBlank(message = "名字不能为空",groups = {AddGroup.class,UpdateGroup.class})
private String name;
@URL(message = "logo必须合法",groups = {AddGroup.class,UpdateGroup.class})
private String logo;
@Min(value = 0, message = "排序必须大于0",groups = {AddGroup.class})
private Integer sort;

在controller上的校验功能@Valid标明哪些分组使用注解

public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){...}

注:如果开启了分组校验后,@Validated没有指定分组,数据校验不生效

校验器全局异常处理

在Controller的方法上声明参数BindingResult result可以捕获校验异常,但是如果每个controller都有异常需要捕获,代码十分冗余,因此可以定义全局异常校验处理类

定义错误码和错误信息,方便日后维护

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;
    }
}

全局异常处理

@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice {

    // 捕获校验器异常
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleVaildException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        Map<String, String> map = new HashMap<>();
        result.getFieldErrors().forEach(item -> {
            String message = item.getDefaultMessage();
            String field = item.getField();
            map.put(field, message);
        });
        return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(), BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data", map);
    }
	// 捕获其他异常
    @ExceptionHandler(value = Exception.class)
    public R handleException(Exception e) {

        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(), BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}

测试数据校验结果

image-20210523222942248

自定义校验器

引入依赖

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

编写自定义校验注解

模仿系统提供的注解,生成自定义注解

@Constraint:指定校验器

image-20210523223213114

@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.common.valid.ListValue.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
	// 定义注解方法
    int[] vals() default {};
}

编写自定义消息模板ValidationMessages.properties

com.common.valid.ListValue.message=必须为指定属性

编写自定义校验器

public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
	// 存放注解的值
    private Set<Integer> set = new HashSet<>();
    // 初始化方法
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }
    // 判断是否校验成功 value为需要校验的值
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        // 如果校验的值包含在注解里校验成功
        return set.contains(value);
    }
}

使用自定义注解

// 显示状态[0-不显示;1-显示] 不为0 1就报错
@ListValue(vals = {0, 1})
private Integer showStatus;

测试自定义注解

image-20210523223841792

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值