Spring Boot adding thymeleaf-layout-dialect - spring-mvc

I am using spring boot (v1.5.3.BUILD-SNAPSHOT)
I am new to spring boot.
Using gradle
Note that the normal thymeleaf dialect works fine (th:...)
spring-boot-starter-thymeleaf\1.5.3.BUILD-SNAPSHOT
I want to add thymeleaf-layout-dialect
I added the dependency
compile('nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect')
the documentation says to add the dialect by doing the following
TemplateEngine templateEngine = new TemplateEngine(); // Or
SpringTemplateEngine for Spring config
templateEngine.addDialect(new LayoutDialect());
So i added a configuration class
#Configuration
public class MyConfiguration {
#Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addDialect(new LayoutDialect());
return templateEngine;
}
}
but when I try running the app I get the following error
org.thymeleaf.exceptions.ConfigurationException: Cannot initialize: no template resolvers have been set
at org.thymeleaf.Configuration.initialize(Configuration.java:203) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.initialize(TemplateEngine.java:827) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.spring4.view.ThymeleafView.renderFragment(ThymeleafView.java:203) ~[thymeleaf-spring4-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.spring4.view.ThymeleafView.render(ThymeleafView.java:190) ~[thymeleaf-spring4-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1282) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.8.BUILD-SNAPSHOT.jar:4.3.8.BUILD-SNAPSHOT]
Can someone tell me how to add the thymeleaf-layout-dialect correctly?

The issue is:
org.thymeleaf.exceptions.ConfigurationException: Cannot initialize: no template resolvers have been set
To integrate Thymeleaf with Spring, you need to configure 3 beans:
ThymeleafViewResolver Bean - You would be set it with a template engine
SpringTemplateEngine Bean - You would be set it with a template resolver
TemplateResolver Bean
In your templateEngine bean you didn't set any template resolver, so you might change your templateEngine() method as following:
#Bean
public SpringTemplateEngine templateEngine(TemplateResolver templateResolver){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.addDialect(new LayoutDialect());
return templateEngine;
}
Spring will provide you with a templateResolver bean of SpringTemplateEngine.
BTW If you define spring-boot-starter-thymeleaf as dependency, it will provide thymeleaf-layout-dialect as a dependency with the convenient version, then Spring will use ThymeleafAutoConfiguration.java - Spring Boot 1.5.x to configure a default beans for the three required beans.
For example:
LayoutDialect bean is define here ThymeleafWebLayoutConfiguration.ThymeleafWebLayoutConfiguration():
#Configuration
#ConditionalOnClass(name = "nz.net.ultraq.thymeleaf.LayoutDialect")
protected static class ThymeleafWebLayoutConfiguration {
#Bean
#ConditionalOnMissingBean
public LayoutDialect layoutDialect() {
return new LayoutDialect();
}
}
SpringTemplateEngine bean is defined with a template resolver and dialect from here ThymeleafWebLayoutConfiguration.ThymeleafDefaultConfiguration():
#Configuration
#ConditionalOnMissingBean(SpringTemplateEngine.class)
protected static class ThymeleafDefaultConfiguration {
private final Collection<ITemplateResolver> templateResolvers;
private final Collection<IDialect> dialects;
public ThymeleafDefaultConfiguration(
Collection<ITemplateResolver> templateResolvers,
ObjectProvider<Collection<IDialect>> dialectsProvider) {
this.templateResolvers = templateResolvers;
this.dialects = dialectsProvider.getIfAvailable();
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
for (ITemplateResolver templateResolver : this.templateResolvers) {
engine.addTemplateResolver(templateResolver);
}
if (!CollectionUtils.isEmpty(this.dialects)) {
for (IDialect dialect : this.dialects) {
engine.addDialect(dialect);
}
}
return engine;
}
}
And finally a thymeleafViewResolver bean is defined here AbstractThymeleafViewResolverConfiguration.thymeleafViewResolver():
#Bean
#ConditionalOnMissingBean(name = "thymeleafViewResolver")
#ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
configureTemplateEngine(resolver, this.templateEngine);
resolver.setCharacterEncoding(this.properties.getEncoding().name());
resolver.setContentType(appendCharset(this.properties.getContentType(),
resolver.getCharacterEncoding()));
resolver.setExcludedViewNames(this.properties.getExcludedViewNames());
resolver.setViewNames(this.properties.getViewNames());
// This resolver acts as a fallback resolver (e.g. like a
// InternalResourceViewResolver) so it needs to have low precedence
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
resolver.setCache(this.properties.isCache());
return resolver;
}
which is extended by ThymeleafAutoConfiguration.Thymeleaf2ViewResolverConfiguration:
#Bean
#ConditionalOnMissingBean(name = "thymeleafViewResolver")
#ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
configureTemplateEngine(resolver, this.templateEngine);
resolver.setCharacterEncoding(this.properties.getEncoding().name());
resolver.setContentType(appendCharset(this.properties.getContentType(),
resolver.getCharacterEncoding()));
resolver.setExcludedViewNames(this.properties.getExcludedViewNames());
resolver.setViewNames(this.properties.getViewNames());
// This resolver acts as a fallback resolver (e.g. like a
// InternalResourceViewResolver) so it needs to have low precedence
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
resolver.setCache(this.properties.isCache());
return resolver;
}
Hope it is clear now.

