【學習筆記】初識FreeMarker簡單使用
楔子:
之前在和同事討論,同事說“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 packagecom.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="[email protected]" /> 73 ${mail} 74 <#assign mail="[email protected]" 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 = "[email protected]">
在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部分見下篇博客
【學習筆記】初識FreeMarker簡單使用