亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

詳解Spring Boot2 Webflux的全局異常處理

2024-07-14 08:43:15
字體:
來源:轉載
供稿:網友

本文首先將會回顧Spring 5之前的SpringMVC異常處理機制,然后主要講解Spring Boot 2 Webflux的全局異常處理機制。

SpringMVC的異常處理

Spring 統一異常處理有 3 種方式,分別為:

  • 使用 @ExceptionHandler 注解
  • 實現 HandlerExceptionResolver 接口
  • 使用 @controlleradvice 注解

使用 @ExceptionHandler 注解

用于局部方法捕獲,與拋出異常的方法處于同一個Controller類:

@Controllerpublic class BuzController {  @ExceptionHandler({NullPointerException.class})  public String exception(NullPointerException e) {    System.out.println(e.getMessage());    e.printStackTrace();    return "null pointer exception";  }  @RequestMapping("test")  public void test() {    throw new NullPointerException("出錯了!");  }}

如上的代碼實現,針對 BuzController 拋出的 NullPointerException 異常,將會捕獲局部異常,返回指定的內容。

實現 HandlerExceptionResolver 接口

通過實現 HandlerExceptionResolver 接口,定義全局異常:

@Componentpublic class CustomMvcExceptionHandler implements HandlerExceptionResolver {  private ObjectMapper objectMapper;  public CustomMvcExceptionHandler() {    objectMapper = new ObjectMapper();  }  @Override  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,                     Object o, Exception ex) {    response.setStatus(200);    response.setContentType(MediaType.APPLICATION_JSON_VALUE);    response.setCharacterEncoding("UTF-8");    response.setHeader("Cache-Control", "no-cache, must-revalidate");    Map<String, Object> map = new HashMap<>();    if (ex instanceof NullPointerException) {      map.put("code", ResponseCode.NP_EXCEPTION);    } else if (ex instanceof IndexOutOfBoundsException) {      map.put("code", ResponseCode.INDEX_OUT_OF_BOUNDS_EXCEPTION);    } else {      map.put("code", ResponseCode.CATCH_EXCEPTION);    }    try {      map.put("data", ex.getMessage());      response.getWriter().write(objectMapper.writeValueAsString(map));    } catch (Exception e) {      e.printStackTrace();    }    return new ModelAndView();  }}

如上為示例的使用方式,我們可以根據各種異常定制錯誤的響應。

使用 @controlleradvice 注解

@ControllerAdvicepublic class ExceptionController {  @ExceptionHandler(RuntimeException.class)  public ModelAndView handlerRuntimeException(RuntimeException ex) {    if (ex instanceof MaxUploadSizeExceededException) {      return new ModelAndView("error").addObject("msg", "文件太大!");    }    return new ModelAndView("error").addObject("msg", "未知錯誤:" + ex);  }  @ExceptionHandler(Exception.class)  public ModelAndView handlerMaxUploadSizeExceededException(Exception ex) {    if (ex != null) {      return new ModelAndView("error").addObject("msg", ex);    }    return new ModelAndView("error").addObject("msg", "未知錯誤:" + ex);  }}

和第一種方式的區別在于, ExceptionHandler 的定義和異常捕獲可以擴展到全局。

Spring 5 Webflux的異常處理

webflux支持mvc的注解,是一個非常便利的功能,相比較于RouteFunction,自動掃描注冊比較省事。異常處理可以沿用ExceptionHandler。如下的全局異常處理對于RestController依然生效。

@RestControllerAdvicepublic class CustomExceptionHandler {  private final Log logger = LogFactory.getLog(getClass());  @ExceptionHandler(Exception.class)  @ResponseStatus(code = HttpStatus.OK)  public ErrorCode handleCustomException(Exception e) {    logger.error(e.getMessage());    return new ErrorCode("e","error" );  }}

WebFlux示例

WebFlux提供了一套函數式接口,可以用來實現類似MVC的效果。我們先接觸兩個常用的。

Controller定義對Request的處理邏輯的方式,主要有方面:

  • 方法定義處理邏輯;
  • 然后用@RequestMapping注解定義好這個方法對什么樣url進行響應。

在WebFlux的函數式開發模式中,我們用HandlerFunction和RouterFunction來實現上邊這兩點。

