目前開發大都是前后端分離模式,一套規范的接口是非常有必要的,不僅能夠提高對接效率,而且能提高代碼的可閱讀性。本文主要介紹了統一接口數據封裝、全局異常處理等。
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;// 返回結果描述}
- 在Controller中使用封裝對象
@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時會出現空白頁異常。
- 加密可以使用Hutool-crypto加密工具,封裝了常用的加密加密方法,直接調用。
<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());}
- 測試 實體user屬性username 長度最大是10
@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之間"}
這樣,就實現了統一接口數據封裝、全局異常處理。