欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2018年12月19日 11:08:27   作者:Aoho''s Blog  
這篇文章主要介紹了詳解Spring Boot2 Webflux的全局異常處理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

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

SpringMVC的異常處理

Spring 統(tǒng)一異常處理有 3 種方式,分別為:

  • 使用 @ExceptionHandler 注解
  • 實(shí)現(xiàn) HandlerExceptionResolver 接口
  • 使用 @controlleradvice 注解

使用 @ExceptionHandler 注解

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

@Controller
public 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("出錯(cuò)了!");
  }
}

如上的代碼實(shí)現(xiàn),針對(duì) BuzController 拋出的 NullPointerException 異常,將會(huì)捕獲局部異常,返回指定的內(nèi)容。

實(shí)現(xiàn) HandlerExceptionResolver 接口

通過實(shí)現(xiàn) HandlerExceptionResolver 接口,定義全局異常:

@Component
public 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();
  }
}

如上為示例的使用方式,我們可以根據(jù)各種異常定制錯(cuò)誤的響應(yīng)。

使用 @controlleradvice 注解

@ControllerAdvice
public 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", "未知錯(cuò)誤:" + 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", "未知錯(cuò)誤:" + ex);

  }
}

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

Spring 5 Webflux的異常處理

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

@RestControllerAdvice
public 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提供了一套函數(shù)式接口,可以用來實(shí)現(xiàn)類似MVC的效果。我們先接觸兩個(gè)常用的。

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

  • 方法定義處理邏輯;
  • 然后用@RequestMapping注解定義好這個(gè)方法對(duì)什么樣url進(jìn)行響應(yīng)。

在WebFlux的函數(shù)式開發(fā)模式中,我們用HandlerFunction和RouterFunction來實(shí)現(xiàn)上邊這兩點(diǎn)。

HandlerFunction

HandlerFunction 相當(dāng)于Controller中的具體處理方法,輸入為請(qǐng)求,輸出為裝在Mono中的響應(yīng):

Mono<T> handle(ServerRequest var1);

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

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

如上定義了一個(gè) TimeHandler ,根據(jù)請(qǐng)求的參數(shù)返回當(dāng)前時(shí)間。

RouterFunction

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

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

針對(duì)我們要對(duì)外提供的功能,我們定義一個(gè)Route。

@Configuration
public 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請(qǐng)求,將會(huì)由 TimeHandler::getTime 處理。

功能級(jí)別處理異常

如果我們?cè)跊]有指定時(shí)間類型(type)的情況下調(diào)用相同的請(qǐng)求地址,例如/time,它將拋出異常。

Mono和Flux APIs內(nèi)置了兩個(gè)關(guān)鍵操作符,用于處理功能級(jí)別上的錯(cuò)誤。

使用onErrorResume處理錯(cuò)誤

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

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

當(dāng)出現(xiàn)錯(cuò)誤時(shí),我們使用fallback方法執(zhí)行替代路徑:

@Component
public 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();
    }
  }
}

在如上的實(shí)現(xiàn)中,每當(dāng) getTimeByType() 拋出異常時(shí),將會(huì)執(zhí)行我們定義的 fallback 方法。除此之外,我們還可以捕獲、包裝和重新拋出異常,例如作為自定義業(yè)務(wù)異常:

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處理錯(cuò)誤

每當(dāng)發(fā)生錯(cuò)誤時(shí),我們可以使用 onErrorReturn() 返回靜態(tài)默認(rèn)值:

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));
}

全局異常處理

如上的配置是在方法的級(jí)別處理異常,如同對(duì)注解的Controller全局異常處理一樣,WebFlux的函數(shù)式開發(fā)模式也可以進(jìn)行全局異常處理。要做到這一點(diǎn),我們只需要自定義全局錯(cuò)誤響應(yīng)屬性,并且實(shí)現(xiàn)全局錯(cuò)誤處理邏輯。

我們的處理程序拋出的異常將自動(dòng)轉(zhuǎn)換為HTTP狀態(tài)和JSON錯(cuò)誤正文。要自定義這些,我們可以簡單地?cái)U(kuò)展 DefaultErrorAttributes 類并覆蓋其 getErrorAttributes() 方法:

@Component
public 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;
  }
  //...有省略
}

如上的實(shí)現(xiàn)中,我們對(duì) ServerException 進(jìn)行了特別處理,根據(jù)傳入的 ErrorCode 對(duì)象構(gòu)造對(duì)應(yīng)的響應(yīng)。

接下來,讓我們實(shí)現(xiàn)全局錯(cuò)誤處理程序。為此,Spring提供了一個(gè)方便的 AbstractErrorWebExceptionHandler 類,供我們?cè)谔幚砣皱e(cuò)誤時(shí)進(jìn)行擴(kuò)展和實(shí)現(xiàn):

@Component
@Order(-2)
public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

 //構(gòu)造函數(shù)
  @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));
  }
}