HandlerFunction

HandlerFunction 相當于Controller中的具體處理方法,輸入為請求,輸出為裝在Mono中的響應:

Mono<T> handle(ServerRequest var1);

在WebFlux中,請求和響應不再是WebMVC中的ServletRequest和ServletResponse,而是ServerRequest和ServerResponse。后者是在響應式編程中使用的接口,它們提供了對非阻塞和回壓特性的支持,以及Http消息體與響應式類型Mono和Flux的轉換方法。

@Componentpublic class TimeHandler {  public Mono<ServerResponse> getTime(ServerRequest serverRequest) {    String timeType = serverRequest.queryParam("type").get();    //return ...  }}

如上定義了一個 TimeHandler ,根據請求的參數返回當前時間。

RouterFunction

RouterFunction ,顧名思義,路由,相當于 @RequestMapping ,用來判斷什么樣的url映射到那個具體的 HandlerFunction 。輸入為請求,輸出為Mono中的 Handlerfunction :

Mono<HandlerFunction<T>> route(ServerRequest var1);

針對我們要對外提供的功能,我們定義一個Route。

@Configurationpublic class RouterConfig {  private final TimeHandler timeHandler;  @Autowired  public RouterConfig(TimeHandler timeHandler) {    this.timeHandler = timeHandler;  }  @Bean  public RouterFunction<ServerResponse> timerRouter() {    return route(GET("/time"), req -> timeHandler.getTime(req));  }}

可以看到訪問/time的GET請求,將會由 TimeHandler::getTime 處理。

功能級別處理異常

如果我們在沒有指定時間類型(type)的情況下調用相同的請求地址,例如/time,它將拋出異常。

Mono和Flux APIs內置了兩個關鍵操作符,用于處理功能級別上的錯誤。

使用onErrorResume處理錯誤

還可以使用onErrorResume處理錯誤,fallback方法定義如下:

Mono<T> onErrorResume(Function<? super Throwable, ? extends Mono<? extends T>> fallback);

當出現錯誤時,我們使用fallback方法執行替代路徑:

@Componentpublic class TimeHandler {  public Mono<ServerResponse> getTime(ServerRequest serverRequest) {    String timeType = serverRequest.queryParam("time").orElse("Now");    return getTimeByType(timeType).flatMap(s -> ServerResponse.ok()        .contentType(MediaType.TEXT_PLAIN).syncBody(s))        .onErrorResume(e -> Mono.just("Error: " + e.getMessage()).flatMap(s -> ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).syncBody(s)));  }  private Mono<String> getTimeByType(String timeType) {    String type = Optional.ofNullable(timeType).orElse(        "Now"    );    switch (type) {      case "Now":        return Mono.just("Now is " + new SimpleDateFormat("HH:mm:ss").format(new Date()));      case "Today":        return Mono.just("Today is " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()));      default:        return Mono.empty();    }  }}

在如上的實現中,每當 getTimeByType() 拋出異常時,將會執行我們定義的 fallback 方法。除此之外,我們還可以捕獲、包裝和重新拋出異常,例如作為自定義業務異常:

public Mono<ServerResponse> getTime(ServerRequest serverRequest) {  String timeType = serverRequest.queryParam("time").orElse("Now");  return ServerResponse.ok()      .body(getTimeByType(timeType)          .onErrorResume(e -> Mono.error(new ServerException(new ErrorCode(HttpStatus.BAD_REQUEST.value(),              "timeType is required", e.getMessage())))), String.class);}

使用onErrorReturn處理錯誤

每當發生錯誤時,我們可以使用 onErrorReturn() 返回靜態默認值:

public Mono<ServerResponse> getDate(ServerRequest serverRequest) {  String timeType = serverRequest.queryParam("time").get();  return getTimeByType(timeType)      .onErrorReturn("Today is " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()))      .flatMap(s -> ServerResponse.ok()          .contentType(MediaType.TEXT_PLAIN).syncBody(s));}

全局異常處理

如上的配置是在方法的級別處理異常,如同對注解的Controller全局異常處理一樣,WebFlux的函數式開發模式也可以進行全局異常處理。要做到這一點,我們只需要自定義全局錯誤響應屬性,并且實現全局錯誤處理邏輯。

我們的處理程序拋出的異常將自動轉換為HTTP狀態和JSON錯誤正文。要自定義這些,我們可以簡單地擴展 DefaultErrorAttributes 類并覆蓋其 getErrorAttributes() 方法:

@Componentpublic class GlobalErrorAttributes extends DefaultErrorAttributes {  public GlobalErrorAttributes() {    super(false);  }  @Override  public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {    return assembleError(request);  }  private Map<String, Object> assembleError(ServerRequest request) {    Map<String, Object> errorAttributes = new LinkedHashMap<>();    Throwable error = getError(request);    if (error instanceof ServerException) {      errorAttributes.put("code", ((ServerException) error).getCode().getCode());      errorAttributes.put("data", error.getMessage());    } else {      errorAttributes.put("code", HttpStatus.INTERNAL_SERVER_ERROR);      errorAttributes.put("data", "INTERNAL SERVER ERROR");    }    return errorAttributes;  }  //...有省略}

如上的實現中,我們對 ServerException 進行了特別處理,根據傳入的 ErrorCode 對象構造對應的響應。

接下來,讓我們實現全局錯誤處理程序。為此,Spring提供了一個方便的 AbstractErrorWebExceptionHandler 類,供我們在處理全局錯誤時進行擴展和實現:

@Component@Order(-2)public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { //構造函數  @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, true);    return ServerResponse.status(HttpStatus.OK)        .contentType(MediaType.APPLICATION_JSON_UTF8)        .body(BodyInserters.fromObject(errorPropertiesMap));  }}

這里將全局錯誤處理程序的順序設置為-2。這是為了讓它比 @Order(-1) 注冊的 DefaultErrorWebExceptionHandler 處理程序更高的優先級。

該errorAttributes對象將是我們在網絡異常處理程序的構造函數傳遞一個的精確副本。理想情況下,這應該是我們自定義的Error Attributes類。然后,我們清楚地表明我們想要將所有錯誤處理請求路由到renderErrorResponse()方法。最后,我們獲取錯誤屬性并將它們插入服務器響應主體中。

然后,它會生成一個JSON響應,其中包含錯誤,HTTP狀態和計算機客戶端異常消息的詳細信息。對于瀏覽器客戶端,它有一個whitelabel錯誤處理程序,它以HTML格式呈現相同的數據。當然,這可以是定制的。

小結

本文首先講了Spring 5之前的SpringMVC異常處理機制,SpringMVC統一異常處理有 3 種方式:使用 @ExceptionHandler 注解、實現 HandlerExceptionResolver 接口、使用 @controlleradvice 注解;然后通過WebFlux的函數式接口構建Web應用,講解Spring Boot 2 Webflux的函數級別和全局異常處理機制(對于Spring WebMVC風格,基于注解的方式編寫響應式的Web服務,仍然可以通過SpringMVC統一異常處理實現)。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩美女在线播放| 欧美成人在线免费| 国产精品一二区| 97av在线视频免费播放| 亚洲激情视频在线观看| 亚洲国产精品久久久久| 国产精品xxx视频| 日韩成人免费视频| 欧美性理论片在线观看片免费| 精品人伦一区二区三区蜜桃网站| 国产www精品| 欧美孕妇孕交黑巨大网站| 最近2019年中文视频免费在线观看| 欧美精品一区二区三区国产精品| 国产精品三级美女白浆呻吟| 91色视频在线观看| 国产精品久久久久久av福利软件| 6080yy精品一区二区三区| 欧美精品999| 国产伦精品一区二区三区精品视频| 自拍偷拍亚洲欧美| 中文字幕日韩av| 欧美俄罗斯乱妇| 国产69精品久久久久9999| 日韩精品极品在线观看播放免费视频| 91香蕉国产在线观看| 亚洲欧美在线第一页| 亚洲一区二区在线| 欧美激情啊啊啊| 不卡在线观看电视剧完整版| 欧美午夜xxx| 中文一区二区视频| 毛片精品免费在线观看| 九九热精品视频在线播放| 欧美体内谢she精2性欧美| 日韩在线高清视频| 亚洲另类欧美自拍| 亚洲高清在线观看| 久久福利网址导航| 亚洲片国产一区一级在线观看| 欧美一区视频在线| 超碰91人人草人人干| 欧美最近摘花xxxx摘花| 亚洲国语精品自产拍在线观看| 欧美激情一区二区久久久| 欧美大成色www永久网站婷| 亚洲欧美一区二区激情| 国产91九色视频| 欧洲亚洲免费在线| 欧美黑人巨大xxx极品| 一区二区三区 在线观看视| 国内伊人久久久久久网站视频| 国产视频精品xxxx| 亚洲自拍另类欧美丝袜| 国产精品网红福利| 97超碰蝌蚪网人人做人人爽| 久久人人爽人人爽人人片av高请| 国产精品九九久久久久久久| 国产精品第七十二页| 日日骚av一区| 欧美在线欧美在线| 91影院在线免费观看视频| 最新中文字幕亚洲| 国模吧一区二区三区| 永久555www成人免费| 国产精品视频久久久久| 欧美最猛性xxxxx(亚洲精品)| 高清欧美电影在线| 国产精品扒开腿做爽爽爽视频| 在线电影欧美日韩一区二区私密| 亚洲国产另类 国产精品国产免费| 欧美疯狂做受xxxx高潮| 深夜福利日韩在线看| 成人免费黄色网| 精品久久久久久久久久久久久久| 美日韩丰满少妇在线观看| 黄色成人av在线| 91久久国产精品91久久性色| 综合网日日天干夜夜久久| 久久国产加勒比精品无码| 亚洲精品久久久久中文字幕欢迎你| 91精品在线观| 欧美高清视频一区二区| 国产亚洲精品va在线观看| 日韩欧美在线免费观看| 国产一区二区美女视频| 欧美性xxxx极品高清hd直播| 亚洲自拍小视频免费观看| 久久视频这里只有精品| 国内精品久久久久| 国产日韩综合一区二区性色av| 亚洲国产天堂网精品网站| 亚洲久久久久久久久久| 欧美日韩精品在线视频| 国产欧美日韩最新| 97久久精品在线| 2020欧美日韩在线视频| 在线观看日韩视频| 日韩影视在线观看| 美女国内精品自产拍在线播放| 久久99国产综合精品女同| 国内精品视频久久| 久久精品视频一| 97超级碰碰碰| 日韩欧美亚洲成人| 亚洲午夜久久久影院| 国产欧美一区二区三区在线看| 欧美影院成年免费版| 欧美精品久久久久久久| 97精品一区二区视频在线观看| 久久人人爽人人| 日韩精品久久久久久福利| 成人黄色片网站| 国产一区视频在线播放| 日韩在线免费视频观看| 久久久中文字幕| 成人高清视频观看www| 欧美午夜精品久久久久久浪潮| 久久久精品国产| 亚洲精品99久久久久中文字幕| 中文字幕精品久久久久| 日本三级久久久| 91在线色戒在线| 国产一区私人高清影院| 91丝袜美腿美女视频网站| 欧美一级淫片播放口| 中文字幕日韩在线观看| 91精品国产综合久久久久久久久| 欧美肥老太性生活视频| 亚洲欧洲自拍偷拍| 91精品国产自产在线观看永久| 欧美国产亚洲视频| 国产一区二区三区丝袜| 中文字幕日韩欧美精品在线观看| 日韩在线欧美在线| 亚洲最大成人网色| 亚洲欧美在线免费观看| 国产精品青青在线观看爽香蕉| 欧美激情性做爰免费视频| 欧美美女15p| 亚洲精品日韩在线| 欧美专区在线视频| 欧美大片免费观看在线观看网站推荐| 日本欧美爱爱爱| 亚洲精品98久久久久久中文字幕| 免费99精品国产自在在线| 97人人爽人人喊人人模波多| 精品国产欧美成人夜夜嗨| 欧美日韩国产黄| 国产在线观看不卡| 国产精品激情自拍| 日韩久久免费电影| 国产69久久精品成人| 成人国内精品久久久久一区| 亚洲欧美成人网| 日韩视频免费看| 久久久久久欧美| 中文字幕欧美日韩精品| 精品欧美一区二区三区| 国产精品极品尤物在线观看| 国产伦精品一区二区三区精品视频| 亚洲第一福利网站| 成人午夜激情网| 国产成人+综合亚洲+天堂|