WebMvcTest when Multiple TemplateResolver - spring-boot

I have added a second TemplateResolver because I would like to use also Thymeleaf to serve Template for Plain-Text Templates. When starting application it works fine, the Thymeleaf templates are being resolved.
But from now my #WebMvcTests are not working. I says, that:
Error resolving template [disclaimer/view], template might not exist or might not be accessible by any of the configured Template Resolvers
The TemplateResolver are configures like:
#Configuration
public class SitemapViewResolverConfiguration {
#Bean
public ITemplateResolver thymeleafTextTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/templates/sitemap/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".txt");
templateResolver.setTemplateMode(TemplateMode.TEXT);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setCheckExistence(TRUE);
return templateResolver;
}
}
#Configuration
public class PageViewResolverConfiguration {
#Bean
public ITemplateResolver thymeleafHtmlTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("classpath:/templates/view/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setCheckExistence(TRUE);
return templateResolver;
}
}
My template structure is as follows:
The test class is:
#RunWith(SpringRunner.class)
#WebMvcTest(DisclaimerController.class)
public class DisclaimerControllerTest {
#Autowired MockMvc mvc;
#Test
public void testGet() throws Exception {
mvc.perform(get("/disclaimer")
.andExpect(status().isOk())
.andExpect(view().name("disclaimer/view"))
;
}
}
Error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving template [disclaimer/view], template might not exist or might not be accessible by any of the configured Template Resolvers

Okay, I found the problem. As I use #WebMvcTest it didn't load my TemplateResolver. As before I relied on Spring Boot automatic resolver, I am using now two selfmade resolver. But they are not picked up by the test, that's why MockMvc could not resolve it.
I fixed it by adding Configuration as Import:
#RunWith(SpringRunner.class)
#WebMvcTest({PageViewResolverConfiguration.class, DisclaimerController.class})
public class DisclaimerControllerTest {
...
}

Related

Thymeleaf - return rendered template to String

I was using this solution as an example:
Can I render Thymeleaf templates manually from a String?
but after processing template I am getting not rendered template:
my template (plans/test.html):
<!doctype html>
<html lang="pl">
<div th:text="${loki}"></div>
</html>
Java code that should renderd the template:
#RestController
public class PlansPageRestController {
#Autowired
TemplateEngine myTemplateEngine;
#RequestMapping(value = {"/public/plans"}, method = RequestMethod.POST, produces = "application/json")
public Map<String,String> getPlans(#RequestParam Map<String, String> requestParams) {
Context ctx = new Context();
ctx.setVariable("loki", "Some test value");
String htmlTemplate = myTemplateEngine.process("plans/test.html", ctx);
Map<String,String> result = new HashMap<>();
result.put("html", htmlTemplate );
result.put("result", "success" );
return result;
}
}
but as a result I am getting content of plans/test.html so:
<!doctype html>
<html lang="pl">
<div th:text="${loki}"></div>
</html>
I am working with spring boot 3.0.0 and regarding to pom I am using thymeleaf:
<artifactId>thymeleaf-spring6</artifactId>
<version>3.1.0.RELEASE</version>
Can anyone help me in finding what I am doing wrong?
my thymeleaf configuration:
#Configuration
public class ThymeleafConfiguration implements WebMvcConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#Bean
public TemplateEngine myTemplateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.setTemplateResolver(templateResolver());
engine.setDialect(new LayoutDialect());
return engine;
}
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/templates/");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
resolver.setCacheTTLMs(0L);
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
}
The reason your standard Thymeleaf expression is not being evaluated is because you have replaced the Thymeleaf "standard" dialect with the layout dialect:
engine.setDialect(new LayoutDialect());
(I should say "the Spring dialect", given you are using Spring-Thymeleaf.)
If you need to use the layout dialect, then you can add it to the engine - and still keep the standard dialect as well:
engine.addDialect(new LayoutDialect());
Or, you may not need the layout dialect at all (you do not use it in the sample HTML file in the question, but maybe you use it elsewhere). If that is the case, you can remove this line of code.
Just to add: The default Spring Boot settings should work without you needing to define any ThymeleafConfiguration class. But, again, there may be other places where you need to use a custom configuration (e.g. the UTF-8 encoding).

What is the difference between SpringResourceTemplateResolver and ClassLoaderTemplateResolver?

I'm trying to cofigure my project. I have two variants of tempalteResolver.
if i use this one:
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(true);
return templateResolver;
}
i get an error that my template can't resolve the thymeleaf syntax th even when i add xmlns:th="http://www.thymeleaf.org"
and when i use the following code:
#Bean
public ClassLoaderTemplateResolver templateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(false);
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
i get an error that there is no templates under this path (/WEB-INF/templates).
Full path to my templates is src\main\webapp\WEB-INF\templates\
What is the best template resolver to be used and why?
Thanks!
You should be using SpringResourceTemplateResolver for web projects (using SpringMvc controllers), and ClassLoaderTemplateResolver for command line projects, or when you need to generate html for non-web applications (such as sending html email or something like that).
First error occured becouse spring security somehow didn't connect to a project and my
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
modelAndView.addObject("auth", auth);
Send nulls.
And second error i dunno why occured.

