繁体   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