后端校验(JSR303)和统一异常处理

1.在Entity中,对需要校验的字段添加注解。

比如,字段不能为空,则对相应字段添加注解:@NotEmpty,如果需要自定义对错误的说明,则可以修改注解:@NotEmpty (message = "XX必须提交")

2.在controller中对需要校验的内容添加注解:@Valid

比如:

@RequestMapping("/save")

public R save(@Valid @RequestBody CategoryEntity category){

       //进行操作

}

如想对校验结果进行记录,则有:

    @RequestMapping("/save")

    public R save(@Valid @RequestBody CategoryEntity category, BindingResult result){

        if(result.hasErrors()){

            //1.获取校验的错误结果

            Map<String,String> map = new HashMap<>();

            result.getFieldErrors().forEach((item)->{

                String message = item.getDefaultMessage();

                String field = item.getField();

                map.put(field,message);

            });

            R.error(400,"提交的数据不合法").put("data",map);

        }

              categoryService.save(category);

        return R.ok();

}

其中“BindingResult result“里就记录了校验结果的信息,通过getField()和getDefaultMessage()分别得到字段名和校验不通过给出的信息。

但这样每个方法都需要重复,所以可以进行统一结果处理。

3.统一异常处理

@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")

public class GulimallExceptionControllerAdvice {

    @ExceptionHandler(value = MethodArgumentNotValidException.class)

    public R handleValidException(MethodArgumentNotValidException e){

      log.error("数据校验出现问题:{},异常类型:{}",e.getMessage(),e.getClass());

      BindingResult bindingResult = e.getBindingResult();

      Map<String,String> map = new HashMap<>();

      bindingResult.getFieldErrors().forEach((item)->{

          map.put(item.getField(),item.getDefaultMessage());

      });

      return R.error(400,"数据校验出现问题").put("data",map);

    }

}

其中@RestControllerAdvice是一个组合注解,由@ControllerAdvice、@ResponseBody组成。同时使用basepakage指定了处理哪里的异常。

而使用@ExceptionHandler来处理指定的异常,这里就指定了处理MethodArgumentNotValidException,就可以将前面的校验不通过的异常捕获到,并最终得到输出。

4.分组

同一个字段可能在不同情况下有不同校验规则,比如添加和更新两种情况,则可以使用分组。

先创建两个接口,更新:public interface UpdateGroup {},添加:public interface AddGroup {},这两个接口不需要添加任何额外的东西。

接着对对应字段添加分组,比如:

@NotNull(message = "修改必须指定品牌id",groups = {UpdateGroup.class})

@Null(message="新增不能指定id",groups = {AddGroup.class})

private Long brandId;

接着在contronller中,添加分组

@RequestMapping("/save")

    public R save(@Validated(AddGroup.class) @RequestBody CategoryEntity category){

              categoryService.save(category);

        return R.ok();

}

注意,没有添加分组的字段,校验规则会不生效

5.自定义校验

对字段使用自定义注解@ListValue

/**

* 显示状态[0-不显示;1-显示]

*/

@ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class})

@NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})

private Integer showStatus;

编写自定义注解:

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

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

    Class<? extends Payload>[] payload() default {};

    int[] vals() default {};

}

在resource中创建ValidationMessages.properties,并添加以下内容:

com.atguigu.common.valid.ListValue.message=必须提交指定的值

这样就得到了默认的提示信息。

可以看到上面写的自定义注解用了ListValueConstraintValidator.class,则创建相应的自定义校验器:

public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {

Set<Integer> set = new HashSet<>();

    //初始化方法

    @Override

    public void initialize(ListValue constraintAnnotation) {

        int[] vals = constraintAnnotation.vals();

        for(int val:vals){

            set.add(val);

        }

}

    //判断是否校验成功

    /***\

     *

     * @param integer 需要校验的值

     * @param constraintValidatorContext

     * @return

     */

    @Override

    public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {

        return set.contains(integer);

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值