This really should be built-in.
First, disable the built in FreeMarkerAutoConfiguration
on your Application
:
@SpringBootApplication
@EnableAutoConfiguration(exclude = {FreeMarkerAutoConfiguration.class})
public class Application extends WebMvcConfigurerAdapter {
...
]
Then add this custom configuration:
(adapted from https://github.com/isopov/fan/blob/master/fan-web/src/main/java/com/sopovs/moradanen/fan/WebApplicationConfiguration.java; Added an ObjectWrapper
to the TaglibFactory
and removed the addResourceHandlers()
override)
import freemarker.cache.ClassTemplateLoader;
import freemarker.ext.jsp.TaglibFactory;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Locale;
import java.util.Properties;
@Configuration
public class CustomFreemarkerConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
@Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setFallbackToSystemLocale(false);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Bean
public SessionLocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.ENGLISH);
return localeResolver;
}
@Bean
@Autowired
public freemarker.template.Configuration freeMarkerConfig(ServletContext servletContext) throws IOException,
TemplateException {
FreeMarkerConfigurer freemarkerConfig = configFreeMarkerConfigurer(servletContext);
return freemarkerConfig.getConfiguration();
}
@Bean
@Autowired
public TaglibFactory taglibFactory(ServletContext servletContext) throws IOException, TemplateException {
FreeMarkerConfigurer freemarkerConfig = configFreeMarkerConfigurer(servletContext);
TaglibFactory taglibFactory = freemarkerConfig.getTaglibFactory();
taglibFactory.setObjectWrapper(freemarker.template.Configuration.getDefaultObjectWrapper(freemarker.template.Configuration.getVersion()));
return taglibFactory;
}
@Autowired
@Bean
public FreeMarkerConfig springFreeMarkerConfig(ServletContext servletContext) throws IOException, TemplateException {
return new MyFreeMarkerConfig(freeMarkerConfig(servletContext), taglibFactory(servletContext));
}
private static FreeMarkerConfigurer configFreeMarkerConfigurer(ServletContext servletContext) throws IOException,
TemplateException {
FreeMarkerConfigurer freemarkerConfig = new FreeMarkerConfigurer();
freemarkerConfig
.setPreTemplateLoaders(new ClassTemplateLoader(CustomFreemarkerConfiguration.class, "/templates/"));
ServletContext servletContextProxy = (ServletContext) Proxy.newProxyInstance(
ServletContextResourceHandler.class.getClassLoader(),
new Class<?>[] { ServletContext.class },
new ServletContextResourceHandler(servletContext));
freemarkerConfig.setServletContext(servletContextProxy);
Properties settings = new Properties();
settings.put("default_encoding", "UTF-8");
freemarkerConfig.setFreemarkerSettings(settings);
freemarkerConfig.afterPropertiesSet();
return freemarkerConfig;
}
@Bean
public FreeMarkerViewResolver viewResolver() {
FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver();
viewResolver.setCache(false);
viewResolver.setSuffix(".ftl");
viewResolver.setContentType("text/html;charset=UTF-8");
return viewResolver;
}
private static class ServletContextResourceHandler implements InvocationHandler
{
private final ServletContext target;
private ServletContextResourceHandler(ServletContext target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("getResourceAsStream".equals(method.getName())) {
Object result = method.invoke(target, args);
if (result == null) {
result = CustomFreemarkerConfiguration.class.getResourceAsStream((String) args[0]);
}
return result;
} else if ("getResource".equals(method.getName())) {
Object result = method.invoke(target, args);
if (result == null) {
result = CustomFreemarkerConfiguration.class.getResource((String) args[0]);
}
return result;
}
return method.invoke(target, args);
}
}
private static class MyFreeMarkerConfig implements FreeMarkerConfig {
private final freemarker.template.Configuration configuration;
private final TaglibFactory taglibFactory;
private MyFreeMarkerConfig(freemarker.template.Configuration configuration, TaglibFactory taglibFactory) {
this.configuration = configuration;
this.taglibFactory = taglibFactory;
}
@Override
public freemarker.template.Configuration getConfiguration() {
return configuration;
}
@Override
public TaglibFactory getTaglibFactory() {
return taglibFactory;
}
}
}
Add the following to your pom.xml
:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
Then you can load in your template:
<#assign s=JspTaglibs["/META-INF/spring.tld"] />
<a href="${s.mvcUrl("IC#index").build()}">Home</a>
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…