Use multiple ViewResolvers in Spring Boot
1. Objective of Post
Normally, in a Spring application, you usually need to use only one technology for the View layer, which can be a Thymeleaf, JSP or FreeMarker, etc. However, you can also use multiple technologies for the View layer at the same time. In this post, I am going to guide you for creating a such application.
OK, We will create an application that uses all of the 3 technologies such as Thymeleaf, JSP & FreeMarker for the View layer.
3. Configure pom.xml
To be able to use the JSP, Thymeleaf, FreeMarker, you need to have the following libraries:
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- FreeMarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JSP -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
The full content of the pom.xml file:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.o7planning</groupId>
<artifactId>SpringBootMultiViewResolver</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringBootMultiViewResolver</name>
<description>Spring Boot + Multi ViewResolver</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- FreeMarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JSP -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4. Configure ViewResolvers
When developing a Spring Boot project, you usually use only one technology for the View layer (JSP, Thymeleaf, ..), the Spring Boot will automatically configure a ViewResolver for you to work with that technology. However, in case you use multiple technologies for the View layer, you have to manually configure all necessary ViewResolvers.
This is an illustration of the flow of a Spring application if you use a ViewResolver.
In case, you use multiple technologies for the View layer, a lot of ViewResolvers take part in the flow of the application. The ViewResolvers are arranged in order of priority (0, 1, 2, ..). If ViewResolver (0) does not find the required "View Name" , the ViewResolver (1) will be used, ...
Configure Thymeleaf ViewResolver.
ThymeleafViewResolverConfig.java
package org.o7planning.sbmultiviewresolver.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;
@Configuration
public class ThymeleafViewResolverConfig {
@Bean
public ViewResolver thymeleafViewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(thymeleafTemplateEngine());
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setOrder(0);
// Important!!
// th_page1.html, th_page2.html, ...
viewResolver.setViewNames(new String[] { "th_*" });
return viewResolver;
}
// Thymeleaf template engine with Spring integration
@Bean
public SpringTemplateEngine thymeleafTemplateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(thymeleafTemplateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
@Bean
public SpringResourceTemplateResolver springResourceTemplateResolver() {
return new SpringResourceTemplateResolver();
}
// Thymeleaf template resolver serving HTML 5
@Bean
public ITemplateResolver thymeleafTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("templates/");
templateResolver.setCacheable(false);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
}
In this application, we configure the Thymeleaf ViewResolver with the highest priority (order = 0).
Note: The Thymeleaf ViewResolver will throw an exception when it does not find the required "View Name" (A necessary html file). It is contrary to your wish that the ViewResolver with succeeding priority will be used. Therefore, you need to set up rules for the "View Names" to be served by the Thymeleaf ViewResolver.// Important!! // th_page1.html, th_page2.html, ... viewResolver.setViewNames(new String[] { "th_*" });
Configure FreeMarker ViewResolver.
FreeMarkerViewResolverConfig.java
package org.o7planning.sbmultiviewresolver.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
@Configuration
public class FreeMarkerViewResolverConfig {
@Bean(name = "viewResolver")
public ViewResolver getViewResolver() {
FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver();
viewResolver.setCache(true);
viewResolver.setPrefix("/freemarker/");
viewResolver.setSuffix(".ftl");
viewResolver.setOrder(1);
return viewResolver;
}
@Bean(name = "freemarkerConfig")
public FreeMarkerConfigurer getFreemarkerConfig() {
FreeMarkerConfigurer config = new FreeMarkerConfigurer();
// Folder containing FreeMarker templates.
// 1 - "/WEB-INF/views/"
// 2 - "classpath:/templates"
config.setTemplateLoaderPath("classpath:/templates");
return config;
}
}
The operating principle of the FreeMarker ViewResolver:
Configure JSP ViewResolver.
Note: The JSP ViewResolver has to be established with the lowest priority. This is commented in the doucments of Spring.
JspViewResolverConfig.java
package org.o7planning.sbmultiviewresolver.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
@Configuration
public class JspViewResolverConfig {
@Bean
public ViewResolver jspViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
viewResolver.setContentType("text/html");
// Make sure > Thymeleaf order & FreeMarker order.
viewResolver.setOrder(1000);
return viewResolver;
}
}
The operating principles of the JSP ViewResolver:
5. Controller
MainController.java
package org.o7planning.sbmultiviewresolver.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class MainController {
@RequestMapping(value = { "/testJsp" }, method = RequestMethod.GET)
public String testJspView() {
return "testJsp";
}
@RequestMapping(value = { "/testThymeleaf" }, method = RequestMethod.GET)
public String testThymeleafView() {
return "th_page1";
}
@RequestMapping(value = { "/testFreeMarker" }, method = RequestMethod.GET)
public String testFreeMarkerView() {
return "testFreeMarker";
}
}
6. Views
th_page1.html (Thymeleaf)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Thymeleaf</title>
</head>
<body>
<h2>Thymeleaf Page</h2>
<p>templates/th_page1.html</p>
</body>
</html>
freemaker/testFreeMarker.ftl (FreeMarker)
<!DOCTYPE html>
<html lang="en">
<head>
<title>FreeMarker</title>
</head>
<body>
<h2>FreeMarker Page</h2>
<p>templates/freemarker/testFreeMarker.ftl</p>
</body>
</html>
testJsp.jsp
<!DOCTYPE html>
<html lang="en">
<head>
<title>JSP</title>
</head>
<body>
<h2>JSP Page</h2>
<p>WEB-INF/jsp/testJsp.jsp</p>
</body>
</html>
Spring Boot Tutorials
- Install Spring Tool Suite for Eclipse
- Spring Tutorial for Beginners
- Spring Boot Tutorial for Beginners
- Spring Boot Common Properties
- Spring Boot and Thymeleaf Tutorial with Examples
- Spring Boot and FreeMarker Tutorial with Examples
- Spring Boot and Groovy Tutorial with Examples
- Spring Boot and Mustache Tutorial with Examples
- Spring Boot and JSP Tutorial with Examples
- Spring Boot, Apache Tiles, JSP Tutorial with Examples
- Use Logging in Spring Boot
- Application Monitoring with Spring Boot Actuator
- Create a Multi Language web application with Spring Boot
- Use multiple ViewResolvers in Spring Boot
- Use Twitter Bootstrap in Spring Boot
- Spring Boot Interceptors Tutorial with Examples
- Spring Boot, Spring JDBC and Spring Transaction Tutorial with Examples
- Spring JDBC Tutorial with Examples
- Spring Boot, JPA and Spring Transaction Tutorial with Examples
- Spring Boot and Spring Data JPA Tutorial with Examples
- Spring Boot, Hibernate and Spring Transaction Tutorial with Examples
- Integrating Spring Boot, JPA and H2 Database
- Spring Boot and MongoDB Tutorial with Examples
- Use Multiple DataSources with Spring Boot and JPA
- Use Multiple DataSources with Spring Boot and RoutingDataSource
- Create a Login Application with Spring Boot, Spring Security, Spring JDBC
- Create a Login Application with Spring Boot, Spring Security, JPA
- Create a User Registration Application with Spring Boot, Spring Form Validation
- Example of OAuth2 Social Login in Spring Boot
- Run background scheduled tasks in Spring
- CRUD Restful Web Service Example with Spring Boot
- Spring Boot Restful Client with RestTemplate Example
- CRUD Example with Spring Boot, REST and AngularJS
- Secure Spring Boot RESTful Service using Basic Authentication
- Secure Spring Boot RESTful Service using Auth0 JWT
- Spring Boot File Upload Example
- Spring Boot File Download Example
- Spring Boot File Upload with jQuery Ajax Example
- Spring Boot File Upload with AngularJS Example
- Create a Shopping Cart Web Application with Spring Boot, Hibernate
- Spring Email Tutorial with Examples
- Create a simple Chat application with Spring Boot and Websocket
- Deploy Spring Boot Application on Tomcat Server
- Deploy Spring Boot Application on Oracle WebLogic Server
- Install a free Let's Encrypt SSL certificate for Spring Boot
- Configure Spring Boot to redirect HTTP to HTTPS
- Fetch data with Spring Data JPA DTO Projections
Show More