這里將全局錯(cuò)誤處理程序的順序設(shè)置為-2。這是為了讓它比 @Order(-1) 注冊(cè)的 DefaultErrorWebExceptionHandler 處理程序更高的優(yōu)先級(jí)。

該errorAttributes對(duì)象將是我們?cè)诰W(wǎng)絡(luò)異常處理程序的構(gòu)造函數(shù)傳遞一個(gè)的精確副本。理想情況下,這應(yīng)該是我們自定義的Error Attributes類。然后,我們清楚地表明我們想要將所有錯(cuò)誤處理請(qǐng)求路由到renderErrorResponse()方法。最后,我們獲取錯(cuò)誤屬性并將它們插入服務(wù)器響應(yīng)主體中。

然后,它會(huì)生成一個(gè)JSON響應(yīng),其中包含錯(cuò)誤,HTTP狀態(tài)和計(jì)算機(jī)客戶端異常消息的詳細(xì)信息。對(duì)于瀏覽器客戶端,它有一個(gè)whitelabel錯(cuò)誤處理程序,它以HTML格式呈現(xiàn)相同的數(shù)據(jù)。當(dāng)然,這可以是定制的。

小結(jié)

本文首先講了Spring 5之前的SpringMVC異常處理機(jī)制,SpringMVC統(tǒng)一異常處理有 3 種方式:使用 @ExceptionHandler 注解、實(shí)現(xiàn) HandlerExceptionResolver 接口、使用 @controlleradvice 注解;然后通過WebFlux的函數(shù)式接口構(gòu)建Web應(yīng)用,講解Spring Boot 2 Webflux的函數(shù)級(jí)別和全局異常處理機(jī)制(對(duì)于Spring WebMVC風(fēng)格,基于注解的方式編寫響應(yīng)式的Web服務(wù),仍然可以通過SpringMVC統(tǒng)一異常處理實(shí)現(xiàn))。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 聊聊drools?session的不同

    聊聊drools?session的不同

    在drools中存在2種session,一種是有狀態(tài)的Session (Stateful Session),另外一種一種是無狀態(tài)的Session (Stateless Session,本文通過實(shí)例代碼給大家介紹drools?session的不同,感興趣的朋友一起看看吧
    2022-05-05
  • Java介紹多線程計(jì)算階乘實(shí)現(xiàn)方法

    Java介紹多線程計(jì)算階乘實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了Java多線程計(jì)算階乘的實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 淺談?dòng)胘ava實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制

    淺談?dòng)胘ava實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制

    這篇文章主要介紹了淺談?dòng)胘ava實(shí)現(xiàn)事件驅(qū)動(dòng)機(jī)制,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • spring Boot查詢數(shù)據(jù)分頁顯示的方法實(shí)例

    spring Boot查詢數(shù)據(jù)分頁顯示的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于spring Boot查詢數(shù)據(jù)分頁顯示的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • java springboot的概述、特點(diǎn)與構(gòu)建介紹

    java springboot的概述、特點(diǎn)與構(gòu)建介紹

    大家好,本篇文章主要講的是springboot的概述、特點(diǎn)與構(gòu)建介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • Java?pdf文件書簽承前縮放驗(yàn)證的設(shè)置方法

    Java?pdf文件書簽承前縮放驗(yàn)證的設(shè)置方法

    很多朋友不知道是什么是書簽承前縮放,簡單說就是可以任意改變當(dāng)前pdf文檔縮放比例,點(diǎn)擊書簽后不影響其縮放比率,本文給大家介紹下Java?pdf文件書簽承前縮放驗(yàn)證的設(shè)置方法,感興趣的朋友一起看看吧
    2022-02-02
  • PowerMockito的基本使用解析

    PowerMockito的基本使用解析

    這篇文章主要介紹了PowerMockito的基本使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 后端java壓縮圖片超詳細(xì)圖文教程

    后端java壓縮圖片超詳細(xì)圖文教程

    這篇文章主要給大家介紹了關(guān)于后端java壓縮圖片的相關(guān)資料,片壓縮是一種廣泛采用的技術(shù),它不僅能顯著減小文件大小,釋放更多存儲(chǔ)空間,還能提升圖片加載速度,避免長時(shí)間等待,需要的朋友可以參考下
    2024-04-04
  • 簡單了解Java刪除字符replaceFirst原理及實(shí)例

    簡單了解Java刪除字符replaceFirst原理及實(shí)例

    這篇文章主要介紹了簡單了解Java刪除字符replaceFirst原理及實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 詳解Java中的四種引用類型(強(qiáng)軟弱虛)

    詳解Java中的四種引用類型(強(qiáng)軟弱虛)

    Java中的引用類型主要分為四種,分別是強(qiáng)引用、軟引用、弱引用和虛引用,這篇文章主要為大家詳細(xì)介紹了四者的使用與區(qū)別,需要的小伙伴可以參考下
    2023-10-10

最新評(píng)論