Problems adding spring webflow to a spring boot and joinfaces application

I am trying to add webflow to a spring boot app using joinfaces library.
I am using primefaces-spring-boot-starter and jetty-spring-boot-starter to configure jetty server.
Added necessary webflow dependencies to pom and configured necessary flowregistry, flowbuilderservices, flowexecutor and flowhandlermapping, ...
The application start correctly, reads the flows definitions from xmls and if enter to a flow via url the decision states are running correctly, reads the corresponding view state .xhtml file, calls the managed bean methods, and all are working apparently well.
But... once finished executing bean methods, when I hope to html be rendered in browser, the application is redirected to app root folder without any error in the log.
I have this behavior with all the flows of the application. Bean methods are executed correctly and when I hope to see the html... redirected to root.
Anyone tried to add webflow to a joinfaces jsf application successfully? I am missing to override some default configuration of joinfaces?
Thanks.
public class MvcConfiguration implements WebMvcConfigurer {
#Autowired
private WebFlowConfiguration webFlowConfiguration;
#Bean
public FlowHandlerMapping flowHandlerMapping() {
FlowHandlerMapping handlerMapping = new FlowHandlerMapping();
handlerMapping.setOrder(-1);
handlerMapping.setFlowRegistry(this.webFlowConfiguration.flowRegistry());
return handlerMapping;
}
#Bean
public FlowHandlerAdapter flowHandlerAdapter() {
JsfFlowHandlerAdapter adapter = new JsfFlowHandlerAdapter();
adapter.setFlowExecutor(this.webFlowConfiguration.flowExecutor());
return adapter;
}
#Bean
public ViewResolver faceletsViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setViewClass(JsfView.class);
resolver.setPrefix("/");
resolver.setSuffix(".xhtml");
return resolver;
}
}
#Configuration
public class WebFlowConfiguration extends AbstractFacesFlowConfiguration {
#Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.setBasePath("classpath*:/META-INF/resources/flows")
.addFlowLocationPattern("/**/*.xml")
.setFlowBuilderServices(flowBuilderServices())
.build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setDevelopmentMode(true)
.setViewFactoryCreator(new JsfViewFactoryCreator())
.build();
}
#Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(new FlowFacesContextLifecycleListener())
.addFlowExecutionListener(new SecurityFlowExecutionListener())
.setMaxFlowExecutionSnapshots(0)
.build();
}
}

How to use thymeleaf without controller

I want to use thymeleaf templates in my spring boot application. I've some html pages in the src/resources/public directory and I want them to be served wihout writing a controller because I want to write a front end application. I can access the index.html file at http://localhost:8080/index.html but it's not using the thymeleaf syntax. How can I do it?
I've added the thymeleaf dependency, tried writing a SpringResourceTemplateResolver bean but still no luck. Here is what I've done so far:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public SpringResourceTemplateResolver templateResolver(){
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/public/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(true);
return templateResolver;
}
}

Several template locations for Thymeleaf in Spring Boot

Currently Spring Boot allow one value for the Thymeleaf templates location with the spring.thymeleaf.prefix property.
The default value is classpath:/templates/.
I want to have another location for the thymeleaf templates (but keep the default one), outside the jar, for example:
spring.thymeleaf.prefix = classpath:/templates/, file:/resources/templates
Do i have to define another template resolver for the new location i want ?
Define the setting in the application.properties file
spring.thymeleaf.templateResolverOrder=1
Now in your custom Bean which creates ITemplateResolver set order to 0 along with prefix and suffix. This way spring boot will listen to both places
Setting order to 0 is important
An example of bean creation can be
#Bean
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("mails/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode(TemplateMode.HTML);
emailTemplateResolver.setCharacterEncoding("UTF-8");
emailTemplateResolver.setOrder(0);
emailTemplateResolver.setCheckExistence(true);
return emailTemplateResolver;
}
MyExample
In order to define multiple template locations, you must define Spring beans implementing ITemplateResolver.
#Bean
public SpringResourceTemplateResolver firstTemplateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setPrefix("classpath:/templates/templatelocation/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(0);
templateResolver.setCheckExistence(true);
return templateResolver;
}
#Bean
public ClassLoaderTemplateResolver secondTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("templates/templatelocation/other/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setOrder(1);
templateResolver.setCheckExistence(true);
return templateResolver;
}
You can also check out the blog post detailing the usage.

Resources