楔子:
之前在和同事讨论,同事说“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部分见我的下篇博客
http://www.cnblogs.com/hellxz/p/8453239.html