Spring Boot API 統一返回格式封裝

今天給大家帶來的是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;
    }

小結:對於面向對象編程的邏輯思維要始終貫穿於整個項目,對象的封裝也是必然,一個類是對象,多個類組成的模組也是對象,甚至在龐大的系統中,每一個子系統都是一個對象,這也就是OOP的核心 ,一切皆對象,所以沒有對象的同學要抓緊時間找個對象,只有這樣你才會知道如何面向對象!!!