Related

Thymeleaf View Resolver with SpringMVC webapp

How if one can use ThymeleafViewResolver as a defalt view resolver.
Currentely my WebMvcConfig looks like this
#Configuration
#ComponentScan(basePackages="com.greatLearning.ticketAPI.controller")
public class WebMvcConfig implements WebMvcConfigurer {
#Autowired
ApplicationContext applicationContext;
// #Override
// public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// configurer.enable();
// }
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
//Thymeleaf ViewResolver
#Bean
public SpringResourceTemplateResolver templateResolver(){
// SpringResourceTemplateResolver automatically integrates with Spring's own
// resource resolution infrastructure, which is highly recommended.
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(this.applicationContext);
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
// HTML is the default value, added here for the sake of clarity.
templateResolver.setTemplateMode(TemplateMode.HTML);
// Template cache is true by default. Set to false if you want
// templates to be automatically updated when modified.
templateResolver.setCacheable(true);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine(){
// SpringTemplateEngine automatically applies SpringStandardDialect and
// enables Spring's own MessageSource message resolution mechanisms.
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
// Enabling the SpringEL compiler with Spring 4.2.4 or newer can
// speed up execution in most scenarios, but might be incompatible
// with specific cases when expressions in one template are reused
// across different data types, so this flag is "false" by default
// for safer backwards compatibility.
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Bean
public ThymeleafViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
// NOTE 'order' and 'viewNames' are optional
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[] {".html", ".xhtml"});
return viewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
for *.jsp view it is working just fine, but I want to use Thymeleaf to resolve my .html templates becasue I don't want to use *.jsp .
One thing to note is that in my controller
TestController.java
#RequestMapping("/hello")
public String method1() {
return "hello";
}
#RequestMapping("/hello2")
#ResponseBody
public String method2() {
return "hello"; //This works fine
}
when I hit /hello api this is what I get
How do I configre viewResolver so that spring picks up ThymeleafViewResolver to resolve html rather than jsp
Problem Solved!!!!!
Here is what I did after an hour of debugging the libraries
in WebMvcConfig.java I revomed the public InternalResourceViewResolver resolver() method as it is sed to configure jsp.
Now in ThymeleafViewResolver viewResolver() remove these two:
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[] {".html", ".xhtml"});
got help through debgging and [this post](Problem Solved!!!!!
Here is what I did after an hour of debugging the libraries
in WebMvcConfig.java I revomed the public InternalResourceViewResolver resolver() method as it is sed to configure jsp.
Now in ThymeleafViewResolver viewResolver() remove these two:
viewResolver.setOrder(1);
viewResolver.setViewNames(new String[] {".html", ".xhtml"});
got help through debgging and this post.
As to why I will answer if anyone is interested. :)

RedisSentinelConfiguration using spring.redis.sentinel.nodes with spring boot

Trying to configure spring boot application with spring-session and redis but having below issue. Not able to resolve it.
Constructor threw exception; nested exception is java.lang.IllegalStateException: BeanFactory has not been injected into #Configuration class
This code works fine for me
#Configuration
#EnableRedisHttpSession
public class HttpSessionConfig {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(SLAVE_PREFERRED)
.build();
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
.master("mymaster")
.sentinel("192.168.56.50", 26379)
.sentinel("192.168.56.50", 26380)
.sentinel("192.168.56.50", 26381);
#Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(sentinelConfig, clientConfig);
}
}
but not this code using PropertySource.
Spring document says:-
**RedisSentinelConfiguration can also be defined with a PropertySource, which lets you set the following properties:
Configuration Properties
spring.redis.sentinel.master: name of the master node.
spring.redis.sentinel.nodes: Comma delimited list of host:port pairs.**
#Configuration
#EnableRedisHttpSession
#PropertySource(name="application", value="classpath:application.properties")
public class HttpSessionConfig {
#Resource
ConfigurableEnvironment environment;
#Bean
public PropertiesPropertySource propertySource() {
return (PropertiesPropertySource) environment.getPropertySources().get("defaultProperties");
}
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.readFrom(SLAVE_PREFERRED)
.build();
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration(propertySource());
#Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(sentinelConfig, clientConfig);
}
}
application.properties
server.port=8090
spring.security.user.name=admin
spring.security.user.password=admin
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.56.50:26379,192.168.56.50:26380,192.168.56.50:26381
spring.application.name=spring-session-demo
The format of sentinel nodes property is comma separated key:value pairs. So you can extract host and port by java split() function.
#Autowired
private Environment env;
#Bean
public LettuceConnectionFactory connectionFactory() {
RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration();
String master = env.getProperty("spring.redis.sentinel.master");
String nodes = env.getProperty("spring.redis.sentinel.nodes");
sentinelConfig.master(master);
for (String node : nodes.split(",")) {
String split[] = node.split(":");
sentinelConfig.sentinel(split[0], Integer.parseInt(split[1]));
}
...
}

