内容提要
在Spring Boot中,@RestControllerAdvice和@ControllerAdvice用于全局捕获异常,但无法捕获过滤器中抛出的异常。要捕获过滤器中的异常,需要在过滤器中将异常传递到后续处理的Controller。示例代码展示了如何在过滤器中捕获ExpiredJwtException,并通过Dispatcher转发到特定Controller,以便ControllerAdvice能够处理该异常。
延伸解读
为什么过滤器异常无法被全局捕获
Spring Boot 中,请求处理链的顺序是过滤器 -> 拦截器 -> ControllerAdvice。ControllerAdvice 位于 Controller 层之后,因此当过滤器或拦截器中抛出异常时,请求尚未到达 ControllerAdvice 的处理范围,异常自然无法被其捕获。只有 Controller、Service、DAO 层抛出的异常才能被 ControllerAdvice 拦截。理解这一执行顺序是解决问题的关键。
将过滤器异常转发到 Controller 的处理思路
文章给出的方案是在过滤器中捕获异常后,不直接抛出,而是将异常对象存入 request 属性,并通过 RequestDispatcher 转发到一个专门接收异常的 Controller。该 Controller 从属性中取出异常并重新抛出,此时异常已进入 Controller 层,ControllerAdvice 便能正常捕获并处理。这种方法利用了转发机制,将异常处理时机后移。
实现时的注意事项与潜在局限
使用转发方案时,需确保转发路径对应的 Controller 能正确接收请求,并注意转发可能改变请求路径或引发二次过滤。此外,该方案仅适用于过滤器内部可捕获的异常,若异常发生在转发过程中,仍可能无法被 ControllerAdvice 处理。文章未讨论性能影响或替代方案,实际使用时需结合项目情况评估。
Q&A
在Spring Boot中,如何使用@ControllerAdvice捕获异常?
可以使用@RestControllerAdvice和@ControllerAdvice来全局捕获异常,但它们无法捕获过滤器中抛出的异常。
为什么@ControllerAdvice无法捕获过滤器中的异常?
因为过滤器的执行顺序是过滤器->拦截器->ControllerAdvice,过滤器中抛出的异常在ControllerAdvice执行之前就已经停止了执行。
如何在过滤器中处理ExpiredJwtException异常?
在过滤器中捕获ExpiredJwtException后,可以将异常对象设置到请求属性中,并通过Dispatcher转发到特定的Controller。
在过滤器中捕获异常后,如何将其传递给Controller?
可以通过设置请求属性并使用Dispatcher转发到一个接收异常的Controller来传递异常。
如何实现一个接收异常的Controller?
可以创建一个Controller,使用@RequestMapping注解定义一个路径,并在该路径的方法中从请求属性中取出异常并重新抛出。
如何使用@RestControllerAdvice处理ExpiredJwtException?
可以在@RestControllerAdvice中定义一个@ExceptionHandler方法,专门处理ExpiredJwtException并返回相应的ApiResult。