Spring Boot 三招组合拳,手把手教你打出优雅的后端接口

一、前言

一个后端接口大致分为四个部分组成:接口地址(url)、接口请求方式(get、post等)、请求数据(request)、响应数据(response)。如何构建这几个部分每个公司要求都不同,没有什么“一定是最好的”标准,但一个优秀的后端接口和一个糟糕的后端接口对比起来差异还是蛮大的,其中最重要的关键点就是看是否规范!

二、所需依赖包

三、参数校验

一个接口一般对参数(请求数据)都会进行安全校验,参数校验的重要性自然不必多说,那么如何对参数进行校验就有讲究了。

业务层校验

首先我们来看一下最常见的做法,就是在业务层进行参数校验:
public String addUser(User user) {
if (user == null || user.getId() == null || user.getAccount() == null || user.getPassword() == null || user.getEmail() == null) {
return “对象或者对象字段不能为空”;
}
if (StringUtils.isEmpty(user.getAccount()) || StringUtils.isEmpty(user.getPassword()) || StringUtils.isEmpty(user.getEmail())) {
return “不能输入空字符串”;
}
if (user.getAccount().length() 11) {
return “账 长度必须是6-11个字符”;
}
if (user.getPassword().length() 16) {
return “密码长度必须是6-16个字符”;
}
if (!Pattern.matches(“1+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$”, user.getEmail())) {
return “邮箱格式不正确”;
}
// 参数校验完毕后这里就写上业务逻辑
return “success”;
}
这样做当然是没有什么错的,而且格式排版整齐也一目了然。不过这样太繁琐了,这还没有进行业务操作呢光是一个参数校验就已经这么多行代码,实在不够优雅。我们来改进一下,使用 Spring Validator 和 Hibernate Validator 这两套 Validator 来进行方便的参数校验!这两套 Validator 依赖包已经包含在前面所说的 Web 依赖包里了,所以可以直接使用。

Validator + BindResult 进行校验

Validator 可以非常方便的制定校验规则,并自动帮你完成校验。首先在入参里需要校验的字段加上注解,每个注解对应不同的校验规则,并可制定校验失败后的信息:
@Data
public class User {
@NotNull(message = “用户id不能为空”)
private Long id;
@NotNull(message = “用户账 不能为空”)
@Size(min = 6, max = 11, message = “账 长度必须是6-11个字符”)
private String account;
@NotNull(message = “用户密码不能为空”)
@Size(min = 6, max = 11, message = “密码长度必须是6-16个字符”)
private String password;
@NotNull(message = “用户邮箱不能为空”)
@Email(message = “邮箱格式不正确”)
private String email;
}
校验规则和错误提示信息配置完毕后,接下来只需要在接口需要校验的参数上加上 @Valid 注解,并添加 BindResult 参数即可方便完成验证:
@RestController
@RequestMapping(“user”)
public class UserController {
@Autowired
private UserService userService;
@PostMapping(“/addUser”)
public String addUser(@RequestBody @Valid User user, BindingResult bindingResult) {
// 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里
for (ObjectError error : bindingResult.getAllErrors()) {
return error.getDefaultMessage();
}
return userService.addUser(user);
}
}
这样当请求数据传递到接口的时候 Validator 就自动完成校验了,校验的结果就会封装到 BindingResult 中去,如果有错误信息我们就直接返回给前端,业务逻辑代码也根本没有执行下去。此时,业务层里的校验代码就已经不需要了:
public String addUser(User user) {
// 直接编写业务逻辑
return “success”;
}
现在可以看一下参数校验效果。我们故意给这个接口传递一个不符合校验规则的参数,先传递一个错误数据给接口,故意将 password这 个字段不满足校验条件:
{
“account”: “12345678”,
“email”: “123@qq.com”,
“id”: 0,
“password”: “123”
}
再来看一下接口的响应数据:

没错,是直接将整个错误对象相关信息都响应给前端了!这样就很难受,不过解决这个问题也很简单,就是我们接下来要讲的全局异常处理!

四、全局异常处理

参数校验失败会自动引发异常,我们当然不可能再去手动捕捉异常进行处理,不然还不如用之前 BindingResult 方式呢。又不想手动捕捉这个异常,又要对这个异常进行处理,那正好使用 SpringBoot 全局异常处理来达到一劳永逸的效果!

基本使用

首先,我们需要新建一个类,在这个类上加上 @ControllerAdvice 或 @RestControllerAdvice 注解,这个类就配置成全局处理类了(这个根据你的 Controller 层用的是 @Controller 还是 @RestController 来决定)。

然后在类中新建方法,在方法上加上 @ExceptionHandler 注解并指定你想处理的异常类型。接着在方法内编写对该异常的操作逻辑,就完成了对该异常的全局处理!我们现在就来演示一下对参数校验失败抛出的 MethodArgumentNotValidException 全局处理:
@RestControllerAdvice
public class ExceptionControllerAdvice {
@ExceptionHandler(MethodArgumentNotValidException.class)
public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
// 从异常对象中拿到ObjectError对象
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
// 然后提取错误提示信息进行返回
return objectError.getDefaultMessage();
}
}
我们再来看下这次校验失败后的响应数据:

OK,这个异常信息响应就非常好了,状态码和响应说明还有错误提示数据都返给了前端,并且是所有异常都会返回相同的格式!异常这里搞定了,别忘了我们到接口那也要修改返回类型,我们新增一个接口好来看看效果:
@GetMapping(“/getUser”)
public ResultVO getUser() {
User user = new User();
user.setId(1L);
user.setAccount(“12345678”);
user.setPassword(“12345678”);
user.setEmail(“123@qq.com”);
return new ResultVO(user);
}
看一下如果响应正确返回的是什么效果:

成功对数据进行了包装!

注意:beforeBodyWrite 方法里包装数据无法对 String 类型的数据直接进行强转,所以要进行特殊处理,这里不讲过多的细节,有兴趣可以自行深入了解。

六、总结

自此整个后端接口基本体系就构建完毕了。

通过 Validator + 自动抛出异常来完成了方便的参数校验;
通过全局异常处理 + 自定义异常完成了异常操作的规范;
通过数据统一响应完成了响应数据的规范;
多个方面组装非常优雅的完成了后端接口的协调,让开发人员有更多的经历注重业务逻辑代码,轻松构建后端接口。

最后在这里放上此项目的 Github 地址,clone 到本地即可直接运行,并且我将每一次的优化记录都分别做了代码提交,你可以清晰的看到项目的改进过程,如果对你有帮助请在 Github 上点个 star,我还会继续更新很多【项目实践】哦!

GitHub 地址:
github.com/RudeCrab/rude-java/tree/master/project-practice/validation-and-exception-handler

  • END –

最近整理一份面试资料《Java技术栈学习手册》,覆盖了Java技术、面试题精选、Spring全家桶、Nginx、SSM、微服务、数据库、数据结构、架构等等,需要的可以:点击这里!!暗 CSDN


  1. a-zA-Z0-9_- ??

文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92452 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年9月28日
下一篇 2020年9月28日

相关推荐