java - Jersey 和 Spring 中的全局异常处理?

标签 java spring rest jersey-2.0

我正在使用 Jersey & Spring 3.2 以及 Open CMIS 开发 RESTful web 服务。

我没有使用 Spring 的 MVC 模式,它只是 Spring IOC 和 Jersey SpringServlet, Controller 类类似于下面的代码

@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 相关的异常,然后是基本异常,即异常,但对于每个服务方法,我都必须重复它,我不想做。

我在 Google 上搜索并发现 @ControllerAdvice 是解决此类问题的最佳解决方案,您可以定义所有已检查和未检查的异常以及从应用程序中删除所有 try catch block 。但它只适用于 MVC 模式。

问题 1:有没有办法在上面的 Jersey-Spring 框架中使用它?

经过更多研究,我发现 Jersey 提供了 ExceptionMapper 来处理自定义异常,但我想捕获更多 CMIS 异常或默认异常或 IO 异常等。

问题二: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 block 代码。 因此,我希望您在问题 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 block 。并且这种思想使每个方法的代码都短而简单,“领域逻辑”清晰,代码变得难以修改。

所以我创建了 ExceptionMapper 的实现并委托(delegate)给 DI,ExceptionMapper 类管理异常。 (所以 DI 管理替换你的单个类 If block 管理哪个异常处理,这通常是类似于 Extract xxx http://refactoring.com/catalog/extractClass.html 的重构方法。 在我们的讨论案例中,单个类和一个方法太忙了,因此提取每个接近的 ExceptionMapper 类并 DI 调用合适的类和方法策略。)

顺便说一下,目前系统处理结果是一样的。但是如果需要降低 future 的开发成本,就不应该采取接近一级的异常处理方案。因为如果简单地放弃代码和重构状态,项目代码死得更快。

这是我的想法以及原因。

问候。

关于java - Jersey 和 Spring 中的全局异常处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25850486/

相关文章:

java - Android 游戏 - 将时间限制设置为 30 秒

java - 为什么在 spring data jpa starter 中 javax.persistence-api 被 jakarta.persistence-api 替换?

java - Android 应用程序在尝试通过 firebase 接收推送通知时崩溃

javascript - Node 和 Express : How to implement basic webhook server

java - 如何在java中初始化一个二维字符串数组

java - PersistenceUnit 中的多个类

java - 读取 Android Spring 拦截器中的响应主体

spring - Spring容器与Servlets的交互

node.js - 使用 Express Route 使用来自 Mongoose 的数据填充 Backbone Marionette Views

rest - 对于不存在的REST资源,什么时候返回404,什么时候返回403?