91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Boot2中如何使用Webflux進行全局異常處理

發布時間:2021-08-19 14:28:15 來源:億速云 閱讀:198 作者:小新 欄目:編程語言

小編給大家分享一下Spring Boot2中如何使用Webflux進行全局異常處理,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

SpringMVC的異常處理

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

  • 使用 @ExceptionHandler 注解

  • 實現 HandlerExceptionResolver 接口

  • 使用 @controlleradvice 注解

使用 @ExceptionHandler 注解

用于局部方法捕獲,與拋出異常的方法處于同一個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("出錯了!");
  }
}

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

實現 HandlerExceptionResolver 接口

通過實現 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();
  }
}

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

使用 @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", "未知錯誤:" + 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依然生效。

@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提供了一套函數式接口,可以用來實現類似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的轉換方法。

@Component
public 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。

@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請求,將會由 TimeHandler::getTime 處理。

功能級別處理異常

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

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

使用onErrorResume處理錯誤

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

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

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

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

在如上的實現中,每當 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() 方法:

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

如上的實現中,我們對 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 Boot2中如何使用Webflux進行全局異常處理”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

进贤县| 石狮市| 高平市| 恩施市| 济源市| 高邮市| 通州市| 航空| 乡城县| 涟水县| 吴堡县| 泰和县| 南皮县| 泸州市| 康保县| 乐陵市| 景洪市| 霍城县| 安图县| 孝感市| 宜州市| 山东| 抚宁县| 扬中市| 昌图县| 高淳县| 射阳县| 法库县| 沧源| 楚雄市| 宁明县| 浮梁县| 滨海县| 康马县| 信丰县| 龙胜| 民县| 和静县| 济南市| 清涧县| 五大连池市|