javascript
java flux api,SpringBoot学习系列-WebFlux REST API 全局异常处理
本文內(nèi)容
為什么要全局異常處理?
WebFlux REST 全局異常處理實戰(zhàn)
小結(jié)
摘錄:只有不斷培養(yǎng)好習(xí)慣,同時不斷打破壞習(xí)慣,我們的行為舉止才能夠自始至終都是正確的。
一、為什么要全局異常處理?
前后端分離開發(fā),一般提供 REST API,正常返回會有響應(yīng)體,異常情況下會有對應(yīng)的錯誤碼響應(yīng)。
挺多人咨詢的,Spring Boot MVC 異常處理用切面 @RestControllerAdvice 注解去實現(xiàn)去全局異常處理。那 WebFlux 如何處理異常?如何實現(xiàn)統(tǒng)一錯誤碼異常處理?
全局異常處理的好處:
異常錯誤碼等統(tǒng)一維護(hù)
避免一些重復(fù)代碼
二、WebFlux REST 全局異常處理實戰(zhàn)
下面介紹如何統(tǒng)一攔截異常,進(jìn)行響應(yīng)處理。
2.1 工程信息
運行環(huán)境:JDK 7 或 8,Maven 3.0+
技術(shù)棧:SpringBoot 2.1.3
模塊工程名: 2-x-spring-boot-webflux-handling-errors
工程結(jié)構(gòu):
├── 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
復(fù)制代碼
application.properties 無須配置,默認(rèn)即可
Application Spring Boot 應(yīng)用啟動類,是可以用來啟動 Spring Boot 應(yīng)用。其包含了 @SpringBootApplication 注解和 SpringApplication 類,并調(diào)用 SpringApplication 類的 run() 方法,就可以啟動該應(yīng)用。
具體實現(xiàn)類的關(guān)系圖如下:
2.2 CityRouter 路由器類
城市路由器代碼如下:
@Configuration
public class CityRouter {
@Bean
public RouterFunction routeCity(CityHandler cityHandler) {
return RouterFunctions.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), cityHandler::helloCity);
}
}
復(fù)制代碼
RouterFunctions 對請求路由處理類,即將請求路由到處理器,這將一個 GET 請求 /hello 路由到處理器 cityHandler 的 helloCity 方法上。跟 Spring MVC 模式下的 HandleMapping 類似。
RouterFunctions.route(RequestPredicate, HandlerFunction) 方法,對應(yīng)的 參是請求參數(shù)和處理函數(shù),如果請求匹配,就調(diào) 對應(yīng)的處理器函數(shù)。
2.3 CityHandler 服務(wù)處理類
城市服務(wù)器處理類,代碼如下:
@Component
public class CityHandler {
public Mono helloCity(ServerRequest request) {
return ServerResponse.ok().body(sayHelloCity(request), String.class);
}
private Mono sayHelloCity(ServerRequest request) {
Optional 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());
}
}
復(fù)制代碼
Mono:實現(xiàn)發(fā)布者,并返回 0 或 1 個元素,即單對象。Mono 是響應(yīng)流 Publisher 具有基礎(chǔ) rx 操作符。可以成功發(fā)布元素或者錯誤。用 Mono 作為返回對象,是因為返回包含了一個 ServerResponse 對象,而不是多個元素。
ServerResponse 是對響應(yīng)的封裝,可以設(shè)置響應(yīng)狀態(tài),響應(yīng)頭,響應(yīng)正文。比如 ok 代表的是 200 響應(yīng)碼、MediaType 枚舉是代表這文本內(nèi)容類型、返回的是 String 的對象。
ServerRequest 是對請求的封裝。從請求中拿出 city 的值,如果沒有的話則拋出對應(yīng)的異常。GlobalException 是封裝的全局異常。
Mono.justOrEmpty():從一個 Optional 對象或 null 對象中創(chuàng)建 Mono。
2.4 GlobalError 處理類
如圖:
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);
}
}
復(fù)制代碼
GlobalErrorAttributes 全局異常屬性值類,代碼如下:
@Component
public class GlobalErrorAttributes extends DefaultErrorAttributes {
@Override
public Map getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Map 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;
}
}
復(fù)制代碼
重寫了父類 DefaultErrorAttributes 默認(rèn)錯誤屬性類的 getErrorAttributes 獲取錯誤屬性方法,從服務(wù)請求封裝 ServerRequest 中獲取對應(yīng)的異常。
然后判斷是否是 GlobalException,如果是 CityHandler 服務(wù)處理類拋出的 GlobalException,則返回對應(yīng)的異常的信息。
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 getRoutingFunction(final ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
private Mono renderErrorResponse(final ServerRequest request) {
final Map errorPropertiesMap = getErrorAttributes(request, false);
return ServerResponse.status(HttpStatus.BAD_REQUEST)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(errorPropertiesMap));
}
}
復(fù)制代碼
代碼解析如下:
AbstractErrorWebExceptionHandler 抽象類是用來處理全局錯誤時進(jìn)行擴(kuò)展和實現(xiàn)
@Order 注解標(biāo)記 AspectJ 的切面排序,值越小擁有越高的優(yōu)先級,這里設(shè)置優(yōu)先級偏高。
構(gòu)造函數(shù)將 GlobalErrorAttributes 全局異常屬性值類設(shè)置到 AbstractErrorWebExceptionHandler 抽象類的局部變量中。
重寫 getRoutingFunction 方法,設(shè)置對應(yīng)的 RequestPredicates 和 Mono 服務(wù)響應(yīng)對象
將 GlobalErrorAttributes 的全局異常屬性值 map,設(shè)置到新的 ServerResponse 即可。
到此基本結(jié)束。Spring Boot MVC 錯誤碼如何實戰(zhàn),參考地址:www.bysocket.com/archives/16…
2.5 運行驗證
在 IDEA 中執(zhí)行 Application 類啟動,任意正常模式或者 Debug 模式。然后打開瀏覽器訪問:
http://localhost:8080/hello
復(fù)制代碼
異常界面如下:
可見,這是在 CityHandler 城市服務(wù)處理類邏輯中拋出的全局異常信息。那么正常情況會是如何?
改下 URL ,訪問如下:
http://localhost:8080/hello?city=WenLing
復(fù)制代碼
正常界面如下:
三、小結(jié)
在 Spring 框架中沒有代表錯誤響應(yīng)的類,只是返回響應(yīng)對象,一個 Map。如果需要定義業(yè)務(wù)的錯誤碼返回體,參考錯誤碼如何實戰(zhàn),參考地址:www.bysocket.com/archives/16…
本文重點還是有別于 Spring Boot 傳統(tǒng) MVC 模式統(tǒng)一異常處理,實戰(zhàn)了 WebFlux 全局異常處理機(jī)制。實戰(zhàn)中這塊擴(kuò)展需要考慮:
異常分層,從基類中擴(kuò)展出來
錯誤碼設(shè)計分層,易擴(kuò)展,比如在錯誤碼中新增調(diào)用量字段…
總結(jié)
以上是生活随笔為你收集整理的java flux api,SpringBoot学习系列-WebFlux REST API 全局异常处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: php private方法,php如何调
- 下一篇: down.php无法打开,php下载文件
