自动校验参数真的是一项非常必要、非常有意义的工作 。JSR303 提供了丰富的参数校验规则,再加上复杂业务的自定义校验规则,完全把参数校验和业务逻辑解耦开,代码更加简洁,符合单一职责原则 。
更多关于 Spring 参数校验请参考:
https://juejin.cn/post/6856541106626363399自定义异常与统一拦截异常原来的代码中可以看到有几个问题
- 抛出的异常不够具体,只是简单地把错误信息放到了 Exception 中
- 抛出异常后,Controller 不能具体地根据异常做出反馈
- 虽然做了参数自动校验,但是异常返回结构和正常返回结构不一致
而统一拦截异常的目的一个是为了可以与前面定义下来的统一包装返回结构能对应上,另一个是我们希望无论系统发生什么异常,Http 的状态码都要是 200 ,尽可能由业务来区分系统的异常
//自定义异常public class ForbiddenException extends RuntimeException {public ForbiddenException(String message) {super(message);}}//自定义异常public class BusinessException extends RuntimeException {public BusinessException(String message) {super(message);}}//统一拦截异常@RestControllerAdvice(basePackages = "com.example.demo")public class ExceptionAdvice {/*** 捕获 {@code BusinessException} 异常*/@ExceptionHandler({BusinessException.class})public Result<?> handleBusinessException(BusinessException ex) {return Result.failed(ex.getMessage());}/*** 捕获 {@code ForbiddenException} 异常*/@ExceptionHandler({ForbiddenException.class})public Result<?> handleForbiddenException(ForbiddenException ex) {return Result.failed(ResultEnum.FORBIDDEN);}/*** {@code @RequestBody} 参数校验不通过时抛出的异常处理*/@ExceptionHandler({MethodArgumentNotValidException.class})public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {BindingResult bindingResult = ex.getBindingResult();StringBuilder sb = new StringBuilder("校验失败:");for (FieldError fieldError : bindingResult.getFieldErrors()) {sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");}String msg = sb.toString();if (StringUtils.hasText(msg)) {return Result.failed(ResultEnum.VALIDATE_FAILED.getCode(), msg);}return Result.failed(ResultEnum.VALIDATE_FAILED);}/*** {@code @PathVariable} 和 {@code @RequestParam} 参数校验不通过时抛出的异常处理*/@ExceptionHandler({ConstraintViolationException.class})public Result<?> handleConstraintViolationException(ConstraintViolationException ex) {if (StringUtils.hasText(ex.getMessage())) {return Result.failed(ResultEnum.VALIDATE_FAILED.getCode(), ex.getMessage());}return Result.failed(ResultEnum.VALIDATE_FAILED);}/*** 顶级异常捕获并统一处理,当其他异常无法处理时候选择使用*/@ExceptionHandler({Exception.class})public Result<?> handle(Exception ex) {return Result.failed(ex.getMessage());}}
总结做好了这一切改动后,可以发现 Controller 的代码变得非常简洁,可以很清楚地知道每一个参数、每一个 DTO 的校验规则,可以很明确地看到每一个 Controller 方法返回的是什么数据,也可以方便每一个异常应该如何进行反馈这一套操作下来后,我们能更加专注于业务逻辑的开发,代码简洁、功能完善,何乐而不为呢?
原文链接:
https://mp.weixin.qq.com/s/KA1gwlup0uybaJR0PbGFyw
推荐阅读
- Log4j漏洞对静态代码测试工具Helix QAC的影响
- PanGu-Coder:函数级的代码生成模型
- 阿里巴巴|支付宝董事长变更!花名"苗人凤" 第一行代码就是他写的
- 董事长|宁德时代突发高层变动:副董事长辞职 曾毓群披挂总经理
- 罗永浩|真还传2.0?罗永浩因买卖合同纠纷被起诉 退出管理层
- 购房置业|专家们,求求了,你们先了解底层疾苦吧!
- 不粘锅的涂层有毒吗 不粘锅有毒吗
- 谷歌|Chrome新版标签页被指存在广告:一行代码快速清除
- 蘸料|实用干货——夏季皮肤为什么要深层清洁?
- 肚皮舞教程 肚皮舞中有哪些层次动作 肚皮舞教程 学会怎么练呼吸