泽西岛的全球异常处理弹簧?

时间:2014-09-15 14:33:05

标签: java spring rest jersey-2.0

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

我没有使用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添加对象,我的问题是我正在捕获与CMIS相关的5个异常然后基本异常即异常但是对于每个服务方法我必须重复它我不想做。

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

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

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

问题2:如何使用ExceptionMapper进行操作?

问题3:我是否采用了正确的方法,或者您是否建议采取更好的方法来处理此类问题。

提前致谢。

2 个答案:

答案 0 :(得分:7)

我使用带有Tomcat的jersey2.11和ExceptionMapper几乎异常处理。 (在域逻辑中,只有DB回滚过程使用try-catch代码。)

我认为带有@Provider的ExceptionMapper会自动选择正确的ExceptionMapper。所以我认为这个函数满足于“我想要捕获更多的CMIS异常或默认的异常或IO异常等”。

这段代码是我处理ExceptionMapper的设计代码。

1.Some Jersey Root Resource Class

@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类都扩展了这个Abstract类)

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并在应用程序的任何位置投掷。

我的代码设计使用抛出类似这样的方法,这使得它可以通过ExceptionMapper类进行管理。

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

所以在上面的方法中,我为所有可以预期的异常创建了一个类,对于任何未知的异常,基本的Exception都会被捕获。 现在,在我的应用程序中,如果发生任何异常,则会发生CentralControllerException并发送回http状态代码的相应响应。  Q.2。您是否预见到上述方法存在任何问题。

我认为如果简单项目或永不更新/修改项目(项目生命周期短时间),您的一个类异常映射器方法就可以了。 但是......我从不接受这种做法。简单地说,如果需要管理更多异常,这种方法变得庞大而复杂,难以阅读和维护。

在我的策略中,OOP应该使用多形态策略任何级别代码(类计划,DI计划),这种方法的一些部分旨在驱逐if / switch阻止代码。而这个想法使每个方法简短,简单,对“域逻辑”清晰,代码变得耐受修改。

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

顺便说一下,系统处理结果在目前是一样的。但如果需要降低未来的开发成本,不应该采取一类异常处理计划。因为如果放弃简单的代码和重构状态,项目代码就会死得更快。

这是我的想法,为什么会这样。

问候。

答案 1 :(得分:0)

感谢您的回复。我可以看到你已经根据异常类型和行为创建了多个类。

Q1。在您的服务方法中,您抛出任何异常,如

public void addObject(String objId) throws WebApplicationException{ 
}

或者你还没有使用try catch并在应用程序的任何地方抛出。

实际上,我已经尝试了一些东西,在我的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;

}

}

所以在上面的方法中,我为所有可以预期的异常创建了一个类,并且对于任何未知的异常,基本的Exception都会被捕获。

现在,在我的应用程序中,如果发生任何异常,则会发生CentralControllerException,并且会发回带有http状态代码的相应响应。

Q.2。您是否预见到上述方法中的任何问题。