Le Tutoriel de Spring Boot et FreeMarker

1- Qu'est-ce que FreeMarker ?

FreeMarker est un  Template Engine (un moteur de template), il est fournit par  Apache comme une bibliothèque  Java source ouverte. FreeMarker lit des fichiers modèle et les combine avec des objets Java pour générer (generate) un texte de sortie (Html, email, ..).
Les fichiers modèle (Template file) của FreeMarker est par essence un fichier texte dans le format introduit par le  FreeMarker, c'est  FreeMarker Template Language (FTL).
FreeMarker peut être utilisé à remplacer  JSP sur  View (View Layer) de l'application  Web MVC.
Ci-dessous est l'image de l'application que nous effectuons dans cette leçon :

2- Créer une application

Sur  Eclipse sélectionnez :
  • File/New/Other...
Saisissez :
  • Name: SpringBootFreeMarker
  • Group: org.o7planning
  • Artifact: SpringBootFreeMarker
  • Description: Spring Boot and FreeMarker
  • Package: org.o7planning.freemarker
Sélectionnez 2 technologies  Web et  FreeMarker.
Votre projet a été créé :
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>SpringBootFreeMarker</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>SpringBootFreeMarker</name>
    <description>Spring Boot and FreeMarker</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.M3</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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</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>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>


</project>

 

3- FreeMarker Template

Nous allons créer 3 fichier modèle (Template file) et les mettre dans le répertoire  src/main/resources/templates:
index.flt
<#import "/spring.ftl" as spring/>

<!DOCTYPE HTML>
<html>
   <head>
      <meta charset="UTF-8" />
      <title>Welcome</title>
      <link rel="stylesheet"
           type="text/css" href="<@spring.url '/css/style.css'/>"/>
   </head>
   
   <body>
      <h1>Welcome</h1>
      <#if message??>
      <h2>${message}</h2>
      </#if>
    
         
      <a href="<@spring.url '/personList'/>">Person List</a>  
      
   </body>
   
</html>
personList.flt
<#import "/spring.ftl" as spring/>

<html>
   <head>
      <title>Person List</title>
      <link rel="stylesheet"
           type="text/css"
           href="<@spring.url '/css/style.css'/>"/>      
   </head>   
   <body>
     <h3>Person List</h3>
     <a href="addPerson">Add Person</a>
     <br><br>
      <div>
         
         <table border="1">
            <tr>
               <th>First Name</th>
               <th>Last Name</th>
            </tr>
            <#list persons as person>
            <tr>
               <td>${person.firstName}</td>
               <td>${person.lastName}</td>
            </tr>
            </#list>
         </table>
      </div>
   </body>
</html>
addPerson.flt
<#import "/spring.ftl" as spring/>

<html>
   <head>
      <title>Add Person</title>
      <link rel="stylesheet"
           type="text/css" href="<@spring.url '/css/style.css'/>"/>      
   </head>
   <body>
      <#if errorMessage??>
      <div style="color:red;font-style:italic;">
         ${errorMessage}
      </div>
      </#if>
      
      <div>
         <fieldset>
            <legend>Add Person</legend>
            <form name="person" action="" method="POST">
               First Name: <@spring.formInput "personForm.firstName" "" "text"/>    <br/>
               Last Name: <@spring.formInput "personForm.lastName" "" "text"/>    <br/>
               <input type="submit" value="Create" />
            </form>
         </fieldset>
      </div>
      
      
   </body>
   
</html>
Tous les fichiers modèle devraient déclarer un  "FreeMarker Macros".
<!-- FreeMarker Macros -->

<#import "/spring.ftl" as spring/>
Dans les fichiers modèle (Template file) il y a des  Thymeleaf Marker (Des marqueurs de Thymeleaf), qui sont des instructions assistant le  Thymeleaf Engine à procéder des données.
Thymeleaf Engine analyse le fichier modèle (Template file), et combine des données  Java afin de gérer (generate) un nouveau document.
Ci-dessous sont des exemples à utiliser  Context-Path dans  FreeMarker:
<!-- Example 1:  -->

<a href="<@spring.url '/mypath/abc.html'/>">A Link</a>

Output: ==>

<a href="/my-context-path/mypath/abc.html">A Link</a>


<!-- Example 2:  -->

<form action="<@spring.url '/mypath/abc.html'/>"   method="POST">

Output: ==>

<form action="/my-context-path/mypath/abc.html"  method="POST">

4- Static Resource & Properties File

Pour les ressources statiques (Static Resource), par exemple : des fichiers  css, javascript, image,.. vous devriez les mettre dans le répertoire  src/main/resources/static ou dans ses sous - répertoires.
style.css
h1 {
    color:#0000FF;
}

h2 {
    color:#FF0000;
}

table {
    border-collapse: collapse;
}

table th, table td {
    padding: 5px;
}
application.properties

welcome.message=Hello FreeMarker
error.message=First Name & Last Name is required!

5- Des classes Model, Form, Controller

Person.java
package org.o7planning.freemarker.model;

public class Person {

    private String firstName;
    private String lastName;

    public Person() {

    }

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}
La classe  PersonForm représente des données du  FORM que vous crée une nouvelle  Person sur la page  addPerson.
PersonForm.java
package org.o7planning.freemarker.form;

public class PersonForm {

    private String firstName;
    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}
MainController est une classe  Controller, qui procède les demandes de l'utilisateurs et controle un flux (flow) d'application.
MainController.java
package org.o7planning.freemarker.controller;

import java.util.ArrayList;
import java.util.List;

import org.o7planning.freemarker.form.PersonForm;
import org.o7planning.freemarker.model.Person;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MainController {

	private static List<Person> persons = new ArrayList<Person>();

	static {
		persons.add(new Person("Bill", "Gates"));
		persons.add(new Person("Steve", "Jobs"));
	}

	// Injectez (inject) de l'application.properties.
	@Value("${welcome.message}")
	private String message;

	@Value("${error.message}")
	private String errorMessage;

	
	@RequestMapping(value = { "/", "/index" }, method = RequestMethod.GET)
	public String index(Model model) {

		model.addAttribute("message", message);
		
		return "index";
	}

	@RequestMapping(value = { "/personList" }, method = RequestMethod.GET)
	public String personList(Model model) {

		model.addAttribute("persons", persons);

		return "personList";
	}

	@RequestMapping(value = { "/addPerson" }, method = RequestMethod.GET)
	public String addPersonForm(Model model) {

		PersonForm personForm = new PersonForm();
		model.addAttribute("personForm", personForm);

		return "addPerson";
	}

	@RequestMapping(value = { "/addPerson" }, method = RequestMethod.POST)
	public String addPersonSave(Model model, //
			@ModelAttribute("personForm") PersonForm personForm) {

		String firstName = personForm.getFirstName();
		String lastName = personForm.getLastName();

		if (firstName != null && firstName.length() > 0 //
				&& lastName != null && lastName.length() > 0) {
			Person newPerson = new Person(firstName, lastName);
			persons.add(newPerson);

			return "redirect:/personList";
		}
		String error = "First Name & Last Name is required!";
		model.addAttribute("errorMessage", error);
		return "addPerson";
	}

}

6- Exécuter l'application

Afin d'exécuter l'application, cliquez sur le bouton droit du Projet et sélectionnez :
  • Run As/Spring Boot App.
L'application a été déployée (deploy) sur un  Embedded Web Server.
Exécutez URL ci-dessous dans le navigateur :