I have a project where data from several sources are being processed into some data structures. After the program is done building these structures, I want it to set up a server that enables users to fine-tune these structures manually. I decided that Spring MVC on an embedded Tomcat server set up using Spring Boot is just what I need.
I want to use Thymeleaf as view technology, and therefore did
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Main {
public static void main(String... args) throws Exception {
// Lots of initialization ...
SpringApplication.run(Main.class, args);
}
@Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/resources/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
return resolver;
}
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
@Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[]{"*"});
viewResolver.setCache(false);
return viewResolver;
}
}
and
@Controller
public class WebController {
@RequestMapping(value="/greeting", method=RequestMethod.GET)
public String greeting() {
return "greeting";
}
}
But even though there is a view file at /resources/views/greeting.html
, the server's reply to the URL http://localhost:8080/greeting
is
org.thymeleaf.exceptions.TemplateInputException: Error resolving template "greeting", template might not exist or might not be accessible by any of the configured Template Resolvers
After stepping through the code in a debugger it appears that at some point, ServletContext
, which is supposed to return the view file as a stream, looks in a temporary folder like
C:\Users\Michael\AppData\Local\Temp\tomcat-docbase.971027024999448548.8080
which is empty.
Now I get that I need to either
Have the resources deployed to the temporary folder when the server starts up
Have the server operate in the directory where the resources already are
My problem just is that I don't know how to do either, or which approach is the best. Something tells me that 1 is the better wisdom, but any suggestion is welcome.
Edit
Ok, I ended up with something that seems to work. While Joe's answer definitely helped me get on the way, it also appears that I had to change my Maven configuration in a way that puzzles me.
After putting the template greeting.html
into /resources/templates/greeting.html
and adding resources
to the build path, I got the error
javax.servlet.ServletException: Circular view path [greeting]: would dispatch back to the current handler URL [/word/greeting] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
In other words, Thymeleaf seemed to not be properly configured. After some fiddling I ended up changing the version of spring-boot-starter-parent
in pom.xml
from 0.5.0.BUILD-SNAPSHOT
to 0.5.0.M6
:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--<version>0.5.0.BUILD-SNAPSHOT</version>-->
<version>0.5.0.M6</version>
</parent>
and removing the version tag from the Thymeleaf dependency
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId>
<!--<version>${thymeleaf-spring3-version}</version>-->
</dependency>
</dependencies>
After this, it worked.
Can someone please explain why I needed to change the version of spring-boot-starter-parent
to be able to remove the version tag from thymeleaf-spring3
, and why that was necessary?
The servlet context root is not the best place for templates in an embedded server. There is a way to do it, but if I were you I would go with the flow and use the classpath. If you allow Spring Boot to configure the template resolver (also recommended) then it will look in
classpath:/templates
by default. There are several samples that use thymeleaf in the Boot code base, so it should be easy to modify one of those if you have different requirements.