SpringBoot写后端接口,看这一篇就够了( 二 )

这样当请求数据传递到接口的时候Validator就自动完成校验了 , 校验的结果就会封装到BindingResult中去 , 如果有错误信息我们就直接返回给前端 , 业务逻辑代码也根本没有执行下去 。
此时 , 业务层里的校验代码就已经不需要了:
public String addUser(User user) {// 直接编写业务逻辑return "success"; }现在可以看一下参数校验效果 。 我们故意给这个接口传递一个不符合校验规则的参数 , 先传递一个错误数据给接口 , 故意将password这个字段不满足校验条件:
{"account": "12345678","email": "123@qq.com","id": 0,"password": "123"}再来看一下接口的响应数据:
这样是不是方便很多?不难看出使用Validator校验有如下几个好处:
(1)简化代码 , 之前业务层那么一大段校验代码都被省略掉了 。
(2)使用方便 , 那么多校验规则可以轻而易举的实现 , 比如邮箱格式验证 , 之前自己手写正则表达式要写那么一长串 , 还容易出错 , 用Validator直接一个注解搞定 。 (还有更多校验规则注解 , 可以自行去了解哦)
(3)减少耦合度 , 使用Validator能够让业务层只关注业务逻辑 , 从基本的参数校验逻辑中脱离出来 。
使用Validator+ BindingResult已经是非常方便实用的参数校验方式了 , 在实际开发中也有很多项目就是这么做的 , 不过这样还是不太方便 , 因为你每写一个接口都要添加一个BindingResult参数 , 然后再提取错误信息返回给前端 。
这样有点麻烦 , 并且重复代码很多(尽管可以将这个重复代码封装成方法) 。 我们能否去掉BindingResult这一步呢?当然是可以的!
Validator + 自动抛出异常我们完全可以将BindingResult这一步给去掉:
@PostMapping("/addUser")public String addUser(@RequestBody @Valid User user) {return userService.addUser(user);}去掉之后会发生什么事情呢?直接来试验一下 , 还是按照之前一样故意传递一个不符合校验规则的参数给接口 。 此时我们观察控制台可以发现接口已经引发MethodArgumentNotValidException异常了:
其实这样就已经达到我们想要的效果了 , 参数校验不通过自然就不执行接下来的业务逻辑 , 去掉BindingResult后会自动引发异常 , 异常发生了自然而然就不会执行业务逻辑 。 也就是说 , 我们完全没必要添加相关BindingResult相关操作嘛 。
不过事情还没有完 , 异常是引发了 , 可我们并没有编写返回错误信息的代码呀 , 那参数校验失败了会响应什么数据给前端呢?
我们来看一下刚才异常发生后接口响应的数据:
没错 , 是直接将整个错误对象相关信息都响应给前端了!这样就很难受 , 不过解决这个问题也很简单 , 就是我们接下来要讲的全局异常处理!
全局异常处理参数校验失败会自动引发异常 , 我们当然不可能再去手动捕捉异常进行处理 , 不然还不如用之前BindingResult方式呢 。 又不想手动捕捉这个异常 , 又要对这个异常进行处理 , 那正好使用SpringBoot全局异常处理来达到一劳永逸的效果!
基本使用首先 , 我们需要新建一个类 , 在这个类上加上@ControllerAdvice或@RestControllerAdvice注解 , 这个类就配置成全局处理类了 。 (这个根据你的Controller层用的是@Controller还是@RestController来决定)
然后在类中新建方法 , 在方法上加上@ExceptionHandler注解并指定你想处理的异常类型 , 接着在方法内编写对该异常的操作逻辑 , 就完成了对该异常的全局处理!
我们现在就来演示一下对参数校验失败抛出的MethodArgumentNotValidException全局处理:
@RestControllerAdvicepublic class ExceptionControllerAdvice {@ExceptionHandler(MethodArgumentNotValidException.class)public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {// 从异常对象中拿到ObjectError对象ObjectError objectError = e.getBindingResult().getAllErrors().get(0);// 然后提取错误提示信息进行返回return objectError.getDefaultMessage();} }