Table of contents
Freemarker
Hello World
public static void main(String[] args) throws IOException, TemplateException {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
StringTemplateLoader tl = new StringTemplateLoader();
tl.putTemplate("bla", "blabla ${test} blabla");
cfg.setTemplateLoader(tl);
Template template = cfg.getTemplate("bla");
// Build the data-model
Map<String, Object> data = new HashMap<String, Object>();
data.put("test", "Hello World!");
// Console output
Writer out = new OutputStreamWriter(System.out);
template.process(data, out);
out.flush();
}
loading templates from the classpath
TemplateLoader ctl = new ClassTemplateLoader(getClass(), "/freemarker");
cfg.setTemplateLoader(ctl);
cfg.getTemplate("filename.tpl")
loading templates from the filesystem
TemplateLoader ftl = new FileTemplateLoader(new File(templatePath));
chaining multiple template loaders
TemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[] { ftl, ctl });
storing the result in a String
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(baos);
cfg.getTemplate(template).process(data, writer);
writer.flush();
return baos.toString("UTF-8");
escaping output
comments
<#-- programmer's grief -->
filename extension for auto escape html special chars
.ftlh
filename extension for auto escape xml special chars
.ftlx
force escaping for a specific output format regardless of filename (inludes not affected)
<#ftl output_format="HTML">
print raw value (no escaping)
${[value]?no_esc}
documentation
https://freemarker.apache.org/docs/dgui_quickstart_template.html#dgui_quickstart_template_autoescaping
https://freemarker.apache.org/docs/pgui_config_outputformatsautoesc.html
https://freemarker.apache.org/docs/dgui_misc_autoescaping.html
whitespace
trim lines
<#compress>
...
<#/compress>
documentation
https://freemarker.apache.org/docs/dgui_misc_whitespace.html
basics
assign variable
<#assign x = 1>
different kind of null checks
?? -> not null
?has_content -> not empty
![fallback] -> fallback if null
(user.price)! handles all missing variable errors thrown during the evaluation of the ()
(user.price)!0 default value if any part of path is null
optional value
${(log)!}
${variable.method()!}
default value if null
${[variable]![preset]}
section depending on optional value
<#if log??>
${log}
</#if>
types
string
string comparison
<#if someString == someOtherString>
<#if someString != someOtherString>
number
defining and incrementing
<#assign x=0>
<#assign x=x+1>
<#assign x+=1>
string to number
${'999'?number}
compare 2 numbers
${[number] == [number]}
${[number] lt [number]}
${[number] gt [number]}
${[number] lte [number]}
${[number] gte [number]}
print variable without readability characters (numbers without commas, etc)
${question.id?c}
boolean
logical or
||
logical and
&&
logical not
!
map
create a simple map
{'[key]': '[value]'}
read a value from a map
${map[key]}
iterate keys
<#list map?keys as key>${key} = ${map[key]}</#list>
sequence
defining a sequence
<#assign values = ["a", "b"]>
<#list seq[1..3] as i>${i}</#list>
accessing a value from a sequence
${values[0]}
getting the size of a sequence
${values?size}
collection is empty?
?has_content
?size = 0
collection contains value?
?seq_contains([value])
date
date with format
${aDateTime?string["dd.MM.yyyy, HH:mm"]}
${aDateTime?iso("Europe/Rome")}
fragments
include another template
<#include "layout/bottom.tpl"/>
simple macro
<#macro header title>
<h1>${title}</h1>
</#macro>
macro usage
<@header title='blabla' />
macro with optional value
<#macro [name] [param]="[preset]" >
macro with optional value and check
<#macro [name] [param]="" >
<#if ([param]?has_content)>
macro with nested content
<#macro wrap>
before <#nested> after
</#macro>
calling a macro with nested content
<@wrap>
<b>inbetween</b>
</@wrap>
control flow
ternary operator
${result.incorrect ? then ('incorrect', 'visible')}
${(variable.property == 0) ? then ('a', 'b')}
if else
<#if condition>
...
<#elseif condition>
...
<#else>
...
</#if>
iterating a sequence
<#list values as value>
<h1>${value}</h1>
</#list>
for each loop
<#list someList as entry>
${entry.someProperty}
</#list>
iterating with index
<#list 0..variable?size-1 as index>
<p>${variable[index]}</p>
</#list>
Tree structures
navigating a tree structure
<#macro tree nodes>
<#list nodes.getChildren() as node>
<ul>
<li>
${node.getName()}
<#if node.hasChildren()>
<@tree nodes=node />
</#if>
</li>
</ul>
</#list>
</#macro>
to call
<@tree nodes=root/>
sample tree node
public class TreeNode {
private List<TreeNode> children = new ArrayList<>();
private String name;
public TreeNode(String name) {
this.name = name;
}
public List<TreeNode> getChildren() {
return children;
}
public String getName() {
return name;
}
public boolean hasChildren() {
return !children.isEmpty();
}
}
Links
try freemarker code online
https://try.freemarker.apache.org/