FreeMarker je šablonovací systém pro Javu. Je navržen s ohledem na čistotu návrhu podle vzoru MVC. Používá se především pro pohled (view) v prostředí Java Servlets, ale může být použit pro generování textů v libovolném prostředí – např. generování statických webových stránek, konfiguračních souborů, e-mailů…
FreeMarker na rozdíl od JavaServer Pages neumožňuje přímé vkládání Java kódu do šablon a šablony jsou interpretovány až za běhu (nejsou předkompilovány do Java bajtkódu). FreeMarker umožňuje automatický výběr šablony podle zvoleného jazyka – např. při požadavku na stránku index.ftl
pro jazyk cs_CZ
se postupně hledají šablony index_cs_CZ.ftl
, index_cs.ftl
a index.ftl
. FreeMarker rovněž umožňuje používat jakýsi systém dědičnosti šablon. Např. v následující struktuře souborů se při vložení (include) obsahu souboru */menu.ftl
do souborů /index.ftl
a /aktuality.index.ftl
vloží soubor /menu.ftl
, do souboru /e-shop/index.ftl
se ale vloží /e-shop/menu.ftl
:
/index.ftl
/menu.ftl
/aktuality/index.ftl
/aktuality/menu.ftl
/e-shop/index.ftl
/e-shop/menu.ftl
Ve FreeMarkeru lze vytvářet knihovny šablon, které je následně možné naimportovat do jiné šablony. Při importu je určen jmenný prostor knihovny, takže při importu více knihoven s prvky se shodnými názvy nedochází ke konfliktu jmen.
Příklad
Šablona ve FreeMarkeru:
<html>
<body>
<h1>Ahoj světe!</h1>
<p>Tito ${lide?size} lidé zdraví svět:</p>
<ul>
[#list lide as osoba]
<li>${osoba.jmeno} ${osoba.prijmeni} (${osoba.vek} let) z obce ${osoba.obec}</li>
[/#list]
</ul>
</body>
</html>
Model – Java objekty:
public class Osoba {
public Osoba(String jmeno, String prijmeni, int vek, String obec)
public String getJmeno() { … }
public String getPrijmeni() { … }
public int getVek() { … }
public String getObec() { … }
}
List<Osoba> osoby = new LinkedList<osoba>();
osoby.add(new Osoba("Marie", "Černá", 32, "Ostrava"));
osoby.add(new Osoba("František", "Novák", 54, "Brno"));
osoby.add(new Osoba("Natálie", "Zajícová", 72, "České Budějovice"));
Map<String, Object> root = new HashMap<String, Object>();
root.put("lide", osoby);
//root je předáno FreeMarkeru jako datový model
Po spojení šablony a datového modelu je vygenerován výstup:
<html>
<body>
<h1>Ahoj světe!</h1>
<p>Tito 3 lidé zdraví svět:</p>
<ul>
<li>Marie Černá (32 let) z obce Ostrava</li>
<li>František Novák (54 let) z obce Brno</li>
<li>Natálie Zajícová (72 let) z obce České Budějovice</li>
</ul>
</body>
</html>
Datový model - Java
Datový model pro šablonu FreeMarkeru může obsahovat tři typy objektů – skalár (text, číslo, datum a čas, logická hodnota), sekvenci (seřazený seznam objektů) nebo mapu (klíče a odpovídající hodnoty). Skaláry je možné přímo vypisovat do výstupu, případně je formátovat (získat část řetězce, formátovat datum a čas nebo číslo). Sekvenci je možné procházet pomocí příkazu [#list seznam as položka]…[/#list]
. Mapy je možné procházet pomocí tečkové notace mapa.klíč
. FreeMarker poskytuje mapování ze standardních Javovských objektů (řetězce, čísla, logické hodnoty, datum a čas) na skaláry, kolekce mapuje na sekvence a mapy a JavaBeany mapuje na mapy – názvy vlastností (properties) JavaBeanu jsou mapovány
jako klíče mapy. Toto mapování může programátor předefinovat a přidat mapování vlastních objektů – takto je např. ve FreemarkerServlet
u mapován kontext atributů HTTP požadavku, HTTP session a aplikace (servlet kontextu) mapován na mapu Freemarkeru. Jako datový model šablony se Freemarkeru předává mapa objektů.
Šablony
Šablony FreeMarkeru umožňují vypisovat a formátovat skalární hodnoty (pomocí konstrukce ${skalár}
). Dále mohou obsahovat podmíněné příkazy, příkaz pro procházení sekvence, vytváření maker (opakujících se částí šablony), importovat knihovny maker z jiných souborů a vkládat jiné šablony. Do šablon není možné psát Java kód, příkazy šablon jsou orientovány pouze na prezentační logiku.
Použití v prostředí Java servletů
Při použití v prostředí Java servletů je možné používat knihovny tagů pro JSP (taglibs). Freemarker také poskytuje rozšiřitelný FreemarkerServlet
, který je možné namapovat například na vzor *.ftl
. Všechny soubory s koncovkou .ftl
jsou pak zpracovány jako FreeMarker šablony, jako datový model je jim předán sloučený kontext HTTP požadavku, session a aplikace – zadané jméno (např. ${osoba}
) se postupně hledá jako atribut v HttpServletRequest
, HttpSession
a ServletContext
. Díky tomu je možné použít FreeMarker jako hotovou knihovnu (bez dalšího rozšiřování), v servletu naplnit potřebné hodnoty (model) do atributů požadavku, session nebo aplikace a následně požadavek předat na soubor s koncovkou .ftl
.
Příklad
Šablonu z předchozího příkladu uložíme jako soubor /lide.ftl
v kořenovém adresáři webové aplikace. Ve web.xml
nakonfigurujeme FreemarkerServlet
pro zpracování souborů s příponou .ftl
:
<web-app metadata-complete="false" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<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>ContentType</param-name>
<param-value>text/html</param-value>
</init-param>
<!-- FreeMarker settings: -->
<init-param>
<param-name>auto_import</param-name>
<param-value>*/freemarker/common.ftl as c</param-value>
</init-param>
<init-param>
<param-name>tag_syntax</param-name>
<param-value>square_bracket</param-value>
</init-param>
<init-param>
<param-name>template_update_delay</param-name>
<param-value>0</param-value><!-- 0 is for development only! Use higher value otherwise. -->
</init-param>
<init-param>
<param-name>default_encoding</param-name>
<param-value>UTF-8</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>
</web-app>
Řídící servlet:
…
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOexception, ServletException {
List<Osoba> osoby = new LinkedList<osoba>();
osoby.add(new Osoba("Marie", "Černá", 32, "Ostrava"));
osoby.add(new Osoba("František", "Novák", 54, "Brno"));
osoby.add(new Osoba("Natálie", "Zajícová", 72, "České Budějovice"));
request.setAttribute("lide", osoby);
request.getServletContext().getRequestDispatcher("/lide.ftl").forward();
}
…
Požadavek na tento servlet vygeneruje stejný výstup, jako úvodní příklad.
Odkazy
Související články
Externí odkazy