Freemarker è un template engine basato su Java utilizzabile sia in modalità stand-alone che in un ambiente Web, esso prevede un Template file che contiene l'output da visualizzare associato a dei place-holder riguardanti eventuali parti che vogliamo fornire dinamicamente.
<html>
<body>
<h1>${title}</h1>
</body>
</html>
Nell'esempio ${title}
indica una variabile che verrà fornita al template in maniera dinamica. Questo verrà fatto da Java, sarà infatti Freemarker che permetterà di fornire al template i valori dinamici da visualizzare. Tale modalità permette un disaccoppiamento tra la View e la parte back-end, questo perché chi realizza il template potrebbe anche non conoscere cosa rappresenta ${title}
ma, più semplicemente, aspettarsi che il valore venga fornito a runtime.
Installazione
Scarichiamo la libreria Freemarker dalla sezione download che troviamo all'indirizzo http://freemarker.org/freemarkerdownload.html e memorizziamola in una directory a parte, ci servirà successivamente:
Ora apriamo Eclipse, nel nostro caso abbiamo utilizzato Kepler, ed installiamo il plugin per Freemarker selezionando in eclipse la voce "help/Install New Software" e, inserendo l'url http://download.jboss.org/jbosstools/updates/stable/kepler/
, selezioniamo il Freemarker IDE per entrambe le checkbox come in figura:
Un primo esempio di utilizzo in Eclipse
In Eclipse creiamo un progetto Java, chiamato per esempio "FreemarkerProject", e il template mytemplate.ftl
sotto la cartella templates
:
Creiamo quindi anche il seguente Bean:
package com.freemarker; public class Developer {
private String name;
private String project;
public Developer(String name, String project) {
this.name = name;
this.project = project;
}
public String getName() {
return name;
}
public String getProject() {
return project;
}
}
Come nomi, i due campi del Bean hanno "name" e "project", vedremo successivamente come ciò non sia un caso. Creiamo ora una classe di test che dovrà caricare il template ed effettuare il binding dei valori con quelli che il template si aspetta di ricevere:
package com.freemarker.test;
.. imports
public class TestOutput {
public static void main(String[] args) {
// configuration object di Freemarker
Configuration cfg = new Configuration();
// definiamo la classe che carica il template
cfg.setClassForTemplateLoading(TestOutput.class, "templates");
// impostazioni raccomandate
cfg.setIncompatibleImprovements(new Version(2, 3, 20));
cfg.setDefaultEncoding("UTF-8");
cfg.setLocale(Locale.US);
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// caricamento del template
try {
// path assoluto al template
cfg.setDirectoryForTemplateLoading(new File("C:/Users/g.astarita/Desktop/Work/WS Articoli/FreemarkerProject/templates"));
// generazione del data-model
Map data = new HashMap();
String title = "Freemaker example";
data.put("title", title);
Developer developer = new Developer("giuseppe","Progetto Telecom");
data.put("developer", developer);
Template template = cfg.getTemplate("mytemplate.ftl");
// Console output
Writer out = new OutputStreamWriter(System.out);
template.process(data, out);
out.flush();
// File output
Writer file = new FileWriter (new File("freemarkerOutput.txt"));
template.process(data, file);
file.flush();
file.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
La funzionalità di questa classe è quella di caricare il template e di effettuare il binding; nell'Hashmap data
inseriamo prima la stringa "title", fatto questo il codice creerà un Bean con due campi, developer.name
e developer.project
, proprio le due variabili rimanenti che il template si aspetta. Infine il codice scriverà l'output su console e in un file:
Un esempio più complesso: una Web application
Ora, creiamo il Dynamic Web Project FreemarkerWebProject e, per far questo, apriamo il file Web.xml
ed aggiungiamo la parte relativa alla configurazione:
<?xml version="1.0" encoding="UTF-8"?>
<Web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://Java.sun.com/xml/ns/Javaee"
xsi:schemaLocation="http://Java.sun.com/xml/ns/Javaee http://Java.sun.com/xml/ns/Javaee/Web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>FreemarkerWebProject</display-name>
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
</init-param>
<init-param>
<param-name>NoCache</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>ContentType</param-name>
<param-value>text/html; charset=UTF-8</param-value>
</init-param>
<init-param>
<param-name>template_update_delay</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>default_encoding</param-name>
<param-value>ISO-8859-1</param-value>
</init-param>
<init-param>
<param-name>number_format</param-name>
<param-value>0.##########</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</Web-app>
In tal modo verrà caricata una servletDispatcher di Freemarker che filtrerà le richieste RL e gestirà quelle terminanti per ".ftl" interpretandole come richiesta all'engine, permettendo quindi il merging dinamico tra parametri e template. Dopo aver creato il Web project, dovremo effettuare i seguenti passaggi:
Quindi, nell'ordine, abbiamo:
- riutilizzato il bean Developer;
- aggiunto le librerie per la compilazione;
- creato il nostro template file sotto la cartella
WebContent
.
Ora creiamo la seguente servlet sotto il package com.myservlet
:
package com.myservlet;
import Java.io.IOException;
import Java.io.PrintWriter;
import Java.util.ArrayList;
import Java.util.HashMap;
import Javax.servlet.ServletException;
import Javax.servlet.annotation.WebServlet;
import Javax.servlet.http.HttpServlet;
import Javax.servlet.http.HttpServletRequest;
import Javax.servlet.http.HttpServletResponse;
import com.freemarker.Developer;
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public HelloServlet() {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// creiamo la lista di developers
ArrayList<Developer> developers = new ArrayList<Developer>();
developers.add(new Developer("Claudio","Html.it"));
developers.add(new Developer("Alfredo","Html.it"));
developers.add(new Developer("Giuseppe","Engineering"));
// settiamo la lista come parametro della request
request.setAttribute("developers", developers);
// binding della lista con il template
request.getRequestDispatcher("/mytemplate.ftl").forward(request, response);
}
}
Questo, infine, il nostro template mytemplate.ftl
:
<html>
<head><title>Freemarker Web Example</title>
<body>
<table>
<tr>
<th>Firstname</th> <th>Lastname</th>
</tr>
<#list developers as developer>
<tr>
<td>${developer.name}</td> <td>${developer.project}</td>
</tr>
</#list>
</table>
</body>
</html>
Deployamo la Web appliction su un target server e carichiamo l'URL della nostra servlet:
In questo caso lo script del template ha recuperato la lista dei beans e per ognuno ha stampato i campi a video attraverso i costrutti di Freemarker.
Un'importante considerazione è che possiamo editare il template ftl
come se fosse una pagina HTML, quindi con tutti gli strumenti che offre un moderno Web editor; ma per ottenere questo dovremo trattare il template come pagina HTML e rinominarlo con estensione ftl
: