您好,登錄后才能下訂單哦!
這篇文章主要介紹了SpringBoot統一響應體解決方案的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
最近在優化自己之前基于Spring AOP的統一響應體的實現方案。
什么是統一響應體呢?在目前的前后端分離架構下,后端主要是一個RESTful API的數據接口。
但是HTTP的狀態碼數量有限,而隨著業務的增長,HTTP狀態碼無法很好地表示業務中遇到的異常情況。
那么可以通過修改響應返回的JSON數據,讓其帶上一些固有的字段,例如以下這樣的
{ "code": 10000, "msg": "success", "data": { "id": 2, "name": "test" } }
其中關鍵屬性的用途如下:
code為返回結果的狀態碼
msg為返回結果的消息
data為返回的業務數據
這3個屬性為固有屬性,每次響應結果都會有帶有它們。
需求
希望實現一個能夠代替基于AOP的實現方案,需要滿足以下幾點:
原有的基于AOP的實現方案需要Controller的返回類型為Object,需要新方案不限制返回類型
原有的基于AOP的實現方案需要通過切面表達式+注解控制切點的Controller(注解的包名修改會導致切面表達式的修改,即需要修改兩處地方),需要新方案能夠基于注解,而不需要修改切面表達式
方案思路
基于上述的需求,選擇使用Spring的Controller增強機制,其中關鍵的類為以下3個:
@ControllerAdvice:類注解,用于指定Controller增強處理器類。
ResponseBodyAdvice:接口,實現后beforeBodyWrite()方法后可以對響應的body進行修改,需要結合@ControllerAdvice使用。
@ExceptionHandler:方法注解,用于指定異常處理方法,需要結合@ControllerAdvice和@ResponseBody使用。
示例關鍵代碼
本示例使用的Spring Boot版本為2.1.6.RELEASE,同時需要開發工具安裝lombok插件
引入依賴
<dependencies> <!--web-starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--test-starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
統一響應體
Controller增強后統一響應體對應的對象
import lombok.AllArgsConstructor; import lombok.Data; import java.io.Serializable; /** * 統一的公共響應體 * @author NULL * @date 2019-07-16 */ @Data @AllArgsConstructor public class ResponseResult implements Serializable { /** * 返回狀態碼 */ private Integer code; /** * 返回信息 */ private String msg; /** * 數據 */ private Object data; }
統一響應注解
統一響應注解是一個標記是否開啟統一響應增強的注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 統一響應注解<br/> * 添加注解后,統一響應體才能生效 * @author NULL * @date 2019-07-16 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface BaseResponse { }
狀態碼枚舉
統一響應體中返回的狀態碼code和狀態信息msg對應的枚舉類
/** * 返回狀態碼 * * @author NULL * @date 2019-07-16 */ public enum ResponseCode { /** * 成功返回的狀態碼 */ SUCCESS(10000, "success"), /** * 資源不存在的狀態碼 */ RESOURCES_NOT_EXIST(10001, "資源不存在"), /** * 所有無法識別的異常默認的返回狀態碼 */ SERVICE_ERROR(50000, "服務器異常"); /** * 狀態碼 */ private int code; /** * 返回信息 */ private String msg; ResponseCode(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
業務異常類
業務異常類是用于識別業務相關的異常,需要注意這個異常類強制需要以ResponseCode作為構造方法入參,這樣可以通過捕獲異常獲得返回的狀態碼信息
import com.rjh.web.response.ResponseCode; import lombok.Data; import lombok.EqualsAndHashCode; /** * 業務異常類,繼承運行時異常,確保事務正常回滾 * * @author NULL * @since 2019-07-16 */ @Data @EqualsAndHashCode(callSuper = false) public class BaseException extends RuntimeException{ private ResponseCode code; public BaseException(ResponseCode code) { this.code = code; } public BaseException(Throwable cause, ResponseCode code) { super(cause); this.code = code; } }
異常處理類
用于處理Controller運行時未捕獲的異常的處理類。
import com.rjh.web.exception.BaseException; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * 異常處理器 * * @author NULL * @since 2019-07-16 */ @ControllerAdvice(annotations = BaseResponse.class) @ResponseBody @Slf4j public class ExceptionHandlerAdvice { /** * 處理未捕獲的Exception * @param e 異常 * @return 統一響應體 */ @ExceptionHandler(Exception.class) public ResponseResult handleException(Exception e){ log.error(e.getMessage(),e); return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null); } /** * 處理未捕獲的RuntimeException * @param e 運行時異常 * @return 統一響應體 */ @ExceptionHandler(RuntimeException.class) public ResponseResult handleRuntimeException(RuntimeException e){ log.error(e.getMessage(),e); return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null); } /** * 處理業務異常BaseException * @param e 業務異常 * @return 統一響應體 */ @ExceptionHandler(BaseException.class) public ResponseResult handleBaseException(BaseException e){ log.error(e.getMessage(),e); ResponseCode code=e.getCode(); return new ResponseResult(code.getCode(),code.getMsg(),null); } }
響應增強類
Conrtoller增強的統一響應體處理類,需要注意異常處理類已經進行了增強,所以需要判斷一下返回的對象是否為統一響應體對象。
import lombok.extern.slf4j.Slf4j; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; /** * 統一響應體處理器 * @author NULL * @date 2019-07-16 */ @ControllerAdvice(annotations = BaseResponse.class) @Slf4j public class ResponseResultHandlerAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter returnType, Class converterType) { log.info("returnType:"+returnType); log.info("converterType:"+converterType); return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if(MediaType.APPLICATION_JSON.equals(selectedContentType) || MediaType.APPLICATION_JSON_UTF8.equals(selectedContentType)){ // 判斷響應的Content-Type為JSON格式的body if(body instanceof ResponseResult){ // 如果響應返回的對象為統一響應體,則直接返回body return body; }else{ // 只有正常返回的結果才會進入這個判斷流程,所以返回正常成功的狀態碼 ResponseResult responseResult =new ResponseResult(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),body); return responseResult; } } // 非JSON格式body直接返回即可 return body; } }
使用示例
首先準備一個User對象
import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serializable; /** * 用戶類 * @author NULL * @date 2019-07-16 */ @Data @EqualsAndHashCode public class User implements Serializable { private Integer id; private String name; }
然后是準備一個簡單的UserController即可
import com.rjh.web.entity.User; import com.rjh.web.exception.BaseException; import com.rjh.web.response.BaseResponse; import com.rjh.web.response.ResponseCode; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 測試用的Controller * * @author NULL * @date 2019-07-16 */ @BaseResponse @RestController @RequestMapping("users") public class UserController { @GetMapping("/{userId}") public User getUserById(@PathVariable Integer userId){ if(userId.equals(0)){ throw new BaseException(ResponseCode.RESOURCES_NOT_EXIST); } if(userId.equals(1)){ throw new RuntimeException(); } User user=new User(); user.setId(userId); user.setName("test"); return user; } }
運行結果
在瀏覽器直接訪問http://127.0.0.1:8080/users/0,則返回結果如下(結果經過格式化處理):
{ "code": 10001, "msg": "資源不存在", "data": null }
在瀏覽器直接訪問http://127.0.0.1:8080/users/1,則返回結果如下(結果經過格式化處理):
{ "code": 50000, "msg": "服務器異常", "data": null }
在瀏覽器直接訪問http://127.0.0.1:8080/users/2,則返回結果如下(結果經過格式化處理):
{ "code": 10000, "msg": "success", "data": { "id": 2, "name": "test" } }
由運行結果可以得知統一響應增強其實已經生效了,而且能夠很好的處理異常。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“SpringBoot統一響應體解決方案的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。