thymeleaf 3 spring 5 load css

I'm trying to configure Spring5 and Thymeleaf3 togheter.
I'm working on Eclipse, I build with clean install and run the app with springboot:run.
I've setup a controller and a couple of template and css but it seems that thymeleaf cannot find the css, in the browser it shows the template (es. 'panda.html') without loading the css but if I open manually the .html the browser load also the .css . What i need to add to my code?
this is the mapping
#Controller
public class MyController {
#Autowired
UtentiRepository utentiRepository;
#GetMapping("/gab")
public String panda(Model model) {
return "panda";
}
and this is the template resolver
#Bean
public SpringResourceTemplateResolver templatecssResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("classpath:/static/css/");
templateResolver.setSuffix(".css");
return templateResolver;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("classpath:/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(templatecssResolver());
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
registry.viewResolver(resolver);
}
You've to override the addResourceHandlers(..) method of the you calls that implements the WebMvcConfigurerAdapter not as a bean (SpringResourceTemplateResolver )
SO just add the overiding method
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**")
.addResourceLocations("classpath:/static/css/");
}
in your template use
<link href="<c:url value="/css/style.css" />" rel="stylesheet">
or using themleaf
<link th:href="#{/css/style.css}" />" rel="stylesheet">

Multiple View Resolvers not working with thymeleaf

When I use the following configuration of Thymeleaf for views as well as sending custom emails, it is not working
#Configuration
public class ThymeleafConfig {
#Bean
public ITemplateResolver classLoaderTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("/templates/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(StandardTemplateModeHandlers.LEGACYHTML5.getTemplateModeName());
templateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return templateResolver;
}
#Bean
public ITemplateResolver webTemplateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/public/");
resolver.setSuffix(".html");
resolver.setTemplateMode(StandardTemplateModeHandlers.LEGACYHTML5.getTemplateModeName());
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
resolver.setCacheable(false);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(webTemplateResolver());
templateEngine.addTemplateResolver(classLoaderTemplateResolver());
return templateEngine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return resolver;
}
}
View Resolution is working fine. But when I try to resolve a template by passing org.thymeleaf.context.Context to the template engine, following exception is thrown.
2017-10-06 13:36:27.962 ERROR 79725 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "resultPdf": Resource resolution by ServletContext with org.thymeleaf.resourceresolver.ServletContextResourceResolver can only be performed when context implements org.thymeleaf.context.IWebContext [current context: org.thymeleaf.context.Context]
org.thymeleaf.exceptions.TemplateProcessingException: Resource resolution by ServletContext with org.thymeleaf.resourceresolver.ServletContextResourceResolver can only be performed when context implements org.thymeleaf.context.IWebContext [current context: org.thymeleaf.context.Context]
at org.thymeleaf.resourceresolver.ServletContextResourceResolver.getResourceAsStream(ServletContextResourceResolver.java:78) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateRepository.getTemplate(TemplateRepository.java:221) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1104) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:924) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:898) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
Now since I have configured multiple template resolvers, the resolution should move on to the second one and IWebContext should not be required.
So what shuold be the correct configuration for viee resolution as well as mail sending templates?
EDIT:
I am using spring-boot-starter-thymeleaf with spring boot 1.4.0

How to modify the ObjectMapper in JHipster project?

I am having trouble configuring the default ObjectMapper in JHipster to allow JsonViews and also setting to false the FORCE_LAZY_LOADING property of the Hibernate4Module module.
I have tried three things without success:
1) Create a #Bean using the #Primary annotation to replace the default bean:
#Bean
#Primary
public ObjectMapper viewsObjectMapper(){
ObjectMapper mapper = new ObjectMapper();
Hibernate4Module hibernateModule = new Hibernate4Module();
hibernateModule.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false); mapper.registerModule(hibernateModule);
mapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
return mapper;
}
2) I modified the #Bean Hibernate4Module in the DatabaseConfiguration class as follows:
#Bean
public Hibernate4Module hibernate4Module() {
Hibernate4Module hibernateModule = new Hibernate4Module();
hibernateModule.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, true);
return hibernateModule;
}
3) And this solution.
Any help will be appreciated.
You can do it as stated in Spring Boot's documentation. In Spring Boot, it is not necessary to declare the ObjectMapper in a #Configuration class that extends the WebMvcConfigurationSupport. JHipster creates a #Configuration class named WebConfigurer where you can put this code:
#Bean
public ObjectMapper viewsObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
Hibernate4Module hibernateModule = new Hibernate4Module();
hibernateModule.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false);
objectMapper.registerModule(hibernateModule);
return objectMapper;
}
#Bean
public MappingJackson2HttpMessageConverter jackson2Converter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(viewsObjectMapper());
return converter;
}

Resources