本文內容java
摘錄:只有不斷培養好習慣,同時不斷打破壞習慣,咱們的行爲舉止纔可以自始至終都是正確的。
先後端分離開發,通常提供 REST API,正常返回會有響應體,異常狀況下會有對應的錯誤碼響應。react
挺多人諮詢的,Spring Boot MVC 異常處理用切面 @RestControllerAdvice
註解去實現去全局異常處理。那 WebFlux 如何處理異常?如何實現統一錯誤碼異常處理?git
全局異常處理的好處:github
下面介紹如何統一攔截異常,進行響應處理。web
工程結構:spring
├── pom.xml └── src └── main ├── java │ └── org │ └── spring │ └── springboot │ ├── Application.java │ ├── error │ │ ├── GlobalErrorAttributes.java │ │ ├── GlobalErrorWebExceptionHandler.java │ │ └── GlobalException.java │ ├── handler │ │ └── CityHandler.java │ └── router │ └── CityRouter.java └── resources └── application.properties
application.properties 無須配置,默認便可
Application Spring Boot 應用啓動類,是能夠用來啓動 Spring Boot 應用。其包含了 @SpringBootApplication 註解和 SpringApplication 類,並調用 SpringApplication 類的 run() 方法,就能夠啓動該應用。後端
具體實現類的關係圖以下:瀏覽器
圖片上傳失敗,見原文 https://www.bysocket.com/archives/2272springboot
城市路由器代碼以下:服務器
@Configuration public class CityRouter { @Bean public RouterFunction<ServerResponse> routeCity(CityHandler cityHandler) { return RouterFunctions.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), cityHandler::helloCity); } }
RouterFunctions 對請求路由處理類,即將請求路由處處理器,這將一個 GET 請求 /hello 路由處處理器 cityHandler 的 helloCity 方法上。跟 Spring MVC 模式下的 HandleMapping 相似。
RouterFunctions.route(RequestPredicate, HandlerFunction) 方法,對應的 參是請求參數和處理函數,若是請求匹配,就調 對應的處理器函數。
城市服務器處理類,代碼以下:
@Component public class CityHandler { public Mono<ServerResponse> helloCity(ServerRequest request) { return ServerResponse.ok().body(sayHelloCity(request), String.class); } private Mono<String> sayHelloCity(ServerRequest request) { Optional<String> cityParamOptional = request.queryParam("city"); if (!cityParamOptional.isPresent()) { throw new GlobalException(HttpStatus.INTERNAL_SERVER_ERROR, "request param city is ERROR"); } return Mono.just("Hello," + cityParamOptional.get()); } }
Mono:實現發佈者,並返回 0 或 1 個元素,即單對象。Mono 是響應流 Publisher 具備基礎 rx 操做符。能夠成功發佈元素或者錯誤。用 Mono 做爲返回對象,是由於返回包含了一個 ServerResponse 對象,而不是多個元素。
ServerResponse 是對響應的封裝,能夠設置響應狀態,響應頭,響應正文。好比 ok 表明的是 200 響應碼、MediaType 枚舉是表明這文本內容類型、返回的是 String 的對象。
ServerRequest 是對請求的封裝。從請求中拿出 city 的值,若是沒有的話則拋出對應的異常。GlobalException 是封裝的全局異常。
Mono.justOrEmpty():從一個 Optional 對象或 null 對象中建立 Mono。
如圖:
圖片上傳失敗,見原文 https://www.bysocket.com/archives/2272
GlobalException 全局異常類,代碼以下:
public class GlobalException extends ResponseStatusException { public GlobalException(HttpStatus status, String message) { super(status, message); } public GlobalException(HttpStatus status, String message, Throwable e) { super(status, message, e); } }
GlobalErrorAttributes 全局異常屬性值類,代碼以下:
@Component public class GlobalErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) { Map<String, Object> map = super.getErrorAttributes(request, includeStackTrace); if (getError(request) instanceof GlobalException) { GlobalException ex = (GlobalException) getError(request); map.put("exception", ex.getClass().getSimpleName()); map.put("message", ex.getMessage()); map.put("status", ex.getStatus().value()); map.put("error", ex.getStatus().getReasonPhrase()); return map; } map.put("exception", "SystemException"); map.put("message", "System Error , Check logs!"); map.put("status", "500"); map.put("error", " System Error "); return map; } }
重寫了父類 DefaultErrorAttributes 默認錯誤屬性類的 getErrorAttributes 獲取錯誤屬性方法,從服務請求封裝 ServerRequest 中獲取對應的異常。
而後判斷是不是 GlobalException,若是是 CityHandler 服務處理類拋出的 GlobalException,則返回對應的異常的信息。
GlobalErrorWebExceptionHandler 全局異常處理類,代碼以下:
@Component @Order(-2) public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { public GlobalErrorWebExceptionHandler(GlobalErrorAttributes g, ApplicationContext applicationContext, ServerCodecConfigurer serverCodecConfigurer) { super(g, new ResourceProperties(), applicationContext); super.setMessageWriters(serverCodecConfigurer.getWriters()); super.setMessageReaders(serverCodecConfigurer.getReaders()); } @Override protected RouterFunction<ServerResponse> getRoutingFunction(final ErrorAttributes errorAttributes) { return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse); } private Mono<ServerResponse> renderErrorResponse(final ServerRequest request) { final Map<String, Object> errorPropertiesMap = getErrorAttributes(request, false); return ServerResponse.status(HttpStatus.BAD_REQUEST) .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject(errorPropertiesMap)); } }
代碼解析以下:
到此基本結束。Spring Boot MVC 錯誤碼如何實戰,參考地址:https://www.bysocket.com/arch...
在 IDEA 中執行 Application
類啓動,任意正常模式或者 Debug 模式。而後打開瀏覽器訪問:
http://localhost:8080/hello
異常界面以下:
圖片上傳失敗,見原文 https://www.bysocket.com/archives/2272
可見,這是在 CityHandler 城市服務處理類邏輯中拋出的全局異常信息。那麼正常狀況會是如何?
改下 URL ,訪問以下:
http://localhost:8080/hello?city=WenLing
正常界面以下:
圖片上傳失敗,見原文 https://www.bysocket.com/archives/2272
在 Spring 框架中沒有表明錯誤響應的類,只是返回響應對象,一個 Map。若是須要定義業務的錯誤碼返回體,參考錯誤碼如何實戰,參考地址:https://www.bysocket.com/arch...。
本文重點仍是有別於 Spring Boot 傳統 MVC 模式統一異常處理,實戰了 WebFlux 全局異常處理機制。實戰中這塊擴展須要考慮:
本文示例讀者能夠經過查看下面倉庫的中的模塊工程名: 2-x-spring-boot-webflux-handling-errors:
若是您對這些感興趣,歡迎 star、follow、收藏、轉發給予支持!