目前开发大都是前后端分离模式,一套规范的接口是非常有必要的,不仅能够提高对接效率,而且能提高代码的可阅读性。本文主要介绍了统一接口数据封装、全局异常处理等。
1、统一接口格式
@Datapublic class Result<T> {private int code;// 状态码private String message;// 提示信息private T data;// 返回数据public Result(int code, String message, T data) {super();this.code = code;this.message = message;this.data = data;}public Result(StatusCode statusCode, T data) {this(statusCode.getCode(), statusCode.getMessage(), data);}public static Result success(Object data) {return new Result(StatusCode.SUCCESS, data);}public static Result error(String message) {return new Result(StatusCode.ERROR, message);}}
@Getter@AllArgsConstructorpublic enum StatusCode {SUCCESS(1, "成功"), ERROR(0, "失败");//...自定义private int code;// 返回码private String message;// 返回结果描述}
@GetMApping("hello")public Result<String> test() { return Result.success("hello");}
{"code":1,"message":"成功","data":"hello"}
如何优雅的实现所有的接口都统一格式?
采用ResponseBodyAdvice技术来实现response的统一格式 springboot提供了ResponseBodyAdvice来帮我们处理ResponseBodyAdvice的作用:拦截Controller方法的返回值,统一处理返回值/响应体,一般用来做response的统一格式、加解密、签名等。
@RestControllerAdvice@ControllerAdvice(basePackages = "com.test.controller")public class MyResponseAdvice implements ResponseBodyAdvice<Object> {@Autowiredprivate ObjectMapper objectMapper;@Overridepublic boolean supports(MethodParameter returnType,Class<? extends HttpMessageConverter<?>> converterType) {return true;}/** * 处理返回结果,可以对结果加密 */@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType,MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request, ServerHttpResponse response) {// 处理字符串类型数据if (body instanceof String) {try {return objectMapper.writeValueAsString(Result.success(body));} catch (JsonProcessingException e) {e.printStackTrace();}}// 返回类型是否已经封装if (body instanceof Result) {return body;}return Result.success(body);}}
@GetMapping("test")public String test2() {return "使用advice";}
{"code":1,"message":"成功","data":"使用advice"}
注意:在使用@ControllerAdvice时,要加上basePackages,@ControllerAdvice(basePackages = "com.test.controller"),如果不加的话,在使用swagger时会出现空白页异常。
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.21</version></dependency>
2、实现全局异常处理
@RestControllerAdvicepublic class GlobalExceptionHandler {/** * 参数异常拦截 (model里的) */@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseBodypublic Result handle(MethodArgumentNotValidException e) {FieldError fieldError = e.getBindingResult().getFieldError();String field = fieldError.getField();String message = fieldError.getDefaultMessage();// 具体出错信息String messageAll = String.format("%s:%s", field, message);return Result.error(messageAll);}/** * * 参数异常拦截 (方法上的) */@ExceptionHandler(ConstrAIntViolationException.class)@ResponseBodypublic Result constraintViolationException(ConstraintViolationException e) {StringBuilder builder = new StringBuilder();Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();for (ConstraintViolation<?> constraintViolation : constraintViolations) {String message = constraintViolation.getMessage();builder.append(message);}return Result.error(builder.toString());}/** * 其他异常 */@ExceptionHandler@ResponseBodypublic Result handleException(Exception e) {return Result.error(e.getMessage());}
@Entity@Table(name = "user")@Datapublic class User implements Serializable {@Column(name = "username")@Size(max = 10)@ApiModelProperty(value = "用户名")private String username;......}@PostMapping("add")@ApiOperation("添加用户")public Result<User> add(@RequestBody @Validated User u) {User user = userService.save(u);return Result.success(user);}
{ "code": 0, "message": "失败", "data": "username:个数必须在0和10之间"}
这样,就实现了统一接口数据封装、全局异常处理。