【问题标题】:Spring Boot intercept all exception handlersSpring Boot 拦截所有异常处理程序
【发布时间】:2018-07-24 22:46:26
【问题描述】:

我正在尝试在代码中执行一些适用于我所有@ExceptionHandlers 的通用逻辑。我知道我可以写一个HandlerInterceptor 来拦截快乐的路径。但我想加入异常处理生命周期,以便在呈现错误响应之前执行一些常见的逻辑,例如日志记录。

在 Spring Boot / Spring MVC 中有没有办法做到这一点?如果可能的话,我想避免为此目的编写一个 servlet 过滤器。

【问题讨论】:

  • 你说的是UncaughtExceptionHandler吗?或者你可以有一个像 Spring 这样的代理来拦截错误?
  • 不,我实际上没有处理任何异常。我只想对我拥有的每个异常处理程序进行一些后处理。例如,它可能涉及报告状态代码。

标签: java spring spring-mvc spring-boot


【解决方案1】:

@RestControllerAdvice@ExceptionHandler有一个办法,例子:

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(value = {DeniedPermissionException.class})
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public String deniedPermissionException(DeniedPermissionException ex) {
        return "Denied permission";
    }

    @ExceptionHandler(value = {ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String constraintViolationException(ConstraintViolationException ex) {
        return "Bad request";
    }

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public String internalServerError(Exception ex) {
         return "Internal error";
    }
}

*DeniedPermissionException 是自定义异常。

【讨论】:

  • 对不起,我认为我没有清楚地解释自己。在你上面的例子中,我将如何拦截上面的每个异常处理程序来做一些常见的事情?一种粗略的方法是将通用逻辑放在私有方法中并调用该方法 3 次。但我正在寻找一种拦截器风格的解决方案。
  • @adarshr 根据您的需要,如果您想对所有类型的错误进行过滤,您只需要具有 internalServerError 方法,如果您想区分几种类型的错误但维护一个常见的行为,我可以想到两个选择,要么创建一个私有方法并直接调用它,要么使用 AOP。但在我看来,第二种选择是引入过度工程
  • 我想我已经找到了解决方案 :-) 抱歉,我应该先进行 RTFM。
  • 这个控制器是否会拦截在 Spring Boot 上下文中引发的所有异常?如果 Spring Boot 使用其他协议与其他系统(REST 除外)通信怎么办?有没有更通用的注解类似于@RestControllerAdvice?谢谢
【解决方案2】:

我有一个解决方案。这是关于使用HandlerInterceptor.afterCompletion 方法。但是,documentation of this method 中有一行声明:

注意:只有在此拦截器的 preHandle 方法成功完成并返回 true 时才会调用!

所以诀窍是同时实现preHandle 并使其返回true

现在我的拦截器看起来像这样:

@Component
public class MyInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // perform common logic here
    }
}

但要注意的一件事是,如果您有一个拦截器链和一个拦截器,然后这个拦截器会引发异常,则该拦截器将没有机会执行。因此,如果我们重新排序拦截器链,使MyInterceptor 位于顶部,它将拦截所有请求。

【讨论】:

  • 我认为不需要实现 preHandle 并让它返回 true,因为它在 HandlerInceptorAdapter 类中做同样的事情。
【解决方案3】:

这并不是真正的 Spring Boot 问题。这确实是 Spring MVC 关注的问题。一种好的方法是实现HandlerExceptionResolver 或从ExceptionHandlerExceptionResolver 之类的东西扩展。需要为实现提供比默认异常解析器更高的优先级(它们都以最低优先级运行)。如果你想保留默认解析器的现有行为,但只捕获横切的异常,如日志记录或跟踪,那么只需为 ModelAndView 返回 null ,Spring 将确保像以前一样调用其他默认解析器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2012-07-05
    • 2023-03-28
    • 1970-01-01
    相关资源
    最近更新 更多