我們知道在開發,規范化的開發會節省很多時間,無論是代碼規范還是接口規范,如果你們的開發模式是前后端分離的,那你要和前端開發工程師進行對接,不可能因為每個人的代碼風格不統一來進行更改,統一的規范會讓我們在開發過程事半功倍,下面就看看如何統一處理響應體。
【注意】在編寫實體類的時候 為了簡潔 ,我使用了 lombok 用 @Data 、@Setter 、@Getter 取消了get set 方法,如果你們覺得不習慣,可以自己手動添加。
以下對響應體的處理,不是絕對唯一的,可根據自己的業務需要,自己定義對應的響應方式。
一、定義一個響應實體類
定義了響應的實體類,code 代表響應狀態碼,msg代表響應信息,data 代表響應的具體數據 ,這里使用了泛型,為了可以更好的兼容不同類型的返回數據。
package com.dongl.utils.response; import lombok.Data; /** * @author D-L * @Version 1.0 * @Description 響應體實體類 * @Date 2020/8/26 */ @Data public class ResultVO<T> { /** * 狀態碼,比如200代表響應成功 */ private int code; /** * 響應信息,用來說明響應情況 */ private String msg; /** * 響應的具體數據 */ private T data; public ResultVO(T data) { this(ResultCode.SUCCESS, data); } public ResultVO(ResultCode resultCode, T data) { this.code = resultCode.getCode(); this.msg = resultCode.getMsg(); this.data = data; } }
二、定義一個響應狀態碼枚舉類(統一響應狀態)
這個響應狀態碼可以自己根據具體的業務自行定義:
package com.dongl.utils.response; import lombok.Getter; /** * @author D-L * @Version 1.0 * @Description 響應狀態碼枚舉類 * @Date 2020/8/26 */ @Getter public enum ResultCode { SUCCESS(200, "操作成功"), FAILED(1001, "響應失敗"), VALIDATE_FAILED(1002, "參數校驗失敗"), ERROR(5000, "未知錯誤"); private int code; private String msg; ResultCode(int code, String msg) { this.code = code; this.msg = msg; } }
還記得之前寫過一篇 《如何優雅的處理SpringBoot接口中參數校驗》其中有對異常的全局處理,這里可以對返回的響應數據進一步處理:
package com.dongl.utils.error; import com.dongl.utils.response.ResultCode; import com.dongl.utils.response.ResultVO; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * @author D-L * @Classname ExceptionControllerAdvice * @Version 1.0 * @Description 全局處理參數校驗異常返回提示 * @Date 2020/8/26 */ @RestControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler(APIException.class) public ResultVO<String> APIExceptionHandler(APIException e) { // 注意哦,這里傳遞的響應碼枚舉 return new ResultVO<>(ResultCode.FAILED, e.getMsg()); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResultVO<String> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { ObjectError objectError = e.getBindingResult().getAllErrors().get(0); // 注意哦,這里傳遞的響應碼枚舉 return new ResultVO<>(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage()); } }
返回響應體:
{ "code": 1002, "msg": "參數校驗失敗", "data": "需要在20和99之間" }
三、全局配置響應體(這里需要加上掃描的包)
這樣定義完了響應體,就需要你在編寫代碼的同時,每一個接口都要添加對應的code msg data ,雖然勉強說的過去,但是總感覺差點意思,當然我們可以統一處理,先創建一個類加上注解使其成為全局處理類。然后繼承ResponseBodyAdvice接口重寫其中的方法,即可對我們的controller進行增強操作。
package com.dongl.utils.response; import com.dongl.utils.error.APIException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; /** * @author D-L * @date 2020-08-27 * @Description 全局配置 響應體 * Version 1.0 */ @RestControllerAdvice(basePackages = {"com.dongl.controller"}) // 注意哦,這里要加上需要掃描的包 public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> aClass) { // 如果接口返回的類型本身就是ResultVO那就沒有必要進行額外的操作,返回false return !returnType.getGenericParameterType().equals(ResultVO.class); } @Override public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) { // String類型不能直接包裝,所以要進行些特別的處理 if (returnType.getGenericParameterType().equals(String.class)) { ObjectMapper objectMapper = new ObjectMapper(); try { // 將數據包裝在ResultVO里后,再轉換為json字符串響應給前端 return objectMapper.writeValueAsString(new ResultVO<>(data)); } catch (JsonProcessingException e) { throw new APIException("返回String類型錯誤"); } } // 將原本的數據包裝在ResultVO里 return new ResultVO<>(data); } }
【總結】響應體的定義,以及狀態碼的定義,都可以自己根據自己的需要和業務的需要自行編寫。