Spring Boot 2 Thymeleaf Configuration Ignoring 'templates' - spring

I'm migrating an existing application to Spring 5.0.0.M3 & Spring Boot 2.0.0.M3. With Spring Boot I'm also importing the Thymeleaf starter.
The application has 2 template folders mails and templates. If I specify the below configuration for email templates, the templates folder is ignored; e.g. I'm getting FileNotFoundException for templates in this folder.
#Configuration
public class ThymeleafConfiguration {
#SuppressWarnings("unused")
private final Logger log = LoggerFactory.getLogger(ThymeleafConfiguration.class);
#Bean
#Description("Thymeleaf template resolver serving HTML 5 emails")
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("mails/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
}
I've tried setting the setOrder parameter to 2, 10, etc. which made no difference. If I remove the resolver method, the templates folder is recognized, but the mails folder isn't.
Any ideas what might be going on?

What I understand is you have mails and templates sub-folders under the resources folder.
You can add resource folder as the prefix in your ClassLoaderTemplateResolver. Then add ResourceHandler for both mails and templates sub-folders.
ClassLoaderTemplateResolver
#Bean
#Description("Thymeleaf template resolver serving HTML 5 emails")
public ClassLoaderTemplateResolver emailTemplateResolver() {
ClassLoaderTemplateResolver emailTemplateResolver = new
ClassLoaderTemplateResolver();
emailTemplateResolver.setPrefix("resources/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML5");
emailTemplateResolver.setCharacterEncoding(CharEncoding.UTF_8);
emailTemplateResolver.setOrder(1);
return emailTemplateResolver;
}
Place your ResourceHandler method in your application class, which your have annotated with #SpringBootApplication.
ResourceHandler
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern("/mails/**")) {
registry.addResourceHandler("/mails/**").addResourceLocations("classpath:/resources/mails/");
}
if (!registry.hasMappingForPattern("/templates/**")) {
registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/resources/templates/");
}
}
When you return your view name from any method, it can be like:
return "mails/page1";
or
return "templates/page2";

Related

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;
}
}

Springboot - Thymeleaf tries to resolve files it should not

