I have a Spring Boot app using Thymeleaf 3 as the template engine for the app pages. We use the default configuration provided by spring-boot-starter-thymeleaf, with the HTML Thymeleaf templates under the src/main/resources/templates folder.
Now we would like to use Thymeleaf to generate also some javascript files, using the new javascript template mode. Those javascript templates could be located into the same HTML templates folder or another one (ex: src/main/resources/jstemplates).
I don't know if there is a way to add this configuration without changing anything in the default configuration provided by the spring-boot-starter-thymeleaf, or I have to create a full configuration for everything.
I've tried the first option with the following configuration, which works for the javascript templates, but then html templates don't work anymore.
The configuration:
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
implements ApplicationContextAware {
private static final String UTF8 = "UTF-8";
@Autowired
private SpringTemplateEngine templateEngine;
@Autowired
private ThymeleafProperties properties;
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public ThymeleafViewResolver javascriptThymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine);
resolver.setCharacterEncoding(UTF8);
resolver.setContentType("application/javascript");
resolver.setViewNames(new String[] {".js"});
resolver.setCache(this.properties.isCache());
return resolver;
}
@Bean
public SpringResourceTemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/jstemplates/");
resolver.setSuffix(".js");
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
}
A test javascript controller:
@Controller
public class JavascriptController {
@RequestMapping(method = RequestMethod.GET, value = "/test.js")
public String testjs() {
return "test";
}
}
The controller for the root page:
@Controller
public class MainController {
@RequestMapping(method = RequestMethod.GET, value = "/")
public String index(Model model) {
return "index";
}
}
There is a test.js file in the src/main/resources/jstemplates folder. If I try the url http://localhost:8080/test.js, it works as expected. But if I try, for example, the main url (http://localhost:8080/) it fails with the following error:
Caused by: java.io.FileNotFoundException: class path resource [jstemplates/index.js] cannot be opened because it does not exist
It should be looking for the templates/index.html instead, so it seems the javascriptTemplateResolver overrides or takes precedence over de default one, without falling back to it.
Is there a way to add another template mode support integrated with the default Thymeleaf configuration, or I need to configure everything from scratch?
After some debugging I finally found the solution. It seems the SpringResourceTemplateResolver doesn't check by default if the template really exists. In my example configuration, the first template resolver is the one configured for the javascript templates, and it was creating a View without looking first if the template exists.
To solve it the template checkExistence property must be set to true. Ex:
@Bean
public SpringResourceTemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/jstemplates/");
resolver.setSuffix(".js");
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
resolver.setCharacterEncoding(UTF8);
resolver.setCheckExistence(true);
return resolver;
}
The only problem I see with this configuration is that if we create a js view with the same name as a html view, it will always get the javascript one.
Edit
To solve that last issue I've made some changes in the configuration:
The final configuration is as follows:
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
implements ApplicationContextAware {
private static final String UTF8 = "UTF-8";
@Autowired
private ThymeleafProperties properties;
@Autowired
private TemplateEngine templateEngine;
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public ThymeleafViewResolver javascriptThymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine);
resolver.setCharacterEncoding(UTF8);
resolver.setContentType("application/javascript");
resolver.setViewNames(new String[] {"*.js"});
resolver.setCache(this.properties.isCache());
return resolver;
}
@Bean
public SpringResourceTemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(this.applicationContext);
resolver.setPrefix("classpath:/templates/js/");
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
resolver.setCharacterEncoding(UTF8);
resolver.setCheckExistence(true);
resolver.setCacheable(this.properties.isCache());
return resolver;
}
}
And the sample controller:
@Controller
public class JavascriptController {
@RequestMapping(method = RequestMethod.GET, value = "/js/test.js")
public String testjs() {
return "test.js";
}
}
The HTML view controllers remain unchanged.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With