簡體   English   中英

Jersey 和 Spring 中的全局異常處理?

[英]Global Exception Handling in Jersey & Spring?

我正在使用 Jersey & Spring 3.2 和 Open CMIS 開發 RESTful web 服務。

我沒有使用 Spring 的 MVC 模式,它只是 Spring IOC 和 Jersey SpringServlet,控制器類類似於下面的代碼

@GET
@Path("/{objId:.+}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)

public statusMsg addObject(@PathParam("objId") String objId{

    return repoService.addObject(objId);
}

在 repoService 中,我正在執行業務邏輯以使用 CMIS 添加對象,我的問題是我捕獲了大約 5 個與 CMIS 相關的異常,然后是基本異常,即 Exception 但是對於每個服務方法,我都必須重復它,而我沒有想做。

我在 Google 上搜索,發現 @ControllerAdvice 是解決此類問題的最佳解決方案,您可以定義所有已檢查和未檢查的異常,並從應用程序中刪除所有 try catch 塊。 但它只適用於 MVC 模式。

問題 1:有沒有辦法在上面的 Jersey-Spring 框架中使用它?

經過更多研究,我發現 Jersey 提供了 ExceptionMapper 來處理自定義異常,但我想捕獲更多 CMIS 異常或默認異常或 IO 異常等。

問題 2:我如何使用 ExceptionMapper 做到這一點?

問題 3:我是否采用正確的方法,或者您是否建議使用更好的方法來處理此類問題。

提前致謝。

我將 jersey2.11 與 Tomcat 一起使用,並且幾乎將異常句柄與 ExceptionMapper 一起使用。 (在域邏輯中,只有 DB 回滾過程使用 try-catch 代碼。)

我認為帶有@Provider 的 ExceptionMapper 會自動選擇正確的 ExceptionMapper。 所以我想這個函數滿足於“我想捕獲更多的 CMIS 異常或默認異常或 IO 異常等”。

這段代碼是我處理 ExceptionMapper 的設計代碼。

1.一些 Jersey 根資源類

@GET
@Produces("application/json")
public String getUser(@NotNull @QueryParam("id") String id, 
  @NotNull @QueryParam("token") String token) throws Exception { // This level throws exceptions handled by ExceptionMapper

  someComplexMethod(id, token); // possible throw Exception, IOException or other exceptions.

  return CLICHED_MESSAGE;
}

2.ExceptionMapper 包。 com.yourdomain.exceptionmapper

AbstractExceptionMapper.java (所有 ExceptionMapper 類都擴展了這個抽象類)

public abstract class AbstractExceptionMapper {
  private static Logger logger = LogManager.getLogger(); // Example log4j2.

  protected Response errorResponse(int status, ResponseEntity responseEntity) {
    return customizeResponse(status, responseEntity);
  }

  protected Response errorResponse(int status, ResponseEntity responseEntity, Throwable t) {
    logger.catching(t); // logging stack trace.

    return customizeResponse(status, responseEntity);
  }

  private Response customizeResponse(int status, ResponseEntity responseEntity) {
     return Response.status(status).entity(responseEntity).build();
  }
 }

ExceptionMapper.java (至少這個映射器可以捕獲任何未定義指定異常映射器的異常。)

@Provider
 public class ExceptionMapper extends AbstractExceptionMapper implements
 javax.ws.rs.ext.ExceptionMapper<Exception> {

 @Override
 public Response toResponse(Exception e) {
 // ResponseEntity class's Member Integer code, String message, Object data. For response format.
 ResponseEntity re = new ResponseEntity(Code.ERROR_MISC); 

  return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
 }
}

WebApplicationExceptionMapper.java (指定WebApplicationException)

@Provider
public class WebApplicationExceptionMapper extends AbstractExceptionMapper implements
    ExceptionMapper<WebApplicationException> {

  @Override
  public Response toResponse(WebApplicationException e) {
    ResponseEntity re = new ResponseEntity(Code.ERROR_WEB_APPLICATION);

    return this.errorResponse(e.getResponse().getStatus(), re, e);
  }
}

ConstraintViolationExceptionMapper.java (指定Hibernate Validator ConstraintViolationException)

@Provider
public class ConstraintViolationExceptionMapper extends AbstractExceptionMapper implements
    ExceptionMapper<ConstraintViolationException> {

  @Override
  public Response toResponse(ConstraintViolationException e) {
    ResponseEntity re = new ResponseEntity(Code.ERROR_CONSTRAINT_VIOLATION);

    List<Map<String, ?>> data = new ArrayList<>();
    Map<String, String> errorMap;
    for (final ConstraintViolation<?> error : e.getConstraintViolations()) {
      errorMap = new HashMap<>();
      errorMap.put("attribute", error.getPropertyPath().toString());
      errorMap.put("message", error.getMessage());
      data.add(errorMap);
    }

    re.setData(data);

    return this.errorResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, re, e);
  }
}

.. 和其他指定異常可以創建 ExceptionMapper 類。

根據我的經驗,Exception Mapper 是專注於域邏輯的高級思想。 它可以從域邏輯中去除無聊的分散的 try-catch 塊代碼。 所以我希望你能在問題 3 中感受到“是的,我是”來解決你環境中的問題。

您沒有在應用程序中的任何地方使用過 try catch 和 throw。

我的代碼設計使用 throws at 這樣的方法,這使得通過 ExceptionMapper 類進行管理。

public String getUser(@NotNull @QueryParam("id") String id, 
  @NotNull @QueryParam("token") String token) throws Exception

所以在上面的方法中,我只為我可以預期的所有異常創建了 1 個類,對於任何未知異常,基本異常將在那里捕獲。 現在,無論在我的應用程序中的任何地方,如果發生任何異常,都會出現 CentralControllerException 並發送回帶有 http 狀態代碼的相應響應。 Q.2. 您是否預見到上述方法中的任何問題。

我認為如果簡單的項目或從不更新/修改項目(項目生命周期短時間),您的一類異常映射器方法就可以了。 但是......我從不采取這種方法。 簡單來說,如果需要管理更多的異常,這個方法就會變得龐大而復雜,並且變得難以閱讀和維護。

在我的政策中,OOP 應該在任何級別的代碼(類計划、DI 計划)中使用多態策略,這種方法的某些部分旨在消除代碼中的 if/switch 塊。 而這種思想使得每個方法代碼短小、簡單,清晰“領域邏輯”,代碼變得不易修改。

所以我創建了 ExceptionMapper 並委托給 DI 哪個 ExceptionMapper 類管理異常。 (所以 DI 管理替換你的單個類如果塊管理哪個異常處理,這通常是類似於 Extract xxx http://refactoring.com/catalog/extractClass.html 的重構方法。在我們討論的情況下,單個類和一個方法太忙了,因此提取每個接近的 ExceptionMapper 類並 DI 調用合適的類和方法策略。)

Btw,目前系統處理結果是一樣的。 但是如果需要降低未來的開發成本,就不應該采取接近一類的異常處理方案。 因為如果放棄簡單的代碼和重構狀態,項目代碼會死得更快。

這是我的想法以及為什么會這樣。

問候。

感謝您的回復。 我可以看到您根據異常類型和行為創建了多個類。

一季度。 在您的服務方法中,您是否拋出任何異常,例如

public void addObject(String objId) throws WebApplicationException{ 
}

或者您沒有在應用程序中的任何地方使用 try catch 和 throw。

實際上,我已經嘗試了一些在我的 Web 應用程序中我沒有在任何地方使用 try、catch 和 throws 的東西,並且在我的 CentralControllerException 中我提到了如下:

public class CentralControllerHandler implements ExceptionMapper<Exception> {

@Override
@Produces(MediaType.APPLICATION_JSON)
public Response toResponse(Exception ex) {

    if(ex instanceof CmisContentAlreadyExistsException){

        log.error(ex);
        // send Response status as 400
    }

    if(ex instanceof IOException){

        log.error(ex);
        // send Response status as 400
    }

    return Response;

}

}

所以在上面的方法中,我只為我可以預期的所有異常創建了 1 個類,對於任何未知異常,基本異常將在那里捕獲。

現在,無論在我的應用程序中的任何地方,如果發生任何異常,都會出現 CentralControllerException 並發送回帶有 http 狀態代碼的相應響應。

Q.2. 您是否預見到上述方法中的任何問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM