You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从ControllerAdvice的ExceptionHandler渲染视图时,能否触发其他ControllerAdvice?

问题描述

Thymeleaf升级到3.1.0后移除了#httpServletRequest属性,我写了一个标注@ControllerAdvice的UtilityProvider类,通过@ModelAttribute("requestUri")把HttpServletRequest的requestURI加入模型:

@ControllerAdvice
class UtilityProvider {

    @ModelAttribute("requestUri")
    fun requestUri(request: HttpServletRequest): String {
        return request.requestURI
    }

}

这个类对普通请求都生效,但当另一个标注@ControllerAdvice的GlobalExceptionHandlerAdvice类里的@ExceptionHandler处理异常并返回视图时,requestUri属性没被加到模型里。GlobalExceptionHandlerAdvice代码如下:

@ControllerAdvice
public class GlobalExceptionHandlerAdvice {

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
        return new ModelAndView("error");
    }
}

我有两个疑问:

  1. 这是预期行为吗?
  2. 有没有办法让UtilityProvider的@ControllerAdvice也作用于异常处理器渲染的视图?

我试过用@Ordered注解调整两个@ControllerAdvice的执行顺序,但没效果;目前已经在异常处理器里手动添加该属性临时解决(代码如下),但不想用这种方式:

@ControllerAdvice
public class GlobalExceptionHandlerAdvice {

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
        Map<String, Object> model = new HashMap<>();
        model.put("requestUri", request.getRequestURI());
        return new ModelAndView("error", model);
    }
}
解决方案

1. 这是预期行为吗?

是的,这属于Spring MVC的预期行为。当@ExceptionHandler方法直接返回ModelAndView时,Spring MVC不会自动触发其他@ControllerAdvice类中的@ModelAttribute方法——异常处理流程的模型填充逻辑和正常请求流程有差异,默认只会处理当前@ControllerAdvice内的@ModelAttribute,不会跨类触发其他全局@ModelAttribute。

2. 如何让UtilityProvider的@ModelAttribute作用于异常视图?

有两种更优雅的方式解决:

方式一:让异常处理器返回视图名称而非ModelAndView

修改GlobalExceptionHandlerAdvice的方法,直接返回字符串类型的视图名,这样Spring MVC会走完整的视图渲染流程,包括触发所有@ControllerAdvice的@ModelAttribute:

@ControllerAdvice
public class GlobalExceptionHandlerAdvice {

    @ExceptionHandler(value = Exception.class)
    public String defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception e) {
        return "error";
    }
}

方式二:在异常处理器中注入Model参数并复用全局逻辑

如果必须返回ModelAndView,可以在方法参数中加入Model,Spring会自动将全局@ModelAttribute填充到这个Model里,再用它构建ModelAndView:

@ControllerAdvice
public class GlobalExceptionHandlerAdvice {

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception e, Model model) {
        // 此时model已经包含UtilityProvider中添加的requestUri
        return new ModelAndView("error", model.asMap());
    }
}

补充:关于@Ordered无效的原因

@Ordered注解只控制@ControllerAdvice中同类型方法的执行顺序(比如多个@ExceptionHandler的执行优先级),但无法改变异常处理流程中是否触发全局@ModelAttribute的规则,所以调整顺序不会解决问题。

内容的提问来源于stack exchange,提问作者peach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:32:18