Hi I am currently working on a web project that uses thymeleaf and also JSF (its a legacy system and we can only slowly migrate to thymeleaf thats why JSF is still there and cannot be removed from one day to another since this is a lot of work). Thymeleaf is configured to resolve the views in the webapp directory that lie under the directory "thymeleaf". This works perfectly if I deploy the application directly on a tomcat server. Also pages from other directories then the "thymeleaf" directory are also resolved by the JSF framework.
I added some integration tests in JUnit that are using SpringBoot. Inside these tests I got the problem that thymeleaf now is trying to resolve any page in any directory. JSF is completely ignored and I got a whole bunch of JUnit tests failing because of that. Is there any point why thymeleaf ignores its configuration and wants to resolve all files?
Here is my complete thymeleaf configuration, and as I said this works perfectly if I deploy it on a standalone tomcat.
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
String imagesPattern = "/images/**";
String imagesLocation = basePath() + "resources/images/";
registry.addResourceHandler(imagesPattern).addResourceLocations(imagesLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')",
imagesPattern,
imagesLocation);
String cssPattern = "/css/**";
String cssLocation = basePath() + "resources/css/";
registry.addResourceHandler(cssPattern).addResourceLocations(cssLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')", cssPattern, cssLocation);
}
#Bean(name = "basepath")
public String basePath()
{
String basepath = "";
File file = new File(Optional.ofNullable(System.getenv("THYMELEAF_APP_RESOURCES"))
.orElse("thymeleaf-resources/"));
if (file.exists())
{
basepath = "file:" + file.getAbsolutePath();
}
if (!basepath.endsWith("/"))
{
basepath += "/";
}
log.info("basepath: {}", basepath);
return basepath;
}
#Bean
#Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver(String basePath)
{
log.info("setting up Thymeleaf view resolver");
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine(basePath));
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setCache(true);
return viewResolver;
}
public SpringTemplateEngine templateEngine(String basePath)
{
log.info("setting up Thymeleaf template engine.");
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver(basePath));
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
private ITemplateResolver templateResolver(String basePath)
{
log.info("setting up Thymeleaf template resolver");
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix(basePath + "thymeleaf/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
return resolver;
}
#Bean
public IMessageResolver thymeleafMessageSource(MessageSource messageSource)
{
SpringMessageResolver springMessageResolver = new SpringMessageResolver();
springMessageResolver.setMessageSource(messageSource);
return springMessageResolver;
}
EDIT
I just found that the problem seems to lie much deeper. Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context... I just deleted my ThymeleafConfig class for testing purposes and still thymeleaf tries to resolve the JSF pages... (yes I did maven clean before executing the test)
EDIT 2
I read it now and tried to exclude the ThymeleafAutoConfiguration class but it does not help. My configurations are still overridden. Here is my configuration for this so far. (And yes this is the ONLY EnableAutoConfiguration annotation in the whole project)
#Configuration
#EnableAutoConfiguration(exclude = {ThymeleafAutoConfiguration.class})
#Import({WebAppConfig.class, ThymeleafConfig.class})
public class SpringBootInitializer extends SpringBootServletInitializer
and my ThymeleafConfig class is already added above.
Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context...
If this has surprised you then I would recommend spending some time to take a step back and read about how Spring Boot works and, in particular, it's auto-configuration feature. This section of the reference documentation is a good place to start.
In short, Spring Boot adopts a convention over configuration approach. If a dependency is on the classpath, Spring Boot assumes that you want to use it, and configures it with sensible defaults. This is what it's doing with Thymeleaf. You can disable this auto-configuration for a specific dependency using the excludes attribute on #SpringBootApplication:
#SpringBootApplication(exclude={ThymeleafAutoConfiguration.class})
public class ExampleApplication {
}
You can also use the spring.autoconfigure.exclude property to provide a comma-separated list of auto-configuration classes to exclude. Each entry in the list should be the fully-qualified name of an auto-configuration class. You could use this property with #TestPropertySource to disable auto-configuration on a test-by-test basis.
I have been struggling with a similar issue for hours and finally found out the root cause.
If you have a dependency to *-data-rest in your pom like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
you will have to add Thymeleaf to your pom as well even if you use a another template engine (Freemarker, JSP, ...) everywhere else.
Reason: to expose a JpaRepository as a rest service Spring Boot requires Thymeleaf. I do not understand why this is not defined as a dependency of spring-boot-starter-data-rest so that Maven resolves it automatically.
In my opinion it is a Spring Boot configuration bug.

Does a Spring Boot Project that runs as a Jar needs a web.xml file?

As the title states.
I am migrating a Spring-MVC application that uses XML based Configuration.
I don't know where to move the filters located in the web.xml file to the new Spring Boot Project.
You can make use of the annotation : #ImportResource for this
Find more details here
You can define your filters using Java Configurations when using Spring Boot.
As mentioned in the documentation, you only need to declare that filter as a Bean in a configuration class.
#Configuration
public class WebConfig {
#Bean
public Filter someFilter() {
return new someFilter();
}
}
If for some reason "SomeFilter" is not a spring managed bean, or if you need to customize the filter behaviour, then you can register the filter using FilterRegistrationBean as follows
#Configuration
public class WebConfig {
#Bean
public Filter someFilter() {
return new someFilter();
}
#Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(someFilter());
return registration;
}
}
In case of multiple Filters you can specify the order using FilterRegistrationBean.setOrder() as mentioned in the doc
Finally I registered my Interceptors using Java Configuration (no xml) this way.
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
ControllerInterceptor controllerInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.controllerInterceptor).addPathPatterns(this.buildPaths());
}
private String[] buildPaths() {
String paths[] = { "/api/example1/**", "/api/example2/**" };
return paths;
}
}

How to Configure Servlet Mapping and Resource Handler in Spring MVC

I have created sample Spring MVC REST Maven project with following folder structure
ResourceHandlerRegistry configuration as follows
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.raju.spring_app")
public class RootConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static_res/*").addResourceLocations("/WEB-INF/html/static_res/");
}
//Other methods
}
Servlet mapping as follows
public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected String[] getServletMappings() {
return new String[] { "/", "/static_res/*" };
}
//Other Methods
}
The problem is whenever I tried to access resource
http://localhost:8080/spring4_rest_angular_demo/static/css/app.css
I got 404 error.
I want to keep this folder structure to get css IntelliSense suggestions
in index.jsp file.
<link href="static_res/css/app.css" rel="stylesheet"></link>
Few corrections :
Replace
return new String[] { "/", "/static_res/*" };
with
return new String[] { "/" };
and
registry.addResourceHandler("/static_res/*")
with
registry.addResourceHandler("/static_res/**")
Also, the right path is
http://localhost:8080/spring4_rest_angular_demo/static_res/css/app.css
and not
http://localhost:8080/spring4_rest_angular_demo/static/css/app.css
With Spring 3.0.4.RELEASE and higher you can use
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
As seen in http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources
Also, you should avoid putting pages in WEB-INF. Put the folder with html/css/js higher in hierarchy, under the web app folder. Generally, in WEB-INF there should be only configuration xml files.

Resources