I want to have two template resolver BEANs in one project.
first template resolver is using already. it works well.
#Bean
public ITemplateResolver feTemplateResolver(SpringResourceResourceResolver thymeleafResourceResolver) {
String prefix = "classpath:fe20/is/templates/";
boolean cacheable = true;
if (environment.acceptsProfiles(LOCAL)) {
String localResourcePath = environment.getRequiredProperty("FEB_HOME");
prefix = "file:///" + localResourcePath + "/is/templates/";
cacheable = false;
}
TemplateResolver resolver = new TemplateResolver();
resolver.setResourceResolver(thymeleafResourceResolver);
resolver.setPrefix(prefix);
resolver.setSuffix(".html");
resolver.setTemplateMode(StandardTemplateModeHandlers.LEGACYHTML5.getTemplateModeName());
resolver.setCharacterEncoding("UTF-8");
resolver.setCacheable(cacheable);
resolver.setOrder(0);
return resolver;
}
and i added anthoer resolver for thymeleaf like,
#Bean
public ServletContextTemplateResolver servletContextTemplateResolver() {
ServletContextTemplateResolver servletContextTemplateResolver = new ServletContextTemplateResolver();
servletContextTemplateResolver.setPrefix("classpath:resources/templates/");
servletContextTemplateResolver.setSuffix(".html");
servletContextTemplateResolver.setTemplateMode("HTML5");
servletContextTemplateResolver.setOrder(1);
return servletContextTemplateResolver;
}
#Bean
public SpringTemplateEngine springTemplateEngine() {
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setTemplateResolver(servletContextTemplateResolver());
return springTemplateEngine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
thymeleafViewResolver.setTemplateEngine(springTemplateEngine());
return thymeleafViewResolver;
}
and then i run this app, request correct url, then i get an error
HTTP Status 500 - Request processing failed; nested exception is
org.thymeleaf.exceptions.TemplateInputException: Error resolving
template "statistics/index", template might not exist or might not be
accessible by any of the configured Template Resolvers
THE QUESTION IS,
through so many troubles,
i solved this problem by removing SpringTemplateEngin/ThymeleafViewResolver BEANs. so the remained BEAN is only ServletContextTemplateResolver.
why did ThymeleafViewResolver not work?
and why did it works when i use only ServletContextTemplateResolver BEAN?
Related
Since Thymeleaf 3, Thymeleaf prefers the use of SpringResourceTemplateResolver (https://www.thymeleaf.org/doc/articles/thymeleaf3migration.html). So I decided to go from ClassLoaderTemplateResolver to SpringResourceTemplateResolver:
#Configuration
#EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
registry.setOrder(1);
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(0);
resolver.setCheckExistence(true);
return resolver;
}
#Bean
public SpringResourceTemplateResolver templateResolver2() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("/templates-2/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(1);
resolver.setCheckExistence(true);
return resolver;
}
}
Unfortunately, when implementig like this, I'll get an error:
Error resolving template [index], template might not exist or might not be accessible by any of the configured Template Resolvers.
To be honest, I've simple replaced ClassLoaderTemplateResolver with SpringResourceTemplateResolver in the hope, this will work. It doesn't. But searching for a working solution dealing with two template locations, all I find are outdated samples using ClassLoaderTemplateResolvers.
Trying to implement the code snippet provided by Thymeleaf as shown here https://www.thymeleaf.org/doc/articles/thymeleaf3migration.html won't work either when using two template directories, besides the fact, that this code itself uses the deprecated WebMvcConfigurerAdapter.
Is there any example how to configure a Spring Boot application using Thymeleaf having two or more template locations which isn't completely outdated?
So after a while and many many tryouts I've finally got the templates working. Since there isn't any decent answer to my question flying round the internet, I will post my solution for others:
#Configuration
public class ThymeleafConfig implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(#Autowired ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("classpath:/templates-1/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(1);
templateResolver.setCheckExistence(true); /* FYI: necessary to chain TemplateResolvers */
templateResolver.setCacheable(false); /* FYI: during development -> false, so that we can see changes we make */
return templateResolver;
}
#Bean
public SpringResourceTemplateResolver templateResolver2() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("classpath:/templates-2/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(2);
templateResolver.setCheckExistence(true); /* FYI: necessary to chain TemplateResolvers */
templateResolver.setCacheable(false); /* FYI: during development -> false, so that we can see changes we make */
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
/* SpringTemplateEngine automatically applies SpringStandardDialect and
enables Spring's own MessageSource message resolution mechanisms. */
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(this.templateResolver());
templateEngine.addTemplateResolver(this.templateResolver2());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(this.templateEngine());
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setCache(false); /* FYI: during development -> false */
viewResolver.setOrder(1);
return viewResolver;
}
}
I hope this will help others to save time and nerves^^.
If you are using Spring Boot, you can add an extra resolver on top of the default one like this:
First, add this to application.properties:
# This ensures that the default HTML template resolver of Thymeleaf has priority over our custom SVG resolver
spring.thymeleaf.template-resolver-order=0
Then add the extra resolver in a #Configuration class:
#Configuration
public class MyApplicationConfiguration {
#Bean
public ITemplateResolver svgTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/templates/svg/");
resolver.setSuffix(".svg");
resolver.setTemplateMode("XML");
return resolver;
}
}
There is no need to manually define SpringTemplateEngine and ViewResolver beans.
You can disable caching during development using spring.thymeleaf.cache=false.
I have a problem with finding a thymeleaf template on docker. I'm familiar with the leading slash problem in ordinary controllers. However I'd now like to use thymeleaf to render email bodies.
My code looks like this:
#Component
public class HtmlEmailDocumenter implements Documenter {
#Autowired
SpringTemplateEngine thymeleafTemplateEngine;
// more dependencies
#Override
public void accept(Documentable documentable){
Context thymeleafContext = new Context();
thymeleafContext.setVariable("doc", documentable);
String template = "mail/default";
String htmlBody = thymeleafTemplateEngine.process(template, thymeleafContext);
// send the email...
}
}
The template in question is under /src/main/resources/templates/mail/default.html. I have alternatively tried using "mail/default.html" in the source code. Doesn't work either in docker.
Any hints welcome.
I am doing something similar in non-Boot Spring application by defining the template engine template and resolver as follows:
#Bean
public ResourceBundleMessageSource emailMessageSource() {
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("templates/email/mailMessages");
return messageSource;
}
#Bean
public TemplateEngine emailTemplateEngine() {
final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
return templateEngine;
}
private ITemplateResolver htmlTemplateResolver() {
final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setOrder(Integer.valueOf(2));
templateResolver.setPrefix("/templates/email/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setCacheable(false);
return templateResolver;
}
I then refer to an email message template using just the name of the template within the /templates/email directory without extension.
i have this project structure
--> src/main/java
--> src/main/resources/static/myFolder/css/common.css
i have this configuration class
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
private LocalValidatorFactoryBean localValidatorFacotryBean;
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.setBasePath("classpath:flow")
.addFlowLocationPattern("/myflows/myflow1.xml")
.addFlowLocationPattern("/myflows/myflow2.xml")
.setFlowBuilderServices(this.flowBuilderServices())
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(this.flowRegistry()) //
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder() //
.setViewFactoryCreator(this.mvcViewFactoryCreator()) // Important!
.setValidator(this.localValidatorFacotryBean).build();
}
// ----------------------------------------------------------
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1);
handlerMapping.setFlowRegistry(this.flowRegistry());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
FlowHandlerAdapter handlerAdapter = new FlowHandlerAdapter();
handlerAdapter.setFlowExecutor(this.flowExecutor());
handlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
return handlerAdapter;
}
#Bean
public ViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Collections.<ViewResolver>singletonList(this.thymeleafViewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
#Bean
#Description("Thymeleaf AJAX view resolver for Spring WebFlow")
public AjaxThymeleafViewResolver thymeleafViewResolver() {
AjaxThymeleafViewResolver viewResolver = new AjaxThymeleafViewResolver();
viewResolver.setViewClass(FlowAjaxThymeleafView.class);
viewResolver.setTemplateEngine(this.templateEngine());
viewResolver.setCharacterEncoding("UTF-8");
return viewResolver;
}
#Bean
#Description("Thymeleaf template resolver serving HTML 5")
public ClassLoaderTemplateResolver templateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("templates/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
#Bean
#Description("Thymeleaf template engine with Spring integration")
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(this.templateResolver());
return templateEngine;
}
I always get this error No mapping found for HTTP request with URI [/static/common.css] in DispatcherServlet with name 'dispatcherServlet'
I always get this error it seems that the tags like <link rel = "stylesheet" href = "/ static / myFolder / common.css" /> are solved as html
I am writing a JUnit test, which should test the title of an html page. This project is a SpringBoot, Thymeleaf starter project.
HtmlPath:
private final static String HTML_PATH = "/pages/dashboard/dashboard.html";
JUnitTest:
#Test
public void shouldRenderPageTitle() throws IOException, NodeSelectorException {
Map<String,Object> model = new HashMap<>();
model.put("pageTitle", "expected title");
HtmlElements tags = testEngine.process(HTML_PATH, model);
assertThat(tags.matching("title"), isSingleElementThat(hasOnlyText("expected title")));
}
ThymeleafConfiguration
#Configuration
public class ThymeleafConfig {
#Bean
public TemplateResolver templateResolver() {
TemplateResolver templateResolver = new TemplateResolver();
templateResolver.setPrefix("/resources/templates/");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.addDialect(new LayoutDialect());
templateEngine.addDialect(new SpringStandardDialect());
return templateEngine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
return viewResolver;
}
}
The Error:
org.thymeleaf.exceptions.TemplateInputException: Error resolving template "/pages/dashboard/dashboard.html"
You have to use
private final static String HTML_PATH = "/pages/dashboard/dashboard"; //no ".html"
Can you try replacing this line of code
templateResolver.setPrefix("/resources/templates/");
with this one
templateResolver.setPrefix("templates/");
I am new in spring configuration with jasper report ,
I have a problem calling the correct file for my jrxml when I setup the tiles configuration.
#Bean
public InternalResourceViewResolver setupViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver ();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setOrder(2);
resolver.setViewClass(JstlView.class);
return resolver;
}
#Bean
public UrlBasedViewResolver urlBasedViewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(TilesView.class);
viewResolver.setOrder(1);
return viewResolver;
}
when calling the the file. it append .jsp to the end of the file.
I tried this one but still not doesnt work :
#Autowired
ServletContext servletContext;
#Bean
public XmlViewResolver getXmlViewResolver() {
XmlViewResolver resolver = new XmlViewResolver();
Resource resource = new ClassPathResource("classpath:reports/testReport1.jrxml");
resolver.setLocation(resource);
resolver.setOrder(0);
return resolver;
}
You can try this:
#Bean
public JasperReportsViewResolver getJasperReportsViewResolver() {
JasperReportsViewResolver resolver = new JasperReportsViewResolver();
resolver.setPrefix("resources/jasperreports/");
resolver.setSuffix(".jasper");
resolver.setReportDataKey("datasource");
resolver.setViewNames(new String[] {"Report_*"});
resolver.setViewClass(JasperReportsMultiFormatView.class);
resolver.setOrder(0);
return resolver;
}
Where:
"resources/jasperreports/" is the folder where you have all your reports.
".jasper" is the the extension of compilled jasper report.
new String[] {"Report_*"} is the prefix of the jasper reports.