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

Spring Boot中如何在ControllerAdvice捕获FreeMarker TemplateException

问题:无法通过@ControllerAdvice捕获FreeMarker的TemplateException

尝试在@ControllerAdvice中捕获FreeMarker的TemplateException以实现异常日志记录,但自定义异常处理器无法捕获该异常,仅在控制台输出模板错误信息。

现有配置代码

FreeMarker配置类

@Configuration
public class FreeMarkerConfig {

    @Bean
    public ViewResolver viewResolver() {
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
        resolver.setCache(true);
        resolver.setPrefix("classpath:/templates/");
        resolver.setSuffix(".ftlh");
        return resolver;
    }

    @Bean
    public FreeMarkerConfigurer freemarkerConfig() {
        FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
        freeMarkerConfigurer.setTemplateLoaderPath("classpath:/templates/");

        Properties settings = new Properties();
        settings.setProperty(freemarker.template.Configuration.TEMPLATE_EXCEPTION_HANDLER_KEY, "rethrow");
        freeMarkerConfigurer.setFreemarkerSettings(settings);
        return freeMarkerConfigurer;
    }
}

自定义异常处理器

@ControllerAdvice
public class CustomExceptionHandler {
    private static final Logger logger = LogManager.getLogger(CustomExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    public String handleException(final HttpServletRequest request, final Exception e) {
        String incidentId = logException(request, e);
        return "redirect:/error?incident-id=" + incidentId;
    }
    @ExceptionHandler(TemplateException.class)
    public ResponseEntity<Object> handleTemplEx(Exception e,
                                         HttpServletRequest request, HttpServletResponse response) {
        logException(request, e);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

控制台错误信息

18:16:39 | ERROR | http-nio-8080-exec-1 | freemarker.runtime | Error executing FreeMarker template
freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> articleTagIndice1s [in template "themes/article.ftlh" at line 7, column 20]

解决方案

核心原因

Spring MVC渲染FreeMarker视图时,默认会捕获TemplateException并包装为ServletException,导致@ControllerAdvice无法直接捕获原始的TemplateException。即便配置了TEMPLATE_EXCEPTION_HANDLER_KEY="rethrow",也会被Spring的视图处理逻辑拦截包裹。

修复步骤

  • 修改FreeMarkerViewResolver配置
    自定义视图构建逻辑,开启视图渲染错误时直接抛出异常的配置:

    @Bean
    public ViewResolver viewResolver() {
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver() {
            @Override
            protected AbstractUrlBasedView buildView(String viewName) throws Exception {
                FreeMarkerView view = (FreeMarkerView) super.buildView(viewName);
                // 禁用路径变量暴露,避免异常被Spring额外包装
                view.setExposePathVariables(false);
                // 开启渲染错误时直接抛出异常
                view.setThrowExceptionOnRenderError(true);
                return view;
            }
        };
        resolver.setCache(true);
        resolver.setPrefix("classpath:/templates/");
        resolver.setSuffix(".ftlh");
        return resolver;
    }
    
  • 优化FreeMarker配置的异常处理器
    使用枚举值替代字符串配置,避免拼写错误,确保异常被重新抛出:

    settings.setProperty(Configuration.TEMPLATE_EXCEPTION_HANDLER_KEY, 
                         TemplateExceptionHandler.RETHROW_HANDLER.getIdentifier());
    
  • 调整异常处理器方法签名
    直接接收TemplateException类型参数,保证匹配精准:

    @ExceptionHandler(TemplateException.class)
    public ResponseEntity<Object> handleTemplateException(TemplateException e,
                                                          HttpServletRequest request, 
                                                          HttpServletResponse response) {
        logException(request, e);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
    

验证

完成以上调整后,模板渲染时的InvalidReferenceException等TemplateException子类异常会被全局异常处理器捕获,执行自定义日志记录逻辑,而非仅输出默认控制台日志。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 12:58:18