Apache FreeMarker es un motor de plantillas: una biblioteca Java para generar salida de texto (páginas HTML, xml, archivos de configuración, código fuente, etc.) Se envía una plantilla a la entrada, por ejemplo, html en el que hay expresiones especiales, se preparan los datos correspondientes a esta expresión, y Freemarker inserta dinámicamente estos datos y obtiene un documento poblado dinámicamente.

En el artículo de FreeMarker
Bota de primavera
Macros
API REST
Es decir una expresión simple en freemarker es, por ejemplo, $ {name}, cálculos, operaciones de comparación, condiciones, bucles, listas, funciones integradas, macros y muchos otros son compatibles con la expresión. Ejemplo html con la expresión $ {name} (template test.ftl):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>${name}!</title> </head> <body> <h2>Hello ${name}!</h2> </body> </html>
Si ahora crea un modelo de datos en Java:
import freemarker.template.Configuration; import freemarker.template.Template; ...
entonces obtenemos un documento html con el nombre completo.
Si necesita procesar la lista, se utiliza la construcción #list, por ejemplo, para una lista html:
<ul> <#list father as item> <li>${item}</li> </#list> </ul>
En java, puede enumerar el modelo de datos de la siguiente manera
Map<String, Object> root = new HashMap<>(); .... root.put("father", Arrays.asList("Alexander", "Petrov", 47));
Pasemos a la primavera
Spring boot tiene soporte para Freemarker. En el sitio
SPRING INITIALIZR puede obtener el archivo del proyecto pom.
archivo pom <?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>com.example</groupId> <artifactId>demoFreeMarker</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demoFreeMarker</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/> </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-devtools</artifactId> <scope>runtime</scope> </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>
Clase DemoFreeMarkerApplication @SpringBootApplication public class DemoFreeMarkerApplication { public static void main(String[] args) { SpringApplication.run(DemoFreeMarkerApplication.class, args); } }
Spring tiene un componente de configuración preconfigurado para freemarker. Para una aplicación de consola de ejemplo, tomaré la interfaz de Spring para procesar la línea de comando (CommandLineRunner) y prepararé el modelo de datos para la siguiente plantilla ftl (hello_test.ftl):
Plantilla Hello_test.ftl <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello ${name}!</title> </head> <body> <input type="text" placeholder="${name}"> <table> <#list persons as row> <tr> <#list row as field> <td>${field}</td> </#list> </tr> </#list> </table> </body> </html>
Código Java para el modelo de datos de plantilla hello_test.ftl:
Clase de línea de comandos y modelo de datos @Component public class CommandLine implements CommandLineRunner { @Autowired private Configuration configuration; public void run(String... args) { Map<String, Object> root = new HashMap<>();
Después del procesamiento, obtenemos un documento html:
Salida html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello Fremarker!</title> </head> <body> <input type="text" placeholder="Fremarker"> <table> <tr> <td>Alexander</td> <td>Petrov</td> <td>47</td> </tr> <tr> <td>Slava</td> <td>Petrov</td> <td>13</td> </tr> </table> </body>
Macros
Freemarker tiene soporte macro, es muy conveniente y fuerte, y es absolutamente necesario usarlo.
Un simple ejemplo:
<#macro textInput id value=""> <input type="text" id="${id}" value="${value}"> </#macro>
Esta es una macro con el nombre textInput y los parámetros id (es obligatorio) y value (no es obligatorio porque tiene un valor predeterminado). El siguiente es su cuerpo y el uso de parámetros de entrada. En la plantilla, el archivo macro está conectado de la siguiente manera:
<#import "ui.ftl" as ui/>
Desde la plantilla, la macro se llama así:
<@ui.textInput id="name" value="${name}"/>
Donde ui es el alias que se especificó al conectarse, $ {name} es una variable en el modelo, luego a través del alias nos referimos al nombre de macro textInput y especificamos sus parámetros, al menos obligatorios. Prepararé macros simples para entrada y tabla html:
archivo de macro ui.ftl <#-- textInput macro for html input --> <#macro textInput id placeholder="" value=""> <input type="text" id="${id}" placeholder="${placeholder}" value="${value}"> </#macro> <#-- table macro for html table --> <#macro table id rows> <table id="${id}"> <#list rows as row> <tr> <td>${row?index + 1}</td> <#list row as field> <td>${field}</td> </#list> </tr> </#list> </table> </#macro>
$ {row? index + 1} es el soporte integrado para el índice de un elemento de la lista; Si ahora cambiamos la plantilla principal anterior y reemplazamos la entrada y la tabla con macros, obtenemos el siguiente documento:
Plantilla Hello.ftl <#import "ui.ftl" as ui/> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello ${name}!</title> </head> <body> <@ui.textInput id="name" placeholder="Enter name" value="${name}"/> <@ui.table id="table1" rows=persons/> </body> </html>
DESCANSO
Por supuesto, dicho modelo es conveniente para usar en una aplicación web. Conecto la dependencia en pom:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
Agregar controlador REST:
DemoController.java @Controller public class DemoController { @Autowired private RepositoryService repositoryService; @GetMapping("/") public String index() { return "persons"; } @RequestMapping(value = "/search", method = RequestMethod.POST) public String hello(Model model, @RequestParam(defaultValue = "") String searchName) { List<List<String>> persons = repositoryService.getRepository(); List<List<String>> filterList = persons.stream() .filter(p -> p.get(0).contains(searchName)) .collect(Collectors.toList()); model.addAttribute("persons", filterList); model.addAttribute("lastSearch", searchName); return "persons"; } @RequestMapping(value = "/save", method = RequestMethod.POST) public String save(Model model, @ModelAttribute("person") Person person) { List<List<String>> persons = repositoryService.addPerson(person); model.addAttribute("persons", persons); return "persons"; } }
Depósito de servicios para particulares:
RepositoryService.java @Service public class RepositoryService { private static List<List<String>> repository = new ArrayList<>(); public List<List<String>> getRepository() { return repository; } public List<List<String>> addPerson(Person person) { repository.add(Arrays.asList(person.getFirstName(), person.getAge().toString())); return repository; } }
Clase de la cara:
Person.java public class Person { public Person(String firstName, Integer age) { this.firstName = firstName; this.age = age; } private String firstName; private Integer age; public String getFirstName() { return firstName; } public Integer getAge() { return age; } }
Plantilla macro:
ui.ftl <#macro formInput id name label type="text" value=""> <label for="${id}">${label}</label> <input type="${type}" id="${id}" name="${name}" value="${value}"> </#macro> <#macro table id rows> <table id="${id}" border="1px" cellspacing="2" border="1" cellpadding="5"> <#list rows as row> <tr> <td>${row?index + 1}</td> <#list row as field> <td>${field}</td> </#list> </tr> </#list> </table> </#macro>
La plantilla principal:
personas.ftl <#import "ui.ftl" as ui/> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Person</title> <link href="style/my.css" rel="stylesheet"> </head> <body> <div> <fieldset> <legend> </legend> <form name="person" action="save" method="POST"> <@ui.formInput id="t1" name="firstName" label=""/> <br/> <@ui.formInput id="t2" name="age" label=""/> <br/> <input type="submit" value="Save" /> </form> </fieldset> </div> <div> <fieldset> <legend></legend> <form name="searchForm" action="search" method="POST"> <@ui.formInput id="t3" name="searchName" label=""/> <br/> <input type="submit" value="Search" /> </form> </fieldset> </div> <p><#if lastSearch??> : ${lastSearch}<#else></#if></p> <@ui.table id="table1" rows=persons![]/> </body> </html>
Estructura del proyecto:

La aplicación procesará dos comandos "guardar" y "buscar" de la cara (ver controlador). Spring realiza todo el trabajo de procesamiento (mapeo) de los parámetros de entrada.
Algunas explicaciones a la plantilla.
<#if lastSearch??> : ${lastSearch}<#else></#if>
comprueba si el parámetro está configurado, luego muestra la frase "Buscar: ..", de lo contrario nada:
<@ui.table id="table1" rows=persons![]/>
aquí también se verificó que la lista de personas está presente, de lo contrario está vacía. Estas comprobaciones son importantes cuando abre la página por primera vez; de lo contrario, deberá inicializarlas en el controlador index ().
Trabajo de aplicación

Materiales:
→
Manual de Apache FreeMarker