Utilisation de plusieurs ViewResolvers dans Spring Boot

View more categories:

1- Objectif de la publication

Normalement, dans une application  Spring, vous devez utiliser uniquement une technology pour la couche View, soit  Thymeleaf, JSP ou  FreeMarker,... Cependant, vous pouvez utiliser plusieurs technologies pour la couche  View. Dans cet article, je vous donnerai des instructions de la création une telle application.
OK, nous allons créer une application qui utilise toutes les trois technologies telles que  Thymeleaf, JSP & FreeMarker pour la couche  View.

2- Créer un projet C Spring Boot

3- Configurer le fichier pom.xml

Pour utiliser les technologies  JSP, Thymeleaf, FreeMarker vous devez posséder des bibliothèques comme ci-dessous : 
<!-- 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>
Le contenu complet du fichier  pom.xml:
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- Configurer des ViewResolver

Lorsque vous développez un projet  Spring Boot, vous devez habituellement utiliser une technology pour la couche  View ( JSP, Thymeleaf, ..), Spring Boot va automatiquement configurer un  ViewResolver avec lequel vous pouvez travailler. Dans le cas où vous utilisez plusieurs technologies pour la couche  View, vous devez configurer tous les  ViewResolver nécessaires.
Voici est une illustration du flux (Flow) d'une application  Spring dans la cas où vous utilisez 1 ViewResolver.
Au cas où vous utilisez plusieurs technologies pour la couche  View, plusieurs  ViewResolver vont participer aux flux (flow) de l'application. Les  ViewResolver sont arrangés par ordre de priorité (0, 1, 2, ..). Si  ViewResolver (0) ne trouve pas  "View Name" nécessaire, ViewResolver (1) sera utilisé, ...

Configurer 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;
    }
 
}
Dans cette application, nous configurons  Thymeleaf ViewResolver avec la plus haute priorité (order = 0).
Remarque : Deuxième priorité sera utilisée. Par conséquent, vous devez établir des ordres de  "View Name" qui seront servis par  Thymeleaf ViewResolver.
// Important!!
// th_page1.html, th_page2.html, ...
viewResolver.setViewNames(new String[] { "th_*" });

Configurer 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;
    }
    
}
La principe d'exploitation de  FreeMarker ViewResolver:

Configurer JSP ViewResolver.

Remarque : JSP ViewResolver doit être établit de basse  priorité. Ceci est commenté dans les documents de  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;
    }
    
}
Les principes d'exploitation de  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>

View more categories: