Freemarker
Apache FreeMarker is a template engine: a Java library to generate text output (HTML web pages, e-mails, configuration files, source code, etc.) based on templates and changing data.
Getting Started
+ =
Template
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
data model
- product class
public class Product {
private String url;
private String name;
public Product(String url, String name) {
this.url = url;
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- create html class code
public class Demo {
public static void main(String[] args) throws Exception {
Template template = FreemarkerHelper.getTemplate("demo.ftl");
//map build
Map<String, Object> root = new HashMap<String, Object>();
map.put("user", "echo");
Product product = new Product("www.google.com", "greenhouse");
map.put("latestProduct", product);
FileHelper.createFile(template, "demo.html", root);
}
}
There are some utility class as following.
- get path of package web which save ftl and html.
public class PathHelper {
public static final String LOCAL_WEB_PATH = "/src/main/web/";
public static String getWebPath() {
String rootPath = System.getProperty("user.dir");
return rootPath + LOCAL_WEB_PATH;
}
}
- get freemarker template
Do not needlessly re-create Configuration instances; it’s expensive, among others because you lose the template cache. Configuration instances meant to be application-level singletons.
public class FreemarkerHelper {
private FreemarkerHelper() {}
private static Configuration configuration = null;
/**
* define Configuration
* @return
* @throws Exception
*/
public static Configuration getConfiguration() throws Exception {
if(configuration == null) {
configuration = new Configuration();
configuration.setDirectoryForTemplateLoading(new File(PathHelper.getWebPath())); //path
configuration.setObjectWrapper(new DefaultObjectWrapper());
}
return configuration;
}
/**
* Get template by ftl name under web;
* @param ftlName
* @return
* @throws Exception
*/
public static Template getTemplate(String ftlName) throws Exception {
Configuration configuration1 = getConfiguration();
Template template = configuration1.getTemplate(ftlName, "UTF-8"); //default charset UTF-8
return template;
}
}
- create file
public class FileHelper {
/**
* create html by template, htmlName, and modal map;
* @param template
* @param htmlName
* @param map
* @throws Exception
*/
public static void createFile(Template template, String htmlName, Map<String, Object> map) throws Exception {
File file = new File(PathHelper.getWebPath()+htmlName);
if (!file.exists()) {
file.createNewFile();
}
Writer out = new BufferedWriter(new FileWriter(file));
template.process(map, out);
out.flush();
}
}
output
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>
<body>
<h1>Welcome echo!</h1>
<p>Our latest product:
<a href="www.google.com">greenhouse</a>!
</body>
</html>
Base directives
if
With the if directive you can conditionally skip a section of the template.
- we change the ftl like this
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<#-- Here is the if directive demo -->
<#if user == "echo">
echo
<#elseif user != "hello">
not hello
<#else>
sb. we do not know.
</#if>
</body>
</html>
- output
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<h1>Welcome echo!</h1>
echo
</body>
</html>
list
The generic form of the list directive is:
<#list sequence as loopVariable>repeatThis</#list>.
The repeatThis part will be repeated for each item in the sequence that you have specified with sequence, one after the other, starting from the first item.
- change the Demo.java like this
public class Demo {
public static void main(String[] args) throws Exception {
Template template = FreemarkerHelper.getTemplate("demo.ftl");
//map build
Map<String, Object> map = new HashMap<String, Object>();
List<Product> productList = new LinkedList<Product>();
Product product = new Product("www.google.com", "greenhouse");
Product product2 = new Product("www.baidu.com", "bluesky");
productList.add(product);
productList.add(product2);
map.put("productList", productList);
FileHelper.createFile(template, "demo.html", map);
}
}
- ftl like this
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<#-- Here is the list directive demo -->
<#list productList as product>
<a href="${product.url}">${product.name}</a>
</#list>
</body>
</html>
- output
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<a href="www.google.com">greenhouse</a>
<a href="www.baidu.com">bluesky</a>
</body>
</html>
include
With the include directive you can insert the content of another file into the template.
- +add file copyright_footer.ftl
<i>
Copyright (c) 2016 <a href="houbb.github.io">Echo</a>,
<br>
All Rights Reserved.
</i>
- change ftl like this
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<#-- Here is the include directive demo -->
<#include "copyright_footer.ftl">
</body>
</html>
- output
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<i>
Copyright (c) 2016 <a href="houbb.github.io">Echo</a>,
<br>
All Rights Reserved.
</i>
</body>
</html>
Using built-ins
Missing variables
A non-existent variable and a variable with null value is the same for FreeMarker, so the “missing” term used here covers both cases.
- what will happen if missing ?
public class Demo {
public static void main(String[] args) throws Exception {
Template template = FreemarkerHelper.getTemplate("demo.ftl");
//map build
Map<String, Object> map = new HashMap<String, Object>();
map.put("user", "this is a long name...");
FileHelper.createFile(template, "demo.html", map);
}
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<#-- Here is the missing demo -->
${missing}
</body>
</html>
result
freemarker.core.InvalidReferenceException: Expression missing is undefined on line 10, column 7 in demo.ftl.
...
- how to solve this problem?
change the ftl like this
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
<#-- Here is the missing demo -->
${missing!'default value'}
<#if missing??>
${missing}
<#else>
missing
</#if>
</body>
</html>
output
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Title</title>
</head>
<body>
default value
missing
</body>
</html>
处理纯字符串
有时候我们希望将一穿带有 ${}
的字符串替代掉。
怎么办呢?
测试代码
public static void main(String[] args) throws IOException, TemplateException {
Configuration configuration = Configuration.getDefaultConfiguration();
Template template = new Template("template", "hello ${keyword}", configuration);
StringWriter stringwriter = new StringWriter();
Map<String, String> map = new HashMap<>();
map.put("keyword", "word");
template.process(map, stringwriter);
System.out.println(stringwriter.toString());
}
这个结果就是:
hello world