一、FreeMaker介紹
FreeMarker是一款免費的Java模板引擎,是一種基於模板和資料生成文字(HMLT、電子郵件、配置檔案、原始碼等)的工具,它不是面向終端使用者的,而是一款程式設計師使用的元件。
FreeMarker最初設計是用來在MVC模式的Web開發中生成HTML頁面的,所以沒有繫結Servlet或任意Web相關的東西上,所以它可以執行在非Web應用環境中。
發展史
FreeMarker第一版在1999年未就釋出了,2002年初使用JavaCC(Java Compiler Compiler是一個用Java開發的語法分析生成器)重寫了FreeMarker的核心程式碼,2015年FreeMarker程式碼遷移到了Apache下。
GitHub地址:https://github.com/apache/freemarker
工作原理
FreeMarker模板儲存在伺服器上,當有使用者訪問的時候,FreeMarker會查詢出相應的資料,替換模板中的標籤,生成最終的HTML返回給使用者,如下圖:
二、FreeMarker基礎使用
基礎使用分為3部分,這3部分組成了FreeMarker:
- 指令
- 表示式
指令是FreeMarker用來識別轉換的特殊標籤,表示式是標籤裡具體的語法實現,其他部分是一些不好分類的模板。
2.1 指令
使用FTL(freemarker template language)標籤來呼叫指令。
指令速覽:
- assign
- attempt, recover
- compress
- escape, noescape
- flush
- ftl
- function, return
- global
- if, else, elseif
- import
- include
- list, else, items, sep, break
- local
- macro, nested, return
- noparse
- nt
- setting
- stop
- switch, case, default, break
- t, lt, rt
- visit, recurse, fallback
- 使用者自定義標籤
下來我們分別來看每個指令對應具體使用。
2.1.1 assign 程式碼宣告
assign 分為變數和程式碼片段宣告兩種。
2.1.1.1 變數宣告
可以是單變數宣告,或多變數宣告,下面是多變數宣告的示例:
<#assign name="adam" age=18 "sex"="man">
${name} - ${age} - ${"sex"}
單個變數的話,只寫一個就可以了。
2.1.1.2 程式碼片段宣告
<#assign code>
<#list ["java","golang"] as c>
${c}
</#list>
</#assign>
${code}
其中 ${code}
是用來執行方法的,如果不呼叫話,程式碼片段不會執行。
2.1.2 attempt, recover 異常指令
attempt(嘗試), recover(恢復)指令類似於程式的try catch,示例如下:
<#attempt>
i am ${name}
<#recover>
error name
</#attempt>
如果有變數“name”就會正常顯示,顯示“i am xxx”,如果沒有變數就會顯示“error name”。
2.1.3 compress 壓縮程式碼移除空白行
<#compress>
1 2 3 4 5
test only
I said, test only
</#compress>
1 2 3 4 5
test only
I said, test only
效果如下:
對空白不敏感的格式,移除空白行還是挺有用的功能。
2.1.4 escape, noescape 轉義,不轉義
2.1.4.1 escape使用
<#escape x as x?html>
${firstName}
${lastName}
</#escape>
上面的程式碼,類似於:
${firstName?html}
${lastName?html}
Java程式碼:
@RequestMapping("/")
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("/index");
modelAndView.addObject("firstName", "<span style='color:red'>firstName</span>");
modelAndView.addObject("lastName", "lastName");
return modelAndView;
}
最終的效果是:
2.1.4.2 “?html”語法解析
單問號後面跟的是操作函式,類似於Java中的方法名,html屬於內建函式的一個,表示字串會按照HTML標記輸出,字元替換規則如下:
<
替換為<
>
替換為>
&
替換為&
"
替換為"
2.1.4.3 noescape使用
HTML程式碼:
<#escape x as x?html>
<#noescape>
${firstName}
</#noescape>
${lastName}
</#escape>
Java程式碼:
@RequestMapping("/")
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("/index");
modelAndView.addObject("firstName", "<span style='color:red'>firstName</span>");
modelAndView.addObject("lastName", "lastName");
return modelAndView;
}
最終效果:
2.1.5 function, return 方法宣告
程式碼格式:
<#function name param1 param2 ... paramN>
...
<#return returnValue>
...
</#function>
- name 為方法名稱
- param1, param2,paramN 方法傳遞過來的引數,可以有無限個引數,或者沒有任何引數
- return 方法返回的值,可以出現在function的任何位置和出現任意次數
示例程式碼如下:
<#function sum x y z>
<#return x+y+z>
</#function>
${sum(5,5,5)}
注意:function如果沒有return是沒有意義的,相當於返回null,而function之中資訊是不會列印到頁面的,示例如下:
<#function wantToPrint>
這裡的資訊是顯示不了的
</#function>
<#if wantToPrint()??>
Message:${wantToPrint()}
</#if>
“??”用於判斷值是否是null,如果為null是不執行的。如果不判null直接使用${}列印,會報模板錯誤,效果如下:
2.1.6 global 全域性程式碼宣告
語法如下:
<#global name=value>
或
<#global name1=value1 name2=value2 ... nameN=valueN>
或
<#global name>
capture this
</#global>
global使用和assign用法類似,只不過global宣告是全域性的,所有的名稱空間都是可見的。
2.1.7 if elseif else 條件判斷
語法如下:
<#if condition>
...
<#elseif condition2>
...
<#elseif condition3>
...
...
<#else>
...
</#if>
示例如下:
<#assign x=1 >
<#if x==1>
x is 1
<#elseif x==2>
x is 2
<#else>
x is not 1
</#if>
2.1.8 import 引入模板
語法: <#import path as hash>
示例如下
footer.ftl 程式碼如下:
<html>
<head>
<title>王磊的部落格</title>
</head>
<body>
this is footer.ftl
<#assign copy="來自 王磊的部落格">
</body>
</html>
index.ftl 程式碼如下:
<html>
<head>
<title>王磊的部落格</title>
</head>
<body>
<#import "footer.ftl" as footer>
${footer.copy}
</body>
</html>
最終輸出內容:
來自 王磊的部落格
2.1.9 include 嵌入模板
語法: <#include path>
示例如下
footer.ftl 程式碼如下:
<html>
<head>
<title>王磊的部落格</title>
</head>
<body>
this is footer.ftl
<#assign copy="來自 王磊的部落格">
</body>
</html>
index.ftl 程式碼如下:
<html>
<head>
<title>王磊的部落格</title>
</head>
<body>
<#include "footer.ftl">
</body>
</html>
最終內容如下:
this is footer.ftl
2.1.10 list, else, items, sep, break 迴圈
2.1.10.1 正常迴圈
輸出1-3的數字,如果等於2跳出迴圈,程式碼如下:
<#list 1..3 as n>
${n}
<#if n==2>
<#break>
</#if>
</#list>
注意:“1..3”等於[1,2,3]。
結果: 1 2
2.1.10.2 使用items輸出
示例如下:
<#list 1..3>
<ul>
<#items as n>
<li>${n}</li>
</#items>
</ul>
</#list>
2.1.10.3 sep 使用
跳過最後一項
<#list 1..3 as n>
${n}
<#sep>,</#sep>
</#list>
最終結果:1 , 2 , 3
2.1.10.4 陣列最後一項
程式碼如下:
<#list 1..3 as n>
${n}
<#if !n_has_next>
最後一項
</#if>
</#list>
使用“變數_has_next”判斷是否還有下一個選項,來找到最後一項,最終的結果:1 2 3 最後一項
2.1.11 macro 巨集
巨集:是一個變數名的程式碼片段,例如:
<#macro sayhi name>
Hello, ${name}
</#macro>
<@sayhi "Adam" />
相當於宣告瞭一個名稱為“sayhi”有一個引數“name”的巨集,使用自定義標籤“@”呼叫巨集。
輸出的結果: Hello, Adam
2.1.12 switch, case, defalut, break 多條件判斷
示例程式碼如下:
<#assign animal="dog" >
<#switch animal>
<#case "pig">
This is pig
<#break>
<#case "dog">
This is dog
<#break>
<#default>
This is Aaimal
</#switch>
2.1.13 擴充套件知識
指令自動忽略空格特性
FreeMarker會忽略FTL標籤中的空白標記,所以可以直接寫:
<#list ["老王","老李","老張"]
as
p>
${p}
</#list>
即使是這個格式也是沒有任何問題的,FreeMarker會正常解析。
2.2 表示式
2.2.1 字串拼接
字元拼接程式碼:
<#assign name="ABCDEFG">
${"Hello, ${name}"}
結果:Hello, ABCDEFG
2.2.2 算術運算
2.2.2.1 算術符
算術符有五種:
+
-
*
/
%
求餘(求模)
示例程式碼:
${100 - 10 * 20}
輸出:
-100
2.2.2.2 數值轉換
${1.999?int}
輸出:
1
注意:數值轉換不會進行四捨五入,會捨棄小數點之後的。
2.2.3 內建函式(重點)
內建函式:相當於我們Java類裡面的內建方法,非常常用,常用的內建函式有:時間內建函式、字元內建函式、數字內建函式等。
2.2.3.1 單個問號和兩個問號的使用和區別
單問號:在FreeMarker中用單個問號,來呼叫內建函式,比如: ${"admin"?length}
檢視字串“admin”的字元長度,其中length就是字串的內建函式。
雙引號:表示用於判斷值是否為null,比如:
<#if admin??>
Admin is not null
</#if>
2.2.3.2 字串內建函式
2.2.3.2.1 是否包含判斷
使用contains判斷,程式碼示例:
<#if "admin"?contains("min")>
min
<#else >
not min
</#if>
輸出:
min
2.2.3.2.2 大小寫轉換
示例程式碼:
<#assign name="Adam">
${name?uncap_first}
${name?upper_case}
${name?cap_first}
${name?lower_case}
輸出:
adam ADAM Adam adam
更多的字串內建函式:https://freemarker.apache.org/docs/ref_builtins_string.html
2.2.3.3 數字內建函式
示例程式碼:
${1.23569?string.percent}
${1.23569?string["0.##"]}
${1.23569?string["0.###"]}
輸出:
124% 1.24 1.236
注意:
- 使用string.percent計算百分比,會自動四捨五入。
- 使用“?string["0.##"]”可以自定義取小數點後幾位,會自動四捨五入。
2.2.3.4 時間內建函式
2.2.3.4.1 時間戳轉換為任何時間格式
程式碼:
<#assign timestamp=1534414202000>
${timestamp?number_to_datetime?string["yyyy/MM/dd HH:mm"]}
輸出:
2018/08/16 18:10
2.2.3.4.2 時間格式化
示例程式碼:
<#assign nowTime = .now>
${nowTime} <br />
${nowTime?string["yyyy/MM/dd HH:mm"]} <br />
輸出:
2018-8-16 18:33:50
2018/08/16 18:33
更多內建方法:https://freemarker.apache.org/docs/ref_builtins.html
三、Spring Boot 整合
3.1 整合環境
- Spring Boot 2.0.4
- FreeMaker 2.3.28
- JDK 8
- Windows 10
- IDEA 2018.2.1
3.2 整合步驟
3.2.1 pom.xml 新增FreeMaker依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
3.2.2 application.properties 配置模板
主要配置,如下:
## Freemarker 配置
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl
配置項 | 型別 | 預設值 | 建議值 | 說明 |
---|---|---|---|---|
spring.freemarker.template-loader-path | String | classpath:/templates/ | 預設 | 模版存放路徑 |
spring.freemarker.cache | bool | true | 預設 | 是否開啟快取,生成環境建議開啟 |
spring.freemarker.charset | String | - | UTF-8 | 編碼 |
spring.freemarker.content-type | String | text/html | text/html | content-type型別 |
spring.freemarker.suffix | String | .ftl | .ftl | 模板字尾 |
spring.freemarker.expose-request-attributes | bool | false | false | 設定所有request的屬性在merge到模板的時候,是否要都新增到model中 |
spring.freemarker.expose-session-attributes | bool | false | false | 設定所有HttpSession的屬性在merge到模板的時候,是否要都新增到model中. |
spring.freemarker.request-context-attribute | String | - | request | RequestContext屬性的名稱 |
更多配置:
# FREEMARKER (FreeMarkerProperties)
spring.freemarker.allow-request-override=false # Whether HttpServletRequest attributes are allowed to override (hide) controller generated model attributes of the same name.
spring.freemarker.allow-session-override=false # Whether HttpSession attributes are allowed to override (hide) controller generated model attributes of the same name.
spring.freemarker.cache=false # Whether to enable template caching.
spring.freemarker.charset=UTF-8 # Template encoding.
spring.freemarker.check-template-location=true # Whether to check that the templates location exists.
spring.freemarker.content-type=text/html # Content-Type value.
spring.freemarker.enabled=true # Whether to enable MVC view resolution for this technology.
spring.freemarker.expose-request-attributes=false # Whether all request attributes should be added to the model prior to merging with the template.
spring.freemarker.expose-session-attributes=false # Whether all HttpSession attributes should be added to the model prior to merging with the template.
spring.freemarker.expose-spring-macro-helpers=true # Whether to expose a RequestContext for use by Spring's macro library, under the name "springMacroRequestContext".
spring.freemarker.prefer-file-system-access=true # Whether to prefer file system access for template loading. File system access enables hot detection of template changes.
spring.freemarker.prefix= # Prefix that gets prepended to view names when building a URL.
spring.freemarker.request-context-attribute= # Name of the RequestContext attribute for all views.
spring.freemarker.settings.*= # Well-known FreeMarker keys which are passed to FreeMarker's Configuration.
spring.freemarker.suffix=.ftl # Suffix that gets appended to view names when building a URL.
spring.freemarker.template-loader-path=classpath:/templates/ # Comma-separated list of template paths.
spring.freemarker.view-names= # White list of view names that can be resolved.
3.2.3 編寫HTML程式碼
<html>
<head>
<title>王磊的部落格</title>
</head>
<body>
<div>
Hello,${name}
</div>
</body>
</html>
3.2.4 編寫Java程式碼
新建index.java檔案,Application.java(入口檔案)程式碼不便,index.java程式碼如下:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/")
public class Index {
@RequestMapping("/")
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("/index");
modelAndView.addObject("name", "老王");
return modelAndView;
}
}
關鍵程式碼解讀:
- @Controller註解:標識自己為控制器,只需要配置@RequestMapping之後,就可以把使用者URL對映到控制器;
- 使用ModelAndView物件,指定檢視名&新增檢視物件。
3.2.5 執行
執行上面4個步驟之後,就可以執行這個Java專案了,如果是IDEA使用預設快捷鍵“Shift + F10”啟動除錯,在頁面訪問:http://localhost:8080/ 就可看到如下效果:
四、參考資料
FreeMarker官方文件:https://freemarker.apache.org/
FreeMarker翻譯的中文網站:http://freemarker.foofun.cn/toc.html