FREEMARKER学习笔记
一.背景概念
Freemarker之前一直零零散散的接触过一些,都没有很好的去总结过,这里做个学习笔记。Freemarker是一个模板引擎,可以看成和JSP扮演差不多的角色。在Struts2中有大量的应用,基于模板生成文本输出。本身使用纯Java编写,优点很多,缺点是分布式环境中的性能不怎么样。经常被用来设计生成HTML Web页面,但是并不限于此,在普通的Java项目里面也可以应用,比如实现一个Java代码生成器。和JSP不一样的是,Freemarker不依赖于容器,也就是说,他并不知道有HTTP,servlet之类的,只要有基本的Java运行环境即可。
二.用法
2.1 HelloWorld
先来个HelloWorld程序简单感受下用法,当然在此之前有些概念先说一下。Freemarker的data根节点是一个map,下面可以有很多的(Key,Value).继续往下层还可以套很多的容器等子节点,总体是一个树状结构。另外,虽然Freemarker也具备一定的编程能力,但常用的模式还是,Java程序提供数据,freemarker负责模板。
首先创建一个普通Java程序,导入Freemarker的jar包,项目目录下新建templates目录,其下新建hello.ftl模板文件,写入以下内容:
hello,${user}!
然后新建Java类,开始HelloWorld效果测试,
package com.zqx.test;
import freemarker.template.Configuration;
import freemarker.template.Template;
import java.io.File;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
public class TestFreemarker {
public static void main(String[] args) throws Exception{
//创建Freemarker配置实例
Configuration configuration = new Configuration();
configuration.setDirectoryForTemplateLoading(new File("templates"));
//创建数据模型
Map root = new HashMap();
root.put("user","zqx");
//加载模板文件
Template template = configuration.getTemplate("hello.ftl");
//显示生成的数据
Writer out = new OutputStreamWriter(System.out);
template.process(root,out);
out.flush();
out.close();
}
}
结果如下:
2.2 常用指令
1.if指令
模板文件hello.ftl里面加入以下内容
------------if指令测试-----------------
<#if user=="zqx" >
身份验证通过
<#else>
身份验证失败
</#if>
************
<#if random lt 60>
分数:${random},不及格
<#elseif random lte 80>
分数:${random},良好
<#else >
分数:${random},优秀
</#if>
Java类TestFreemarker.java加入这句:
root.put("random",new Random().nextInt(100));
输出结果:
这里可以顺路提一下:
字符串类型可以使用单引号或双引号。里面可以使用转移字符"",如果存在大量的特殊字符,可以在引号前面直接加上一个r,则所有字符将直接输出。
数值类型可以直接输入,不需要引号,不支持科学记数法。
2.list指令
模板文件hello.ftl里面加入以下内容
------------list指令测试-----------------
<#list lst as girl>
<b>姓名:${girl.name},年龄:${girl.age}</b></br>
</#list>
新建Girl类,并在Java类TestFreemarker.java加入这段:
List list = new ArrayList();
list.add(new Girl("小丽",18,"A"));
list.add(new Girl("小美",13,"B"));
list.add(new Girl("小红",22,"C"));
root.put("lst",list);
测试结果:
3.include指令
该指令可以引入其他文件,并不仅限于模板文件。也可以是其他类型的文本文件。
templates下新建include.ftl文件:
hello,${user},我是被包含的文件~
在hello.ftl中引用:
------------include指令测试-----------------
<#include "include.ftl" />
结果:
4.marco自定义指令
类似于函数,过程,方法等概念。
在hello.ftl继续加入以下内容:
------------marco指令测试-----------------
<#macro m1 > <#-- 定义不带参数的宏指令 -->
<b>aaaaaaaaaaaa </b>
<b>bbbbbbbbbbbb </b>
</#macro>
第一次调用:
<@m1></@m1>
第二次调用:
<@m1/>
<#macro m2 a b c > <#-- 定义带参数的宏指令,自动类型转换 -->
${a}---${b}---${c}
</#macro>
调用带参数的宏指令:
<@m2 "a" "bb" "ccc"/>
结果:
5.nested指令
在hello.ftl中加入:
------------nested指令测试-----------------
<#macro border width>
<table border="4" width="${width}px">
<tr>
<td>
<#nested />
</td>
</tr>
</table>
</#macro>
测试nested指令:
<@border 100>
单元格内容
</@border>
结果:
6.命名空间
类似于Java里的package,主要为了防止命名冲突
templates下新建import.ftl文件:
<#macro copyright date>
<p>Copyright (C) ${date} 汉得信息</p>
</#macro>
<#assign mail = "2443934916@qq.com" />
在hello.ftl里加入
------------import指令测试-----------------
<#import "import.ftl" as bb />
<@bb.copyright date="1998-2018" />
${bb.mail}
<#assign mail="jxlpzqx@163.com" />
${mail}
<#assign mail="qingxin.zhu@hand-china.com" in bb />
${bb.mail}
命名空间命名规则:
一个重要规则是ftl模板文件的路径不应该包含大写字母,为了分割单词应该使用下划线。
另外,结合前面的自定义marco宏指令说一下,freemarker自带的指令一般都以#开头,如<#if></#if>. 自定义指令一般一@开头,其他框架中定义的指令也看做自定义指令,但一般会多一个命名空间,Struts2的默认命名空间我们指定为s:
<#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] /> <#--这一句是为了让Freemarker识别struts2的标签 -->
使用就可以这样使用了:
<@s.form></@s.form>
结果:
7.date类型处理
在hello.ftl里加入
------------date类型测试-----------------
${date?string("yyyy-MM-dd HH:mm:ss")}
在在Java类TestFreemarker.java加入
root.put("date",new Date());
结果:
8.空值处理
在hello.ftl里加入
------------空值处理测试-----------------
<#-- ${nullval} 没有定义这个变量会报异常 -->
${nullval!} <#-- 如果没有定义,默认为空字符串 -->
${nullval!"aaa"} <#-- 如果没有定义,使用给定默认值aaa -->
<#-- ??返回布尔值,可以判断变量是否存在 -->
<#if user??><h1>Welcome ${user}!</h1></#if>
结果:
另外,注意一下,这里我们为了测试方便,out流都指向了控制台输出。同理,我们把流指向文件,response到浏览器,甚至于通过scoket指向远程的某个地方都是没问题的。
2.3 在web项目中使用Freemarker
可以直接参考freemarker的examples参考项目webapp1,这里直接粘一些主要代码,方便自己以后查找
Web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>FreeMarker Example Web Application 1</display-name>
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>example.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>help.html</welcome-file>
</welcome-file-list>
</web-app>
Servlet中调用:
package example;
import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import freemarker.template.*;
/**
* This Servlet does not do anything useful, just prints "Hello World!". The
* intent is to help you to get started if you want to build your own Controller
* servlet that uses FreeMarker for the View. For more advanced example, see the
* 2nd Web application example.
*/
public class HelloServlet extends HttpServlet {
private Configuration cfg;
public void init() {
// Initialize the FreeMarker configuration;
// - Create a configuration instance
cfg = new Configuration();
// - Templates are stoted in the WEB-INF/templates directory of the Web app.
cfg.setServletContextForTemplateLoading(
getServletContext(), "WEB-INF/templates");
// In a real-world application various other settings should be explicitly
// set here, but for the sake of brevity we leave it out now. See the
// "webapp2" example for them.
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Build the data-model
Map root = new HashMap();
root.put("message", "Hello World!");
// Get the templat object
Template t = cfg.getTemplate("test.ftl");
// Prepare the HTTP response:
// - Use the charset of template for the output
// - Use text/html MIME-type
resp.setContentType("text/html; charset=" + t.getEncoding());
Writer out = resp.getWriter();
// Merge the data-model and the template
try {
t.process(root, out);
} catch (TemplateException e) {
throw new ServletException(
"Error while processing FreeMarker template", e);
}
}
}
三. 其他
到这里,Freemarker就算是入门了。至于其他的更具体,更详细的用法,包括集合,map的各种用法啊,也不可能全记,用到了再去查就是了。
主要参考一个忘了在哪里找到的视频