如何使全局共享对象可用于 Spring Boot 2 中的 freemarker 模板

kal*_*ech 5 freemarker spring-boot

使用 Spring Boot 2.x 时,在不丢失 Spring Boot 的 FreeMarker 自动配置的情况下,使全局共享对象可供 freemarker 模板使用的最佳方法是什么?

执行此操作的底层机制是 Spring Boot 的FreeMakerConfigurer.setFreemarkerVariables,它又调用 FreeMarker 的Configuration.setAllSharedVariables

但是,(对我来说)没有明显的方法来修改由FreeMarkerServletWebConfigurationSpring Boot 支持的预定义 freemarker 属性设置的 FreeMarkerConfigurer。(在这里搜索“freemarker” )。

一种常见的方法是创建自定义FreemarkerConfigurerbean,但我相信这样会丢失 spring boot 提供的一些自动配置,特别是在处理各种外部属性方面。

似乎可行的一种选择是使用 BeanPostProcessor,如下所示:

public class CustomFreeMarkerConfig implements BeanPostProcessor {

    Object sharedWithAllFreeMarkerTemplatesObj = new Object();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
    throws BeansException {

        if (bean instanceof FreeMarkerConfigurer) {
            FreeMarkerConfigurer configurer = (FreeMarkerConfigurer) bean;

            Map<String, Object> sharedVariables = new HashMap<>();
            sharedVariables.put("obj", sharedWithAllFreeMarkerTemplatesObj);
            configurer.setFreemarkerVariables(sharedVariables);
        }

        return bean;
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎应该有一种更干净的方法来做到这一点,也许通过某种方式扩展或配置FreeMarkerConfigurationFactory,但我还没有找到它。

小智 0

我从 spring git 找到了解决方案

Spring Boot 2.0 打破了 @wo8335224 提供的解决方案,因为 FreeMarkerWebConfiguration 被 FreeMarkerServletWebConfiguration 取代,不幸的是,FreeMarkerServletWebConfiguration 是包私有的,因此无法子类化。

当前有效的解决方案是配置 freemarker.template.Configuration bean:

@Configuration
public class FreemarkerConfig {
    public FreemarkerConfig(freemarker.template.Configuration configuration) throws TemplateModelException {
        configuration.setSharedVariable("name", "whatever type of value");
    }
}
Run Code Online (Sandbox Code Playgroud)

在内部 FreeMarkerConfigurer#setFreemarkerVariables 将其工作委托给 freemarker.template.Configuration#setAllSharedVariables。