SpringBoot下的参数校验和全局异常

日常开发中,前后端都会对传递的参数进行校验,前端为的是更好的交互体验,后端则更是为了接口的安全,数据的正确性做了各种各样的校验。

环境:springboot2.3.3.RELEASE

校验依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

一、全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {

    private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);


    /**
     * 对于注解校验的进行统一的验证处理
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public R methodArgumentNotValidExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e){
        log.warn("1、数据校验不通过,请求路径:{},异常错误信息:{}", request.getRequestURI(), e);
        return R.failed(getErrorMsg(e));
    }

    /**
     * 对于注解校验的进行统一的验证处理
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public R methodArgumentNotValidExceptionHandler(HttpServletRequest request, BindException e){
        log.warn("2、数据校验不通过,请求路径:{},异常错误信息:{}", request.getRequestURI(), e);
        return R.failed(getErrorMsg(e));
    }

    /**
     * 默认异常处理方法
     * @param request
     * @param e
     * @return 返回异常请求路径和异常信息
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public R defaulErrorHandler(HttpServletRequest request, Exception e){
        log.error("3、异常请求路径:{},异常错误信息:{}", request.getRequestURI(), e);
        return R.failed(e.getMessage());
    }

    /**
     * 最高级别的错误拦截,防止错误信息进入到前端
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = Throwable.class)
    @ResponseBody
    public R throwableHandler(HttpServletRequest request, Throwable e){
        log.error("6、Throwable错误信息:{}, 异常请求路径:{}", request.getRequestURI(), e);
        return R.failed("内部服务器错误");
    }

    /**
     * 整理错误信息
     * @param e
     * @return
     */
    private String getErrorMsg(Exception e){
        //获取错误验证结果
        StringBuilder sb = new StringBuilder();
        if (e instanceof BindException){
            BindException bindException = (BindException) e;
            bindException.getBindingResult().getFieldErrors().forEach((error) -> {
                //取出错误数据并封装
                sb.append(error.getDefaultMessage());
                sb.append(",");
            });

        } else if (e instanceof MethodArgumentNotValidException){
            MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
            exception.getBindingResult().getFieldErrors().forEach((error) -> {
                sb.append(error.getDefaultMessage());
                sb.append(",");
            });
        }

        //去除最后一个逗号
        return sb.deleteCharAt(sb.length() - 1).toString();
    }

二、表单参数校验

@RestController
@RequestMapping("/args")
@Validated
public class ArgsController {

    @PostMapping("test1")
    public R  validatedTest1(@RequestParam @Pattern(regexp = VerificationUtil.PHONE_REGEXP, message = "手机格式错误") String phone,
                             @RequestParam @NotEmpty(message = "名字不能为空") String name) {

        return R.success(name + "的手机号是" + phone);
    }
}

必须在类上添加@Validated的注解,否则普通表单类型的参数校验不生效。

触发的异常是默认异常处理3:Exception.class,如果没有3异常捕获,则触发6异常Throwable.class

三、实体类参数校验

@Data
public class ArgsDTO {


    private Long id;

    @NotEmpty(message = "名字不能为空!")
    private String name;

    @Pattern(regexp = VerificationUtil.PHONE_REGEXP, message = "手机号格式错误!")
    private String phone;

    @Email(message = "邮箱格式错误!")
    private String email;
}
    @PostMapping("test2")
    public R  validatedTest2(@Validated @RequestBody ArgsDTO argsDTO) {

        return R.success(argsDTO);
    }

 触发的异常是异常1:MethodArgumentNotValidException.class

单单在类上面添加@Validated不生效,需要在实体参数前添加@Validated才生效。类上不添加也可以。

四、对象嵌套

@Data
public class ArgsListDTO {

    private String code;

    @NotEmpty(message = "参数成员不能为空")
    @Valid
    private List<ArgsDTO> argsDTOList;
}
    @PostMapping("test3")
    public R  validatedTest3(@Validated @RequestBody ArgsListDTO argsListDTO) {

        return R.success(argsListDTO);
    }

 需要在嵌套对象添加@Valid才能使嵌套对象里面的属性校验生效

五、分组校验

根据不同的业务场景对同一个属性执行不同的校验规则。比如主键id,添加的时候可以为空,更新的时候不能为空。

public interface AddGroup extends Default {
}
public interface UpdGroup extends Default {
}
@Data
public class ArgsDTO {

    @NotNull(message = "更新id不能为空", groups = UpdGroup.class)
    private Long id;

    @NotEmpty(message = "名字不能为空!", groups = {AddGroup.class, UpdGroup.class})
    private String name;

    @Pattern(regexp = VerificationUtil.PHONE_REGEXP, message = "手机号格式错误!")
    private String phone;

    @Email(message = "邮箱格式错误!")
    private String email;
}
    @PostMapping("test4")
    public R  validatedTest42(@Validated @RequestBody ArgsDTO argsDTO) {

        return R.success(argsDTO);
    }
    @PostMapping("test5")
    public R  validatedTest5(@Validated(value = {AddGroup.class, UpdGroup.class}) @RequestBody ArgsDTO argsDTO) {

        return R.success(argsDTO);
    }

分组AddGroup、UpdGroup必须继承默认默认校验分组,不然实体中没有设置分组的属性不会被校验。比如ArgsDTO中的phone和email字段。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值