目錄
一:統一結果返回
1:統一結果返回寫法
2:String類型報錯問題
解決方法
二:統一異常返回
統一異常返回寫法
三:總結
同志們,今天咱來講一講統一格式返回啊,也是好久沒有講過統一格式返回了,說實話這個統一格式返回就是一個讓咱返回的數據能有一個統一的格式嘛,不為別的就為了和你一塊共事的同事不會提著刀追著你滿大街跑,要跟你交流交流工作經驗。
前端:我這數據咋老是對不上啊?
后端:奧兄弟,這個接口我返回的是Boolean類型
前端:我這數據怎么又對不上了啊?
后端:奧好兄弟,我覺得Boolean類型太丑了我就換成String類型了,我覺得它順眼點。
前端:
那咱肯定不能讓同事追著我們交流經驗啊,所以我們一定要讓咱返回的數據能有一個統一的格式
一:統一結果返回
1:統一結果返回寫法
定義返回模板
想要統一返回一個結果,就肯定要有一個返回結果的模板這里我們用Result類來定義
下面代碼中有Result有三個屬性,狀態碼,錯誤信息,返回的數據,三個方法分別是成功時返回,和失敗時返回。
@Data
public class Result<T> {private Integer code;//后端響應狀態碼,成功200,失敗-1,-2表示未登錄private String errmsg;//后端發生錯誤的原因private T data;//每個接口返回的類型(BookInfo,boolean之類的,類型不固定所以要用泛型)/** 成功時設置* */public static<T> Result<T> success(T data){//泛型方法加static需要加上<T>Result result = new Result<>();result.setData(data);result.setCode(200);return result;}/*失敗時設置* */public static<T> Result<T> fail(String errMsg){Result result = new Result<>();result.setCode(-1);result.setErrmsg(errMsg);return result;}public static<T> Result<T> fail(T data,String errMsg){Result result = new Result<>();result.setData(data);result.setCode(-1);result.setErrmsg(errMsg);return result;}
}
實現ResponseBodyAdvice接口并重寫方法,再加上@ControllerAdvice注解
@ControllerAdvice:這個注解的作用就是標記這個類為全局控制器增強類
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {return Result.success(body);//返回封裝后結果結果}
}
support()方法:
作用:
supports 方法用于判斷是否需要對某個返回值進行處理,返回true就是處理,返回false就是不處理
參數解析:
returnType:這個參數就是表示控制器方法(Controller類)的返回類型信息,它封裝的有方法的返回參數的詳細信息,比如方法本身,方法所屬的類,返回的類型等等...可以根據這些信息來決定是否要對返回值進行處理,返回對應的true或false
Class converterType:這個參數的意思就是用于將響應體對象,轉換為,HTTP響應消息的那個消息轉換器的類型,后面我們會說到,先按下不表
beforeBodyWrite()方法:
作用:
我們直譯一下這個方法的名字是:寫 body 之前 ,意思就是在控制器方法返回之前進行的處理
當support方法返回true之后,beforeBodyWrite()方法就需要對返回值進行一些處理
參數解析:
Object body:該參數表示控制器方法實際返回的響應體對象
MethodParameter returnType:同supports方法中的returnType
?MediaType selectedContentType:表示響應的類型,如application/json
?Class selectedConverterType:表示用于將響應體對象轉換為 HTTP 響應的消息轉換器的類型
?request和response:這個我們很熟悉,就是代表Http的請求和響應
我們定義幾個簡單的控制器類
@RestController
public class Controller {@RequestMapping("/t1")public int t1(){return 1;}@RequestMapping("/t2")public Boolean t2(){return true;}@RequestMapping("/t2")public String t3(){return "老皇甫";}
}
然后啟動項目測試發現
t1和t2方法沒問題,都對控制器的返回結果進行了封裝,但是返回String類型的t3卻報錯了,這是為什么呢?
?
2:String類型報錯問題
首先明確一點,這個報錯的原因是類型不匹配問題,報的是ClassCastException
我黃色框框里面框的翻譯一下就是Result類型和String類型不匹配,那么為什么呢?
還記得我在解釋方法的參數的時候那個先按下不表的Class converterType?參數嗎?converterType的意思是轉換器類型,SpringMVC默認會注冊?些?帶的 HttpMessageConverter(Http消息轉換器),它是以鏈表的形式組織的,它們的順序是
ByteArrayHttpMessageConverter()->StringHttpMessageConverter() ->SourceHttpMessageConverter<>()->AllEncompassingFormHttpMessageConverter()
?其中這個AllEncompassingFormHttpMessageConverter()是根據項目的依賴情況來添加對應的轉換器的,如果我們添加了Jackson依賴一般會添加MappingJackson2HttpMessageConverter()轉換器到消息轉換器鏈表的末尾
我們下面調用的堆棧信息中也發現,最后AbstractMessageConverterMethodProcessor調用的也是StringHttpMessageConverter
這里是AbstractMessageConverterMethodProcessor中的邏輯,body在經過beforeBody方法包裝過之后,就會從String類型變為Result類型,但現在匹配到的還是StringHttpMessageConverter 消息轉換器
我們點進去這個?StringHttpMessageConverter 的write方法中看一下(點擊那個由AbstractHttpMessageConverter實現的
)發現里面有一個addDefaultHeader方法(由?StringHttpMessageConverter實現的),再點進去這個方法,發現這個方法接收到的是String參數,但在上面的我們在beforBodyWrite方法中已經將參數轉換為了Result類型,所以才會報出類型不匹配異常
解決方法
既然是因為參數不匹配導致的錯誤,那就只需要將參數搞成匹配的就行了,如下圖所示,如果返回的是字符串類型,那么就將返回類型序列化成字符串類型,而不是Result類型
?
我知道同志們有時候看源碼很懵,不知道哪個調用哪個,這里可以說一下在控制臺打印的日志中,調用的順序一般就是下面的調用上面的,一層一層的,Spring的調用鏈幾乎都有十幾層,所以看的很懵是很正常的?
二:統一異常返回
還有一個問題,不知道同志們發現沒有,就是上面我們在由于String類型不匹配報錯的時候哪個返回結果狀態碼竟然還是200,但這個200可是成功的狀態碼,這都報錯了,那狀態碼肯定能是200啊,所以這個返回結果肯定是不正確的。
統一異常返回寫法
這時候我們就需要通過統一異常捕獲,構造出另一種返回結果失敗的格式,來返回我們可以用
@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {@ExceptionHandler(Exception.class)//捕獲所有異常public Result handleException(Exception e) {return Result.fail(e.getMessage()+"異常");}@ExceptionHandler(Error.class)//捕獲error類型public Result handleError(Error e) {return Result.fail(e.getMessage()+"錯誤");}@ExceptionHandler(RuntimeException.class)//捕獲運行時異常public Result handleRuntimeException(RuntimeException e) {return Result.fail(e.getMessage()+"運行時異常");}@ExceptionHandler(NullPointerException.class)//捕獲空指針異常public Result handleNullPointerException(NullPointerException e) {return Result.fail(e.getMessage()+"空指針異常");}}
我們來認為制造幾個異常
查看測試結果
狀態碼為-1,返回結果符合預期
三:總結
這篇我們說的也不多,大概就是說了一下
為什么要進行統一的格式返回,
然后統一格式返回的寫法
再是String類型會報錯的問題以及源碼級別的原因,
然后是統一異常返回問題