楔子:
之前在和同事讨论,同事说“jsp技术太古老了,有几种页面技术代替,比如FreeMarker、Velocity、thymeleaf,jsp快废弃了……”云云。我这一听有点心虚……我在后端部分越刨越深,页面装配技术什么的好像只知道有jsp……趁放假自己补补课啦~
简介:
FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,纯Java编写。类似jsp,简单来讲就是模板加数据模型,然后输出页面。
图片来自尚学堂课件,侵权删
相对于jsp,FreeMarker的性能略差几十毫秒,但是复杂页面上性能比jsp更佳。
而且最好的一点,我感觉应该是可以直接把美工写好的html放进模板中使用(无需加jsp头等),FreeMarker自带的一些标签用着也很简单。FreeMarker的模板文件格式为ftl,也可以直接用html
FreeMarker可以应用更多的场景,与容器无关;而jsp要求有JVM环境,只能应用于web应用中。
HelloWorld:
第一个FreeMarker代码
新建一个Java project,起名为 FreeMarker,在src外部新建一个文件夹命名为templates,如图:
在templates中新建一个file,命名为first.ftl,添加如下代码(其中的表达式类似于EL表达式):
hello,${user},这是你的第一个FreeMarker程序!
下载FreeMarker.jar并引入项目
新建FirstFreeMarker类,代码如下:
1 package com.hellxz;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.OutputStreamWriter;
6 import java.io.Writer;
7 import java.util.HashMap;
8 import java.util.Map;
9
10 import freemarker.template.Configuration;
11 import freemarker.template.Template;
12 import freemarker.template.TemplateException;
13
14 /**
15 * 第一个FreeMarker程序
16 *
17 * @author hellxz
18 */
19 public class FirstFreeMarker {
20
21 @SuppressWarnings({"rawtypes","unchecked"})
22 public static void main(String[] args) throws IOException, TemplateException {
23 // 创建Freemarker配置实例
24 Configuration cfg = new Configuration();
25 cfg.setDirectoryForTemplateLoading(new File("templates"));
26
27 // 创建数据模型
28 Map root = new HashMap();
29 root.put("user", "老张");
30
31 // 加载模板文件
32 Template t1 = cfg.getTemplate("first.ftl");
33
34 // 显示生成的数据,将合并后的数据打印到控制台
35 Writer out = new OutputStreamWriter(System.out);
36 t1.process(root, out);
37 out.flush();
38 out.close();
39
40 }
41
42 }
运行代码,查看输出:
hello,老张,这是你的第一个FreeMarker程序!
测试举例:
本例子基本涵盖了大部分FreeMarker特有的属性,参考Java语言不同点写就,相同点并没有测试。通过观察代码可以很清晰的看出这些函数、指令的使用方法
新建一个Address类:
1 package com.hellxz;
2
3 /**
4 * 地址
5 *
6 * @author hellxz
7 */
8 public class Address {
9
10 private String country; // 国家
11 private String city; // 城市
12
13 //getters & setters
14 public String getCountry() {
15 return country;
16 }
17
18 public void setCountry(String country) {
19 this.country = country;
20 }
21
22 public String getCity() {
23 return city;
24 }
25
26 public void setCity(String city) {
27 this.city = city;
28 }
29
30 public Address(String country, String city) {
31 this.country = country;
32 this.city = city;
33 }
34 }
新建一个TestFreeMarker类,代码如下:
1 package com.hellxz;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.OutputStreamWriter;
6 import java.io.Writer;
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.Map;
10 import java.util.Random;
11
12 import freemarker.template.Configuration;
13 import freemarker.template.Template;
14 import freemarker.template.TemplateException;
15
16 /**
17 * FreeMarker Test
18 *
19 * @author hellxz
20 */
21 public class TestFreeMarker {
22
23 @SuppressWarnings({ "rawtypes", "unchecked" })
24 public static void main(String[] args) throws IOException, TemplateException {
25 //1.创建配置文件
26 Configuration conf = new Configuration();
27 //2.设置模板目录
28 conf.setDirectoryForTemplateLoading(new File("templates"));
29 //3.数据模型
30 Map<String,Object> map = new HashMap<>();
31 map.put("user", "老张");
32 map.put("random",new Random().nextInt(100));
33 //新建一个list放入map中,用于测试遍历list操作
34 ArrayList list = new ArrayList();
35 list.add(new Address("中国","上海"));
36 list.add(new Address("日本","东京"));
37 map.put("list", list);
38 //测试内建函数
39 map.put("html5", "<b>大写的文字</b>");
40 map.put("name", "hellxz");
41 map.put("upper", "ABCDEF");
42 //4.获取模板文件
43 Template template = conf.getTemplate("a.ftl");
44 //5.输出流
45 Writer out = new OutputStreamWriter(System.out);
46 //6.生成文件流输出
47 template.process(map, out);
48 out.flush();
49 out.close();
50 }
51 }
在templates文件夹下新建a.ftl
1 hello,${user},今天看起来很精神嘛!
2 ----------------------------------
3 if分支语句测试:
4 <#if user=="老张">
5 老张!
6 </#if>
7 ----------------------------------
8 if else 分支测试:
9 <#if user=="老李">
10 老李
11 <#else>
12 老张
13 </#if>
14 ----------------------------------
15 if else if else 测试:
16 因为大于小于号等会被转义,使用简写代替比较符号
17 gt(great than的简写) 代替 >
18 lt(less than的简写) 代替 <
19 gte(great than equal的简写) 代替 >=
20 lte (less than equal的简写) 代替 <=
21 <#if random gt 80>
22 优秀
23 <#elseif random gt 60>
24 及格
25 <#else>
26 不及格
27 </#if>
28 ----------------------------------
29 遍历list测试:
30 <#list list as addr>
31 ${addr.country} ${addr.city}
32 </#list>
33 ----------------------------------
34 include包含测试:
35 <#include "include.txt"/>
36 ----------------------------------
37 macro无参函数(宏函数)测试:
38 定义函数:
39 <#macro m1>
40 我是函数内容
41 </#macro>
42 调用函数测试:
43 <@m1/><@m1/><#--这是注释内容:这里调用了两次函数-->
44 ----------------------------------
45 macro带参函数<#--(格式为"<#macro 函数名 [变量1 变量2 变量3 ……] </#macro>")-->:
46 <#macro cc a b c>
47 ${a}/${b}/${c}
48 </#macro>
49 调用测试<#--(格式为:"<@函数名 [变量1值 变量2值 变量3值 ……] </#macro>")-->:
50 <@cc "中" "明" "月"/>
51 ----------------------------------
52 nested测试:
53 用于一大段代码的嵌入
54 <#macro border>
55 <html>
56 <head>
57 <body>
58 <#nested/>
59 </body>
60 </head>
61 </html>
62 </#macro>
63 向nested部分添加内容:
64 <@border>
65 <h1>我是nested的内容</h1>
66 </@border>
67 ----------------------------------
68 测试命名空间:
69 <#import "b.ftl" as bb />
70 <@bb.copyright date="2010-2011" />
71 ${bb.mail}
72 <#assign mail="my@163.com" />
73 ${mail}
74 <#assign mail="my@163.com" in bb />
75 ${bb.mail}
76 -----------------------------------
77 声明、指定变量assign:
78 测试数据类型:
79 <#assign ss="hellxz"/>
80 文本型:${ss}
81 <#assign s1=1 />
82 数值型:${s1}
83 <#assign s2=true/>
84 布尔型:<#if s2>布尔型</#if>
85 -------------------------------------
86 字符串常见内建函数:
87 html转义:${html5?html}
88 cap_first(首字母大写):${name?cap_first}
89 upper_case(转大写):${name?upper_case}
90 lower_case(转小写):${upper?lower_case}
91 数值常见内建函数:
92 int(取整数部分)
93 集合内建函数:
94 size(取集合大小)
95 ------------------------------------
96 字符串空值处理:
97 FreeMarker不支持空值,如果为空直接报错
98 没有定义直接引用
99 <#-- ${sss} 直接报错了-->
100 空值处理:
101 ${sss!}<#-- 为空则输出空字符串 -->
102 ${sss!"default"} <#--设置默认值,为空自动使用-->
103 ------------------------------------------
104 ??布尔值处理
105 <#if user??>
106 如果该值存在,返回true,相当于 if user != null
107 <#else>
108 该值不存在返回false
109 </#if>
新建b.ftl 用于测试命名空间
1 <#macro copyright date>
2 <p>Copyright (C) ${date} 北京尚学堂.</p>
3 </#macro>
4 <#assign mail = "bjsxt@163.com">
在templates下新建include.txt,用于测试include指令
我是被包含的内容!
运行TestFreeMarker,查看输出(这里为了方便比较,加上行号):
1 hello,老张,今天看起来很精神嘛!
2 ----------------------------------
3 if分支语句测试:
4 老张!
5 ----------------------------------
6 if else 分支测试:
7 老张
8 ----------------------------------
9 if else if else 测试:
10 因为大于小于号等会被转义,使用简写作为比较符号
11 gt=great than = >
12 lt=less than = <
13 gte = great than equal = >=
14 lte = less than equal = <=
15 及格
16 ----------------------------------
17 遍历list测试:
18 中国 上海
19 日本 东京
20 ----------------------------------
21 include包含测试:
22 我是被包含的内容!
23 ----------------------------------
24 macro无参函数(宏函数)测试:
25 定义函数:
26 调用函数测试:
27 我是函数内容
28 我是函数内容
29 ----------------------------------
30 macro带参函数:
31 调用测试:
32 中/明/月
33 ----------------------------------
34 nested测试:
35 用于一大段代码的嵌入
36 向nested部分添加内容:
37 <html>
38 <head>
39 <body>
40 <h1>我是nested的内容</h1>
41 </body>
42 </head>
43 </html>
44 ----------------------------------
45 测试命名空间:
46 <p>Copyright (C) 2010-2011 北京尚学堂.</p>
47 bjsxt@163.com
48 my@163.com
49 my@163.com
50 -----------------------------------
51 声明、指定变量assign:
52 测试数据类型:
53 文本型:hellxz
54 数值型:1
55 布尔型:布尔型
56 -------------------------------------
57 字符串常见内建函数:
58 html转义:<b>大写的文字</b>
59 cap_first(首字母大写):Hellxz
60 upper_case(转大写):HELLXZ
61 lower_case(转小写):abcdef
62 数值常见内建函数:
63 int(取整数部分)
64 集合内建函数:
65 size(取集合大小)
66 ------------------------------------
67 字符串空值处理:
68 FreeMarker不支持空值,如果为空直接报错
69 没有定义直接引用
70 空值处理:
71
72 default
73 ------------------------------------------
74 ??布尔值处理
75 如果该值存在,返回true,相当于 if user != null
看了一下漏了一个日期处理,这里补一下:
map.put("date", new Date());
a.ftl中模板写法:
${date?string("yyyy-MM-dd HH:mm:ss")}
输出:
2018-02-18 16:18:10
字符串连接字符串连接有两种语法:(1) 使用${..}或#{..}在字符串常量内插入表达式的值;
(2) 直接使用连接运算符“+”连接字符串。如,下面两种写法等效:
${"Hello, ${user}"}
${"Hello, " + user + "!"} 有一点需要注意: ${..}只能用于文本部分作为插值输出,而不能用于比较等其他用途,如:
<#if ${isBig}>Wow!</#if>
<#if "${isBig}">Wow!</#if> 应该写成:
<#if isBig>Wow!</#if>
截取子串截取子串可以根据字符串的索引来进行,如果指定一个索引值,则取得字符串该索引处的字符;如果指定两个索引值,则截取两个索引中间的字符串子串。如:
<#assign number="01234">
${number[0]} <#-- 输出字符0 -->
${number[0..3]} <#-- 输出子串“0123” -->
本文为FreeMarker简单的语法使用,servlet以及struts部分见我的下篇博客