我有一个Spring boot应用程序,它可以作为OAuth2客户端使用。
我使用Thymeleaf 3作为模板引擎。这些是我的build.gradle中与Thymeleaf 3相关的依赖项。
compile('org.thymeleaf:thymeleaf:3.0.1.RELEASE')
compile('org.thymeleaf:thymeleaf-spring4:3.0.1.RELEASE')
compile('nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:2.0.4')
compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.1.RELEASE')
如果我像这样引用依赖关系,那就没有区别了:
ext["thymeleaf.version"] = "3.0.2.RELEASE"
ext["thymeleaf-layout-dialect.version"] = "2.1.1"
dependencies {
compile('org.springframework.boot:spring-boot-starter-thymeleaf')
}
我希望能够使用Thymeleaf 3的HTML和Javascript模板模式。 HTML模式有效,但在javascript模式下,messageSource无法正常工作。
这是我的WebMvcConfiguration类:
@Configuration
public class WebMVCConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {
private static final String CHARACTER_ENCODING = "UTF-8";
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Bean
public ViewResolver htmlViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine(htmlTemplateResolver()));
resolver.setContentType("text/html");
resolver.setCharacterEncoding(CHARACTER_ENCODING);
resolver.setViewNames(new String[] {"*.html"});
return resolver;
}
@Bean
public ViewResolver javascriptViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine(javascriptTemplateResolver()));
resolver.setContentType("application/javascript");
resolver.setCharacterEncoding(CHARACTER_ENCODING);
resolver.setViewNames(new String[] {"*.js"});
return resolver;
}
private TemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver);
return engine;
}
private ITemplateResolver htmlTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("templates/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setSuffix(".html");
return resolver;
}
public ITemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/static/js/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
// resolver.setSuffix(".js");
return resolver;
}
}
请注意我必须使用" classpath:/ static / js /"在javascriptTemplateResolver中,因为当我只使用" static / js /"时,我得到以下异常:
java.io.FileNotFoundException: Could not open ServletContext resource [/static/js/headerconfig.js]
此外,我不得不注释掉setSuffix,因为有了它,我得到以下异常:
java.io.FileNotFoundException: class path resource [static/js/typeutils.js.js] cannot be opened because it does not exist
我认为这已经表明了主要问题,但我无法弄清楚可能导致这种问题的原因。
我有一个处理javascript模板的控制器:
@Controller
public class JavascriptController {
@RequestMapping(method = RequestMethod.GET, value = "/js/{template}.js")
public String jsMapping(@PathVariable("template") String template, Model model) {
model.addAttribute("myAttribute", "Attribute works!");
return template;
}
}
我的messages.properties文件位于
我在src / main / resources / templates /文件夹中有一个HTML文件,它引用了一个javascript文件,如下所示:
<script th:src="@{js/typeutils.js}"></script>
引用的javascript文件(js / typeutils.js):
var a = [[${myAttribute}]];
var b = [[#{test}]];
console.log(a);
console.log(b);
当我运行应用程序并检查javascript控制台时,这就是打印出来的内容:
Attribute works!
??test_hu_HU??
因此,模型属性已成功传递到javascript文件,并且已检测到本地化,但未找到“测试”消息。 似乎javascript模板模式与HTML模板模式完全不同。
如果修复javascript模板模式配置以便它也处理messages.properties文件怎么办?
谢谢!
答案 0 :(得分:0)
我找到了解决方案(通过查看百万美元源代码),这可能不完美,但它确实有效!
与Baeldung给出的example不同,以下为我解决了这个问题:
@Configuration
public class WebMVCConfig implements WebMvcConfigurer, ApplicationContextAware {
private static final String CHARACTER_ENCODING = "UTF-8";
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Bean
public ViewResolver htmlViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setContentType("text/html");
resolver.setCharacterEncoding(CHARACTER_ENCODING);
resolver.setViewNames(new String[] { "*.html" });
return resolver;
}
@Bean
public ViewResolver javascriptViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setContentType("application/javascript");
resolver.setCharacterEncoding(CHARACTER_ENCODING);
resolver.setViewNames(new String[] { "*.js" });
return resolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setMessageSource(messageSource());
engine.addTemplateResolver(htmlTemplateResolver());
engine.addTemplateResolver(javascriptTemplateResolver());
return engine;
}
private ITemplateResolver htmlTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setOrder(0);
resolver.setCheckExistence(true);
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:templates/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setSuffix(".html");
return resolver;
}
public ITemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setOrder(1);
resolver.setCheckExistence(true);
resolver.setPrefix("classpath:/static/js/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
return resolver;
}
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource msgSource = new ResourceBundleMessageSource();
msgSource.setAlwaysUseMessageFormat(false);
msgSource.setBasename("messages");
msgSource.setDefaultEncoding(CHARACTER_ENCODING);
msgSource.setFallbackToSystemLocale(true);
msgSource.setUseCodeAsDefaultMessage(false);
return msgSource;
}
}
基本上我们将templateEngine设置为bean,以便我们覆盖ThymeleafDefaultConfiguration的默认templateEngine实现bean。这意味着每次需要解析模板时,都会使用相同的templateEngine。
我们将htmlTemplateResolver的顺序设置为0,并将javascriptTemplateResolver的顺序设置为1,这样我们将首先尝试在HTML模板模式下解析每个模板,然后在Javascript模式下解析。
同样重要的是,我们将SpringResourceTemplateResolvers的checkExistence标志设置为true,因为如果找不到模板,我们将尝试使用下一个TemplateResolver。
这个解决方案有一个缺点,就是我们首先尝试解决HTML模式中不需要的javascript模板,然后是JAVASCRIPT模式,这样在解析javascript资源时还有一个额外的步骤。
我会尝试更好地解决问题,但就目前而言,这对我有用。