上文測試開發專題:spring-boot統一異常捕獲咱們討論了java異常以及如何使用Spring-Boot捕獲異常,可是沒有去說捕獲異常後該如何進一步處理,這篇文章咱們將對這個遺留的問題進行討論.html
咱們但願在程序發生異常的時候,可以給用戶返回一個比較友好且明確的信息,對於api接口來講,一種比較好的格式是json,相似於下面這種格式前端
{ "code": "10001", "message": "消息", "uri":"Get /v2/banner" }
因此須要一個對象來描述這種數據格式:java
public class UnifyResponse { private int code; private String message; private String requestUri; public UnifyResponse(int code, String message, String requestUri){ this.code = code; this.message = message; this.requestUri = requestUri; } }
上文咱們談到從開發者的角度來講,異常分爲已知異常和未知異常,針對不一樣的異常使用不一樣的異常處理函數進行處理,咱們以前定義兩個處理函數spring
@ControllerAdvice public class GlobalExceptionAdvice { /** * 處理未知異常 * @param req * @param ex */ @ExceptionHandler(value = Exception.class) public void handleHttpException(HttpServletRequest req, Exception ex){ System.out.println("發生異常了"); } /** * 處理已知異常 * @param req * @param ex */ @ExceptionHandler(value = HttpException.class) public void handleHttpException(HttpServletRequest req, HttpException ex){ System.out.println("發生了 HttpException"); } }
當未知異常發生時,須要將異常信息存儲進 UnifyResponse
,序列化後返回給用戶json
@ExceptionHandler(value = Exception.class) public UnifyResponse handleHttpException(HttpServletRequest req, Exception ex){ String uri = req.getRequestURI(); String method = req.getMethod(); System.out.println(ex.getMessage()); return new UnifyResponse(9999, "服務器錯誤", method + " " + uri); }
對於未知異常咱們也不知道發生了什麼,因此這裏的code碼就定義一個通用的,雖然Exception裏面有message,可是這裏不建議將這個異常裏的message返回給用戶,這位可能涉及到代碼結構的一些東西,並且即便將這個信息返回給前端,他也不知道是啥問題,沒什麼意義,因此能夠將這個message寫到日誌裏,方便後面問題查詢。api
返回給用戶的message能夠自定義一個通用的,好比服務器錯誤什麼的。瀏覽器
咱們來測試一下,在Controller裏拋出一個Exception:服務器
@RequestMapping(value = "/v2/banner", method = {RequestMethod.GET}) public String test() throws Exception{ throw new Exception("我拋出來的"); }
而後再瀏覽器裏訪問,發現出錯了app
這裏的這個異常,看不太懂,回到異常處理方法當中去,咱們直接是返回UnifyResponse對象,若是這裏返回的是一個字符串,那會不會出錯呢,再是試一下看看,結果仍是會報這個錯,也就是說不管這裏返回自定義對象仍是字符串,都會出現問題,那就是說spring-boot壓根兒就可能不識別咱們返回的東西。函數
在spring-boot裏有一個註解@ResponseBody,能夠將咱們的返回值,綁定的響應的body上,咱們來試一下看看可否解決這個問題。
會發現,上面改的返回String是能夠成功的,可是返回UnifyResponse對象仍是報錯,並且報錯和以前的還不同
剛纔報的仍是404的錯誤,如今變成了500,哪裏錯了呢。
咱們來看一下UnifyResponse的定義,咱們定義了三個私有的成員變量,可是確沒有定義getter方法,那在序列化的時候是沒法獲取到成員變量的值的,因此報錯,這裏咱們加上:
而後在運行程序,訪問路由:
返回的響應就和咱們預期的同樣了,可是從上面的圖中,看到返回的狀態碼是200,這顯然是不對的,由於服務器已經出錯了,狀態碼應該是500,因此這裏要對狀態碼進行自定義。
spring-boot提供了兩種能夠自定義狀態碼的方式:
直接在異常處理函數上標記一個叫作
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
並制定狀態碼的枚舉值
重啓程序,訪問路由:
能夠看到狀態碼已經變成500了。
上面使用註解的的形式雖然可以實現咱們的目的,可是這種方式不太靈活,,這裏不少的response的設置都是spring-boot幫咱們作了,若是須要作一些自定義就不是太方便,接下來的這種方式確可讓咱們經過代碼靈活的進行控制。
ResponseEntity是一個泛型類,是能夠直接return回去的,能夠設置不少屬性,包括status、headers、body等。
用ResponseEntity來自定義已知異常處理方法的返回信息:
而後再Controller裏拋出一個NotFoundException,從新運行程序,訪問路由:
能夠看到也可以返回正確的狀態碼。
本篇文章咱們介紹了,定義錯誤響應以及如何返回自定義的錯誤信息,多種方式進行定製狀態碼,可是咱們在文章的錯誤信息都是硬編碼在代碼裏的,這樣很很差管理,因此下篇文章咱們將介紹如何對錯誤信息管理,敬請關注!!!
本文連接:https://www.immortalp.com/articles/2020/05/10/1589096782703.html
歡迎你們去 個人博客 瞅瞅,裏面有更多關於測試實戰的內容哦!!