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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25850486/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 08:47:34  来源:igfitidea点击:

Global Exception Handling in Jersey & Spring?

javaspringrestjersey-2.0

提问by user3306543

I am developing the RESTful webservices using Jersey & Spring 3.2 along with Open CMIS.

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

I am not using MVC pattern of Spring and it's just Spring IOC & Jersey SpringServlet, the controller class is something like below code

我没有使用 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);
}

In the repoService I am performing the business logic to add the object using CMIS, my question is that I am catching around 5 exceptions related to CMIS then the base exception i.e Exception but for every service method I have to repeat it which I don't want to do.

在 repoService 中,我正在执行业务逻辑以使用 CMIS 添加对象,我的问题是我捕获了大约 5 个与 CMIS 相关的异常,然后是基本异常,即 Exception 但是对于每个服务方法,我都必须重复它,而我没有想要做。

I was searching on Google and found that @ControllerAdvice is the best solution for such problem wheer you can define all the checked & unchecked exceptions and wherever remove all the try catch blocks from the application. But it only work with MVC pattern.

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

Question 1: Is there a way I can use this in above Jersey-Spring framework?

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

After more reserach I found that Jersey provides ExceptionMapper to handle customized exception but I want to catch more CMIS exception or default Exception or IO Exception etc.

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

Question 2: How can I do it with ExceptionMapper?

问题 2:我如何使用 ExceptionMapper 做到这一点?

Question 3: Am I on the correct approach or do you suggest any better approach to handle such issues.

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

Thanks in advance.

提前致谢。

回答by kj13

I use jersey2.11 with Tomcat and almost exception handle with ExceptionMapper. (In domain logic, only DB rollback process use try-catch code.)

我将 jersey2.11 与 Tomcat 一起使用,并且几乎将异常句柄与 ExceptionMapper 一起使用。(在域逻辑中,只有 DB 回滚过程使用 try-catch 代码。)

I think ExceptionMapper with @Provider automatically choose correct ExceptionMapper. So I suppose this function is satisfied with "I want to catch more CMIS exception or default Exception or IO Exception etc."

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

This code is my handling ExceptionMapper design code.

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

1.Some Jersey Root Resource Class

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 package. com.yourdomain.exceptionmapper

2.ExceptionMapper 包。com.yourdomain.exceptionmapper

AbstractExceptionMapper.java(All ExceptionMapper class extends this Abstract class)

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(At least this mapper can catch any exception which is not define specify exception mapper.)

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(Specify WebApplicationException)

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(Specify Hibernate Validator ConstraintViolationException)

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

.. and other specify exception can create ExceptionMapper classes.

.. 和其他指定异常可以创建 ExceptionMapper 类。

In my experience, Exception Mapper is high level idea for focus to domain logic. It could drive out boring scattered try-catch block code from domain logic. So I hope that you feel the "Yes i am" at Question 3 to resolve the problem at your environment.

根据我的经验,Exception Mapper 是专注于域逻辑的高级思想。它可以从域逻辑中去除无聊的分散的 try-catch 块代码。所以我希望你能在问题 3 中感受到“是的,我是”来解决你所在环境的问题。

you have not used try catch and throw anywhere across the application.

您没有在应用程序中的任何地方使用过 try catch 和 throw。

My code design use throws at method like this and this make to manage by ExceptionMapper classes.

我的代码设计使用 throws at 这样的方法,这使得通过 ExceptionMapper 类进行管理。

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

So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch. Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back. Q.2. Do you foresee any issue in above approach.

所以在上面的方法中,我只为我可以预期的所有异常创建了 1 个类,对于任何未知异常,基本异常将在那里捕获。现在无论在我的应用程序中的任何地方,如果发生任何异常,它都会出现 CentralControllerException 并发送回带有 http 状态代码的适当响应。Q.2. 您是否预见到上述方法中的任何问题。

I think if simple project or never update/modify project (project lifecycle short time), your one class exception mapper approach ok. But ... i never take this approach. Simply, if need to manage more exception, this method become big and complex, and hard to read and maintain becoming.

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

In my policy, OOP should use pleomorphism strategy any level code(class plan, DI plan) and this approach some part aim to drive out if/switch block in code. And this idea make each method short code and simple, clear to "domain logic" and code become to resistant to modify.

在我的政策中,OOP 应该在任何级别的代码(类计划、DI 计划)中使用多态策略,这种方法的某些部分旨在消除代码中的 if/switch 块。而这种思想使每个方法代码短小、简单、清晰,“领域逻辑”清晰,代码变得不易修改。

So i create implements ExceptionMapper and delegate to DI which ExceptionMapper class manage to exception. (So DI manage replace your single class If block manage which exception handling, this is typically refactoring approach similar Extract xxx http://refactoring.com/catalog/extractClass.html. In our discussion case, single class and one method too busy, so extract each ExceptionMapper class approaching and DI call suitable class & method strategy.)

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

Btw, system processing result is same at present point. But if need to reduce future development cost ,should not took approach one class exception handling plan. Because if give up simply code and refactor status, project code is dead faster.

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

This is my idea and why this.

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

regards.

问候。

回答by user3306543

thanks for your reply. I can see you have created multiple classes based on the exception type and behaviour.

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

Q1. In your services method are you throwing any exception like

一季度。在您的服务方法中,您是否抛出任何异常,例如

public void addObject(String objId) throws WebApplicationException{ 
}

or you have not used try catch and throw anywhere across the application.

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

Actually, I have tried something where in my web application I am not using try, catch and throws anywhere and in my CentralControllerException I have mentioned like below:

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

}

}

So in above approach I have created just 1 class for all the exceptions which I could expect and for any unknown exception the base Exception will be there to catch.

所以在上面的方法中,我只为我可以预期的所有异常创建了 1 个类,对于任何未知异常,基本异常将在那里捕获。

Now wherever in my application if any exception occurs it comes to the CentralControllerException and appropriate response with http status code is sent back.

现在无论在我的应用程序中的任何地方,如果发生任何异常,它都会出现 CentralControllerException 并发送回带有 http 状态代码的适当响应。

Q.2. Do you foresee any issue in above approach.

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