本文內容java
摘錄:只有不斷培養好習慣,同時不斷打破壞習慣,咱們的行爲舉止纔可以自始至終都是正確的。git
先後端分離開發,通常提供 REST API,正常返回會有響應體,異常狀況下會有對應的錯誤碼響應。github
挺多人諮詢的,Spring Boot MVC 異常處理用切面 @RestControllerAdvice
註解去實現去全局異常處理。那 WebFlux 如何處理異常?如何實現統一錯誤碼異常處理?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() 方法,就能夠啓動該應用。springboot
具體實現類的關係圖以下:bash
城市路由器代碼以下:服務器
@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。
如圖:
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/archives/1692
在 IDEA 中執行 Application
類啓動,任意正常模式或者 Debug 模式。而後打開瀏覽器訪問:
http://localhost:8080/hello
複製代碼
異常界面以下:
可見,這是在 CityHandler 城市服務處理類邏輯中拋出的全局異常信息。那麼正常狀況會是如何?
改下 URL ,訪問以下:
http://localhost:8080/hello?city=WenLing
複製代碼
正常界面以下:
在 Spring 框架中沒有表明錯誤響應的類,只是返回響應對象,一個 Map。若是須要定義業務的錯誤碼返回體,參考錯誤碼如何實戰,參考地址:https://www.bysocket.com/archives/1692。
本文重點仍是有別於 Spring Boot 傳統 MVC 模式統一異常處理,實戰了 WebFlux 全局異常處理機制。實戰中這塊擴展須要考慮: