瞧瞧人家用SpringBoot写的后端API接口,那叫一个优雅

日常工作中,我们开发接口时,一般都会涉及到参数校验、异常处理、封装结果返回等处理。如果每个后端开发在参数校验、异常处理等都是各写各的,没有统一处理的话,代码就不优雅,也不容易维护。所以,作为一名合格的后端开发工程师,我们需要统一校验参数,统一异常处理、统一结果返回,让代码更加规范、可读性更强、更容易维护。

  • 使用注解,优雅进行参数校验
  • 统一结果返回
  • 统一异常处理
  • 唠叨几句

1. 使用注解,统一参数校验

假设实现一个注册用户的功能,在controller 层,他会先进行校验参数,如下:

@RestController@RequestMappingpublic class UserController { @RequestMapping(“addUser”) public String addUser(UserParam userParam) { if (StringUtils.isEmpty(userParam.getUserName())) { return “用户名不能为空”; } if (StringUtils.isEmpty(userParam.getPhone())) { return “手机号不能为空”; } if (userParam.getPhone().length() > 11) { return “手机号不能超过11”; } if (StringUtils.isEmpty(userParam.getEmail())) { return “邮箱不能为空”; } //省略其他参数校验 //todo 插入用户信息表 return “SUCCESS”; }}

以上代码有什么问题嘛?其实没什么问题,就是校验有点辣眼睛。正常的添加用户业务还没写,参数校验就一大堆啦。假设后来,又接了一个需求:编辑用户信息。实现编辑用户信息前,也是先校验信息,如下:

@RequestMapping(“editUser”)public String editUser(UserParam userParam) { if (StringUtils.isEmpty(userParam.getUserName())) { return “用户名不能为空”; } if (StringUtils.isEmpty(userParam.getPhone())) { return “手机号不能为空”; } if (userParam.getPhone().length() > 11) { return “手机号不能超过11”; } if (StringUtils.isEmpty(userParam.getEmail())) { return “邮箱不能为空”; } //省略其他参数校验 //todo 编辑用户信息表 return “SUCCESS”;}

我们可以使用注解的方式,来进行参数校验,这样代码更加简洁,也方便统一管理。实际上, spring boot有个validation的组件,我们可以拿来即用。引入这个包即可:

org.springframework.boot spring-boot-starter-validation

引入包后,参数校验就非常简洁啦,如下:

public class UserParam { @NotNull(message = “用户名不能为空”) private String userName; @NotNull(message = “手机号不能为空”) @Max(value = 11) private String phone; @NotNull(message = “邮箱不能为空”) private String email;

然后在UserParam参数对象中,加入@Validated注解哈,把错误信息接收到BindingResult对象,代码如下:

@RequestMapping(“addUser”) public String addUser(@Validated UserParam userParam, BindingResult result) { List fieldErrors = result.getFieldErrors(); if (!fieldErrors.isEmpty()) { return fieldErrors.get(0).getDefaultMessage(); } //todo 插入用户信息表 return “SUCCESS”; }

2. 接口统一响应对象返回

如果你在你们项目代码中,看到controller 层报文返回结果,有这样的:

@RequestMapping(“/hello”)public String getStr(){ return “hello,test”;}//返回hello,test

也有这样的:

@RequestMapping(“queryUser”)public UserVo queryUser(String userId) { return new UserVo(“666”, “test”);}//返回:{“userId”:”666″,”name”:”test”}

显然,如果接口返回结果不统一,前端处理就不方便,我们代码也不好维护。再比如有的人喜欢用Result处理结果,有点人喜欢用Response处理结果,可以想象一下,这些代码有多乱。

所以作为后端开发,我们项目的响应结果,需要统一标准的返回格式。一般一个标准的响应报文对象,都有哪些属性呢?

  • code :响应状态
  • message :响应结果描述
  • data:返回的数据

响应状态码一般用枚举表示哈:

public enum CodeEnum { /**操作成功**/ SUCCESS(“0000″,”操作成功”), /**操作失败**/ ERROR(“9999″,”操作失败”),; /** * 自定义状态码 **/ private String code; /**自定义描述**/ private String message; CodeEnum(String code, String message){ this.code = code; this.message = message; } public String getCode() { return code; } public String getMessage() { return message; }}

因为返回的数据类型不是确定的,我们可以使用泛型,如下:

/** * @author kevin * @param */public class BaseResponse { /** * 响应状态码(0000表示成功,9999表示失败 */ private String code; /** * 响应结果描述 */ private String message; /** * 返回的数据 */ private T data; /** * 成功返回 * @param data * @param * @return */ public static BaseResponse success(T data) { BaseResponse response= new BaseResponse(); response.setCode(CodeEnum.SUCCESS.getCode()); response.setMessage(CodeEnum.SUCCESS.getMessage()); response.setData(data); return response; } /** * 失败返回 * @param code * @param message * @param * @return */ public static BaseResponse fail(String code, String message) { BaseResponse response = new BaseResponse(); response.setCode(code); response.setMessage(message); return response; } public void setCode(String code) { this.code = code; } public void setMessage(String message) { this.message = message; } public void setData(T data) { this.data = data; }}

有了统一的响应体,我们就可以优化一下controller 层的代码啦:

@RequestMapping(“/hello”)public BaseResponse getStr(){ return BaseResponse.success(“hello,test”);}//output{“code”:”0000″,”message”:”操作成功”,”data”:”hello,test”}@RequestMapping(“queryUser”)public BaseResponse queryUser(String userId) { return BaseResponse.success(new UserVo(“666”, “test”));}//output{“code”:”0000″,”message”:”操作成功”,”data”:{“userId”:”666″,”name”:”test”}}

3. 统一异常处理

日常开发中,我们一般都是自定义统一的异常类,如下:

public class BizException extends RuntimeException { private String retCode; private String retMessage; public BizException() { super(); } public BizException(String retCode, String retMessage) { this.retCode = retCode; this.retMessage = retMessage; } public String getRetCode() { return retCode; } public String getRetMessage() { return retMessage; }}

在controller 层,很可能会有类似代码:

@RequestMapping(“/query”)public BaseResponse queryUserInfo(UserParam userParam) { try { return BaseResponse.success(userService.queryUserInfo(userParam)); } catch (BizException e) { //doSomething } catch (Exception e) { //doSomething } return BaseResponse.fail(CodeEnum.ERROR.getCode(),CodeEnum.ERROR.getMessage());}

这块代码,没什么问题哈,但是如果try…catch太多,不是很优雅。

可以借助注解@RestControllerAdvice,让代码更优雅。@RestControllerAdvice是一个应用于Controller层的切面注解,它一般配合@ExceptionHandler注解一起使用,作为项目的全局异常处理。我们来看下demo代码哈。

还是原来的UserController,和一个会抛出异常的userService的方法,如下:

@RestControllerpublic class UserController { @Autowired private UserService userService; @RequestMapping(“/query”) public BaseResponse queryUserInfo1(UserParam userParam) { return BaseResponse.success(userService.queryUserInfo(userParam)); }}@Servicepublic class UserServiceImpl implements UserService { //抛出异常 @Override public UserVo queryUserInfo(UserParam userParam) throws BizException { throw new BizException(“6666”, “测试异常类”); }}

我们再定义一个全局异常处理器,用@RestControllerAdvice注解,如下:

@RestControllerAdvice(annotations = RestController.class)public class ControllerExceptionHandler {}

我们有想要拦截的异常类型,比如想拦截BizException类型,就新增一个方法,使用@ExceptionHandler注解修饰,如下:

@RestControllerAdvice(annotations = RestController.class)public class ControllerExceptionHandler { @ExceptionHandler(BizException.class) @ResponseBody public BaseResponse handler(BizException e) { System.out.println(“进入业务异常”+e.getRetCode()+e.getRetMessage()); return BaseResponse.fail(CodeEnum.ERROR.getCode(), CodeEnum.ERROR.getMessage()); }}

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
(0)
用户投稿
上一篇 2022年6月21日
下一篇 2022年6月21日

相关推荐

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息