Spring Boot API 統一返回格式封裝
- 2020 年 11 月 9 日
- 筆記
- Spring-cloud-alibaba
今天給大家帶來的是Spring Boot API 統一返回格式封裝,我們在做項目的時候API 介面返回是需要統一格式的,只有這樣前端的同學才可對介面返回的數據做統一處理,也可以使前後端分離
模式的開發中,只關注於業務,而無需考慮對每一個返回結果做處理,中心思想是,所有結果封裝為json,錯誤資訊通過異常拋出,統一捕捉處理後返回前端,舉例:如果插入一條用戶資訊,而
這個用戶已經在系統中存在,則返回插入失敗,我們用枚舉定義一個返回資訊,通過異常拋出。
**說明:本人沒有公眾號,只要這個部落格,也會對部落格進行持續更新,如果對您有幫助,希望您持續關注**
源碼地址//gitee.com/zgc005/resut
廢話少說 上程式碼
先講項目結構
├── LICENSE
├── demo.iml
├── pom.xml
├── re
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── result
│ │ └── demo
│ │ ├── DemoApplication.java
│ │ ├── common
│ │ │ └── config
│ │ ├── global
│ │ │ ├── advice
│ │ │ │ ├── ExceptionResultAdvice.java ———— 異常捕捉。處理。
│ │ │ │ └── ResponseResultAdvice.java ———— 介面返回統一封裝
│ │ │ ├── annotation
│ │ │ │ └── ResponseResult.java ———— 自定義標籤 用來驗證介面是否需要包裝返回 並且驗證介面是否存在
│ │ │ ├── config
│ │ │ │ └── GlobalConfig.java ———— 全局配置,讀取*.yml 配置文件資訊
│ │ │ ├── enums
│ │ │ │ └── ResultCode.java ———— api異常枚舉
│ │ │ ├── exception
│ │ │ │ └── BizException.java
│ │ │ ├── filterLists
│ │ │ │ ├── FilterConfig.java ———— Filter 配置
│ │ │ │ └── SignAuthFilter.java ———— 介面請求驗簽等操作
│ │ │ ├── interceptor
│ │ │ │ ├── ResponseResultInterceptor.java 用來處理返回數據是否需要封裝
│ │ │ │ └── WebConfigurer.java
│ │ │ ├── result
│ │ │ │ ├── EnumInterface.java
│ │ │ │ └── Result.java
│ │ │ └── sign
│ │ │ ├── BodyReaderHttpServletRequestWrapper.java ————對請求流處理
│ │ │ ├── HttpUtils.java
│ │ │ └── SignUtil.java
│ │ ├── modules
│ │ │ ├── goods
│ │ │ │ ├── controller
│ │ │ │ │ └── GoodsController.java
│ │ │ │ ├── dao
│ │ │ │ │ └── GoodsDao.java
│ │ │ │ ├── entity
│ │ │ │ │ ├── Goods.java
│ │ │ │ │ ├── GoodsBrandBean.java
│ │ │ │ │ ├── GoodsImage.java
│ │ │ │ │ ├── ProductEntity.java
│ │ │ │ │ └── TestName.java
│ │ │ │ └── service
│ │ │ │ ├── GoodsService.java
│ │ │ │ └── impl
│ │ │ │ └── GoodsServiceImpl.java
│ │ │ ├── order
│ │ │ │ ├── controller
│ │ │ │ ├── dao
│ │ │ │ ├── entity
│ │ │ │ └── service
│ │ │ ├── user
│ │ │ │ ├── controller
│ │ │ │ ├── dao
│ │ │ │ ├── entity
│ │ │ │ └── service
│ │ │ └── util
│ │ │ └── JsonTOpagaData.java
│ │ ├── scheduled
│ │ │ ├── ScheduledMachine.java
│ │ │ └── ScheduledProduct.java
│ │ └── test
│ │ ├── Demo.java
│ │ └── Test.java
│ └── resources
│ ├── application-dev.yml
│ ├── application-pro.yml
│ ├── application-test.yml
│ ├── application.yml
│ └── mapper
│ ├── goods
│ │ └── GoodsDao.xml
│ ├── machine
│ │ └── MachineDao.xml
│ ├── order
│ └── user
└── test
└── java
└── com
└── result
└── demo
└── DemoApplicationTests.java
以下是幾個核心的類
- ExceptionResultAdvice :所有的異常都會通個這個類進行捕捉,處理,如果有新增加的Exception 只需要新增方法即可,如新增一個XXXException的方法
@ExceptionHandler(value = XXXException.class)
public Result XXXexceptionHandler(XXXException xxxexception){
log.info("系統異常處理:{}",xxxexception);
return Result.error();
}
- ResponseResultAdvice: 重寫返回數據,這個類主要是對返回結果進行封裝,而不需要在每一個Controller 里的方法進行封裝,簡化程式碼,做到只關注業務。
這裡有一個坑:ResponseBodyAdvice 返回類型如果是String 的話會報錯,原因大家可以自行查看,所以這個地方要對String 類型的數據進行處理
@Override
public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
log.info("進入返回提重寫格式 處理中。。。。。。");
Result result = new Result();
// 包含Result 說明是異常
if (body instanceof Result) {
return body;
}
if (body instanceof String) {
String str = JSON.toJSONString(Result.success(body));
return str;
}
return Result.success(body);
}
- ResponseResult: 這個是自定義的標籤,主要是用來判斷Controller 類的返回數據是否需要封裝用法如下
@Slf4j
@RestController
@RequestMapping(value = "/api")
@ResponseResult
public class Test {
}
在ResponseResultInterceptor 類里會對這個標籤進行判斷處理。
public class ResponseResultInterceptor implements HandlerInterceptor {
public static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";
/**
* 此程式碼核心思想,就是獲取此請求,是否需要返回值包裝,設置一個屬性標記。
*
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 方法校驗
if (handler instanceof HandlerMethod) {
final HandlerMethod handlerMethod = (HandlerMethod) handler;
final Class<?> clazz = handlerMethod.getBeanType();
final Method method = handlerMethod.getMethod();
if (clazz.isAnnotationPresent(ResponseResult.class)) {
request.setAttribute(RESPONSE_RESULT_ANN, clazz.getAnnotation(ResponseResult.class));
} else if (method.isAnnotationPresent(ResponseResult.class)) {
request.setAttribute(RESPONSE_RESULT_ANN, method.getAnnotation(ResponseResult.class));
}
return true;
} else {
return initResponse(response, ResultCode.API_NOT_EXIST);
}
}
private boolean initResponse(HttpServletResponse response,ResultCode resultCode) throws IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", resultCode.getCode());
jsonObject.put("message", resultCode.getMessage());
jsonObject.put("data", null);
writer.write(jsonObject.toString());
return false;
}