I have the following project structure in my Spring boot app, in which I want to use Thymeleaf
projectName
-Gradle-Module1(Spring boot module)
-build
-src
-main
-resources
-templates
index.html
build.gradle
-Gradle-Module2
...
build.gradle
...
but the spring-boot cannot find my template directory and is showing warning
Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
PS: I am using #EnableAutoConfiguration
In my controller code I am doing something like:
#Controller
#EnableAutoConfiguration
public class BaseController {
#RequestMapping(value = "/")
public String index() {
return "index.html";
}
}
and index.html file just prints hello world.
So typically it should look inside src/resources/templates/(of same Gradle module I suppose), but somehow it is not able to find it.
When I try to access localhost:8080 I am getting below error
Error resolving template "index.html", template might not exist or might not be accessible by any of the configured Template Resolvers`
Is there anything I am missing?
Any pointers appreciated. Thanks.
You have to configure Thymeleaf as follows:
#Configuration
public class ThymeleafConfig {
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setCacheable(false);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.addTemplateResolver(templateResolver());
return springTemplateEngine;
}
#Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
}
Spring doc recommends to add #EnableAutoConfiguration annotation to your primary #Configuration class.
Also it seems you have wrong project structure, the typical package hierarchy is:
src
|- main
|- java
|- resources
|- static
|- templates
|- test
In this case your templates will be in src/main/resources/templates, not in src/resources/templates/.
You should only return the file name. E.g without the .hmtl
#RequestMapping(value = "/")
public String index() {
return "index";
}
#GetMapping("/")
public String index() {
return "index";
}
Related
My Project structure is as follows
|src
|--main
|---webapp
|----static
|-----CSS
|-----HTML
|-----js
I am trying to return an HTML resource via my controller for links that are directly under root there is no issue but for other links, I am facing problems.
Here is my controller
#Controller
public class HtmlServer {
#RequestMapping({"/", "/index", "/index.html", "/index.jsp", "/home","/home.html","/home.jsp"})
public ModelAndView index() {
return new ModelAndView("html/index.html");
}
#RequestMapping(method = RequestMethod.GET, value = "/support/{id}/{accessToken}")
public ModelAndView start(#PathVariable Long id, #PathVariable String accessToken) {
return new ModelAndView("html/index.html");
}
}
Here is my WebMvcConfigurerAdapter extending class
#Component
#ConfigurationProperties
#Configuration
#EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {
#Bean
public InternalResourceViewResolver internalResourceViewResolver(){
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("static/");
return internalResourceViewResolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("static/js/")
.setCachePeriod(0);
registry.addResourceHandler("/css/**").addResourceLocations("static/css/")
.setCachePeriod(0);
registry.addResourceHandler("/support/**").addResourceLocations("/static/")
.setCachePeriod(0);
}
}
When I open / or /index.html the controller returns the given value and in return i am served the correct resource.
But when I try to use /support/1/xsdda I am mapped to /support/1/static/html/index.html Can someone explain the internals and logically point out my mistake.
Thanks!
Create folder WEB-INF inside webapp and put your HTML folder inside it
set prefix of resolver to /WEB-INF/HTML/
set suffix of resolver to .html
call it by returning "index"
The Servlet 2.4 specification says this about WEB-INF (page 70):
A special directory exists within the application hierarchy named
WEB-INF. This directory contains all things related to the
application that aren’t in the document root of the application. The
WEB-INF node is not part of the public document tree of the
application. No file contained in the WEB-INF directory may be served
directly to a client by the container. However, the contents of the
WEB-INF directory are visible to servlet code using the getResource
and getResourceAsStream method calls on the ServletContext, and may
be exposed using the RequestDispatcher calls.
I'm working on a project using Spring MVC, Spring Boot, Gradle and Thymeleaf. I was wondering if there's a way to avoid controllers returning lengthy String paths to a specific view in a subfolder?
My views are currently in resources/templates/views/home/
public String index( Model model ) {
return "views/home/index";
}
I'm looking to only have to return something like home/index or home/someotherpage for the HomeController.
Thanks!
Yes, it is possible by defining templateResolver bean in your configuration:
#Configuration
public class TemplateConfig {
#Bean
public SpringResourceTemplateResolver templateResolver() {
final SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setCacheable(false);
templateResolver.setPrefix("classpath:/templates/views/");
templateResolver.setSuffix(".html");
return templateResolver;
}
}
Now you can use your return index page in your controller as:
public String index( Model model ) {
return "home/index";
}
I am migrating my project from Thymeleaf 2 to 3 and I'm having an issue with the email template resolver interfering with my web template resolver.
When we first implemented Thymeleaf we followed this document to allow for email templates and web templates and had no issues (section 4.2):
http://www.thymeleaf.org/doc/articles/springmail.html
During conversion to Thymeleaf 3, I worked with ONLY the one template resolver for HTML templates (using the SpringResourceTemplateResolver) and the conversion was fine. I was able to run my application without any problems and the view templates all rendered without problems.
However, when including the email template resolver (using the ClassLoaderTemplateResolver), the following error occurs when going to any controller endpoint that returns a view:
java.io.FileNotFoundException: ClassLoader resource "thymeleaf/thymeleaf/login.html" does not exist
Which indicates it is trying to load the template from the ClassLoaderTemplateResolver and not the SpringResourceTemplateResolver. In Thymeleaf 2 setting the Order attribute solved this problem but this doesn't appear to work in Thymeleaf 3.
I couldn't find any help in the Thymeleaf 3 documentation for having 2 Template resolvers like there was in Thymeleaf 2 docs.
Any suggestions on how to get this working or documentation that I may have overlooked?
I have this same setup (a ClassLoaderTemplateResolver for emails and a SpringResourceTemplateResolver for html page templates). I think you need to set this property:
resolver.setCheckExistence(true);
On whichever of your template resolvers happens first, otherwise spring will assume it exists and you will see the error your seeing.
You can use the following setup..
AppConfig.java
#Configuration
#EnableWebMvc
#ComponentScan("myapp")
public class AppConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(webTemplateEngine());
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return resolver;
}
#Bean
public TemplateEngine webTemplateEngine() {
//this method must be defined as a bean otherwise i18n messages are not found
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.addTemplateResolver(webTemplateResolver());
return engine;
}
private ITemplateResolver webTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/thymeleaf/");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setSuffix(".html");
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return resolver;
}
#Bean
public TemplateEngine emailTemplateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(emailTemplateResolver());
return templateEngine;
}
private ITemplateResolver emailTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/thymeleaf/email/");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setSuffix(".html");
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return resolver;
}
}
And then where you need to use the email template engine, just autowire the emailTemplateEngine and use it
#Autowired
private TemplateEngine emailTemplateEngine;
I have a (gradle/java/eclipse) project with what seems to me to be quite a standard folder structure
...main
java
...controller
...service
resources
webapp
...resources
WEB-INF
I'm having an issue I just don't understand although I have worked around it in a very messy way. If I specify the controllers folder in the component scan of my WebMvcConfigurerAdapter then the services classes can't pick up properties using the configured PropertySourcesPlaceholderConfigurer bean. If I broaden the component scan out the jsp files don't pick up the css includes!
So with this config class all is well but the properties aren't resolved int he service implementation class
config class
#EnableWebMvc
#Configuration
#ComponentScan({ "comm.app.controller" })
#PropertySource({ "classpath:app.properties" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
//used to handle html put and delete rest calls
#Bean(name = "multipartResolver")
public CommonsMultipartResolver createMultipartResolver() {
CommonsMultipartResolver resolver=new CommonsMultipartResolver();
resolver.setDefaultEncoding("utf-8");
return resolver;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfig() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Service implementation class begins
#Service("appService")
#PropertySource({ "classpath:app.properties" })
public class appServiceImpl implements appService {
private RestTemplate restTemplate = new RestTemplate();
#Value("${property.reference}")
private String propref;
...
In this case ${property.reference} is not picked up but the view page styling (picked up from ...webapp\resources... .css) is fine.
If I change
#ComponentScan({ "comm.app.controller" })
to
#ComponentScan({ "comm.app" })
The properties are picked up (presumably because the propertyConfig bean comes into scope ?) but the local styling files can't be found ? Any link references to files webapp\resources... .css fails.
In the end I came to a bad (!?) solution of
1) keeping the scope of #ComponentScan({ "comm.app.controller" })
2) hacking the serviceimplementation class as so...
#Configuration
#Service("appService")
#PropertySource({ "classpath:app.properties" })
public class appServiceImpl implements appService {
private RestTemplate restTemplate = new RestTemplate();
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfig() {
return new PropertySourcesPlaceholderConfigurer();
}
#Value("${property.reference}")
private String propref;
...
Can anyone tell me if I've configured the path the the resources file incorrectly or maybe should be doing something differently with the propertyConfig bean ? (maybe injecting it or declaring another one in a different configuration file ?)
I'm struggling with trying to return a static web page from a spring MVC controller.
I followed this tutorial: http://www.tutorialspoint.com/spring/spring_static_pages_example.htm and yet it still isn't working.
This is how I defined the configuration (used configuration class):
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan({ "com.my.web.api"})
#ImportResource("classpath:db-context.xml")
public class ApiServletConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("/resources/");
internalResourceViewResolver.setSuffix("*.html");
return internalResourceViewResolver;
}
}
The controller method:
#RequestMapping(value = "/{id}/view", method = RequestMethod.GET, produces = "text/html")
#ResponseBody
public String getPostByIdHtml( #PathVariable String id) throws IOException {
return "/resources/Post.html";
}
Under the webapp folder there's a folder named "resources" and under which there's a file "Post.html". What else should I do in order to get this page returned as HTML instead of getting the string "resources/Post.html"?
Thanks for the help.
Please remove the annotation #ResponseBody. Your browser should be redirected to the desired page once the annotation is removed.
This annotation indicates that the value returned by a method in your controller should be bound to the web response body. In your case, you do not need that: you need Spring to render page /resources/Post.html, so no need for this annotation.