FreeMarker 快速入門
FreeMarker是一個很值得去學習的模版引擎。它是基於模板文件生成其他文本的通用工具。本章內容通過如何使用FreeMarker生成Html web 頁面 和 代碼自動生成工具來快速瞭解FreeMarker。
1 簡介
FreeMarker是一款用java語言編寫的模版引擎,它雖然不是web應用框架,但它很合適作爲web應用框架的一個組件。
特點:
- 輕量級模版引擎,不需要Servlet環境就可以很輕鬆的嵌入到應用程序中
- 能生成各種文本,如html,xml,java,等
- 入門簡單,它是用java編寫的,很多語法和java相似
工作原理:(借用網上的圖片)
2 FreeMarker 程序
這裏通過模擬簡單的代碼自動生產工具來感受第一個FreeMarker程序。
項目目錄結構
項目創建流程
第一步:創建一個maven項目導入 FreeMarker jar 包
第二步:創建目錄templates,並創建一個 FreeMarker模版文件 hello.ftl
第三步:創建一個運行FreeMarker模版引擎的 FreeMarkerDemo.java 文件
第四步:運行main方法後刷新項目
pom.xml 文件 ,maven 項目核心文件,管理 jar 包。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.freemark</groupId>
<artifactId>freemarkerStudy</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency>
</dependencies>
</project>
hello.ftl FreeMarker基本語法: ${xxx} xxx 相當於佔位符,java後臺給xxx賦值後,再通過${}輸出
package ${classPath};
public class ${className} {
public static void main(String[] args) {
System.out.println("${helloWorld}");
}
}
FreeMarkerDemo.java 核心方法,使用 FreeMarker 模版引擎。
package com.freemark.hello;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import freemarker.template.Configuration;
import freemarker.template.Template;
/**
* 最常見的問題:
* java.io.FileNotFoundException: xxx does not exist. 解決方法:要有耐心
* FreeMarker jar 最新的版本(2.3.23)提示 Configuration 方法被棄用
* 代碼自動生產基本原理:
* 數據填充 freeMarker 佔位符
*/
public class FreemarkerDemo {
private static final String TEMPLATE_PATH = "src/main/java/com/freemark/hello/templates";
private static final String CLASS_PATH = "src/main/java/com/freemark/hello";
public static void main(String[] args) {
// step1 創建freeMarker配置實例
Configuration configuration = new Configuration();
Writer out = null;
try {
// step2 獲取模版路徑
configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
// step3 創建數據模型
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("classPath", "com.freemark.hello");
dataMap.put("className", "AutoCodeDemo");
dataMap.put("helloWorld", "通過簡單的 <代碼自動生產程序> 演示 FreeMarker的HelloWorld!");
// step4 加載模版文件
Template template = configuration.getTemplate("hello.ftl");
// step5 生成數據
File docFile = new File(CLASS_PATH + "\\" + "AutoCodeDemo.java");
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
// step6 輸出文件
template.process(dataMap, out);
System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^AutoCodeDemo.java 文件創建成功 !");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != out) {
out.flush();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
運行程序後刷新項目,會發現多了一個AutoCodeDemo.java類。不僅僅是java類,xml也是可以。筆者就是通過FreeMarker做了一個簡易的工具類,公司的一個標準管理頁面及其增刪改查等功能,以及相關的配置文件(十三個文件),一個回車就全部自動生成(偷懶ing)。
3 FreeMarker 語法
語法和java很類似,其中宏的概念可能比較陌生,先上代碼
stringFreeMarker.ftl FreeMarker主要核心知識點
字符串輸出:
${"Hello ${name} !"} / ${"Hello " + name + " !"}
<#assign cname=r"特殊字符完成輸出(http:\www.baidu.com)">
${cname}
字符串截取 :
通過下標直接獲取下標對應的字母: ${name[2]}
起點下標..結尾下標截取字符串:${name[0..5]}
算數運算:
<#-- 支持"+"、"-"、"*"、"/"、"%"運算符 -->
<#assign number1 = 10>
<#assign number2 = 5>
"+" : ${number1 + number2}
"-" : ${number1 - number2}
"*" : ${number1 * number2}
"/" : ${number1 / number2}
"%" : ${number1 % number2}
比較運算符:
<#if number1 + number2 gte 12 || number1 - number2 lt 6>
"*" : ${number1 * number2}
<#else>
"/" : ${number1 / number2}
</#if>
內建函數:
<#assign data = "abcd1234">
第一個字母大寫:${data?cap_first}
所有字母小寫:${data?lower_case}
所有字母大寫:${data?upper_case}
<#assign floatData = 12.34>
數值取整數:${floatData?int}
獲取集合的長度:${users?size}
時間格式化:${dateTime?string("yyyy-MM-dd")}
空判斷和對象集合:
<#if users??>
<#list users as user >
${user.id} - ${user.name}
</#list>
<#else>
${user!"變量爲空則給一個默認值"}
</#if>
Map集合:
<#assign mapData={"name":"程序員", "salary":15000}>
直接通過Key獲取 Value值:${mapData["name"]}
通過Key遍歷Map:
<#list mapData?keys as key>
Key: ${key} - Value: ${mapData[key]}
</#list>
通過Value遍歷Map:
<#list mapData?values as value>
Value: ${value}
</#list>
List集合:
<#assign listData=["ITDragon", "blog", "is", "cool"]>
<#list listData as value>${value} </#list>
include指令:
引入其他文件:<#include "otherFreeMarker.ftl" />
macro宏指令:
<#macro mo>
定義無參數的宏macro--${name}
</#macro>
使用宏macro: <@mo />
<#macro moArgs a b c>
定義帶參數的宏macro-- ${a+b+c}
</#macro>
使用帶參數的宏macro: <@moArgs a=1 b=2 c=3 />
命名空間:
<#import "otherFreeMarker.ftl" as otherFtl>
${otherFtl.otherName}
<@otherFtl.addMethod a=10 b=20 />
<#assign otherName="修改otherFreeMarker.ftl中的otherName變量值"/>
${otherFtl.otherName}
<#assign otherName="修改otherFreeMarker.ftl中的otherName變量值" in otherFtl />
${otherFtl.otherName}
其他FreeMarker文件
<#macro addMethod a b >
result : ${a + b}
</#macro>
<#assign otherName="另外一個FreeMarker的變量">
FreeMarkerDemo.java 核心方法
package com.freemark.demo;
import java.util.List;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class FreeMarkerDemo {
private static final String TEMPLATE_PATH = "src/main/java/com/freemark/demo/templates";
public static void main(String[] args) {
// step1 創建freeMarker配置實例
Configuration configuration = new Configuration();
Writer out = null;
try {
// step2 獲取模版路徑
configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
// step3 創建數據模型
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("name", "itdragon博客");
dataMap.put("dateTime", new Date());
List<User> users = new ArrayList<User>();
users.add(new User(1, "ITDragon 博客"));
users.add(new User(2, "歡迎"));
users.add(new User(3, "You!"));
dataMap.put("users", users);
// step4 加載模版文件
Template template = configuration.getTemplate("stringFreeMarker.ftl");
// step5 生成數據
out = new OutputStreamWriter(System.out);
// step6 輸出文件
template.process(dataMap, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != out) {
out.flush();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
User.java 爲了測試 FreeMarker的集合對象
package com.freemark.demo;
public class User {
private Integer id;
private String name;
public User() {
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
最後的打印結果
字符串輸出:
Hello itdragon博客 ! / Hello itdragon博客 !
特殊字符完成輸出(http:\www.baidu.com)
字符串截取 :
通過下標直接獲取下標對應的字母: d
起點下標..結尾下標截取字符串:itdrag
算數運算:
"+" : 15
"-" : 5
"*" : 50
"/" : 2
"%" : 0
比較運算符:
"*" : 50
內建函數:
第一個字母大寫:Abcd1234
所有字母小寫:abcd1234
所有字母大寫:ABCD1234
數值取整數:12
獲取集合的長度:3
時間格式化:2017-10-29
空判斷和對象集合:
1 - ITDragon 博客
2 - 歡迎
3 - You!
Map集合:
直接通過Key獲取 Value值:程序員
通過Key遍歷Map:
Key: name - Value: 程序員
Key: salary - Value: 15,000
通過Value遍歷Map:
Value: 程序員
Value: 15,000
List集合:
ITDragon blog is cool
include指令:
其他FreeMarker文件
macro宏指令:
使用宏macro: 定義無參數的宏macro--itdragon博客
使用帶參數的宏macro: 定義帶參數的宏macro-- 6
命名空間:
另外一個FreeMarker的變量
result : 30
另外一個FreeMarker的變量
修改otherFreeMarker.ftl中的otherName變量值
語法詳解
數據類型
和java不同,FreeMarker不需要定義變量的類型,直接賦值即可。
字符串: value = "xxxx" 。如果有特殊字符 string = r"xxxx" 。單引號和雙引號是一樣的。
數值:value = 1.2。數值可以直接等於,但是不能用科學計數法。
布爾值:true or false。
List集合:list = [1,2,3] ; list=[1..100] 表示 1 到 100 的集合,反之亦然。
Map集合:map = {"key" : "value" , "key2" : "value2"},key 必須是字符串哦!
實體類:和EL表達式差不多,直接點出來。
字符串操作
字符串連接:可以直接嵌套${"hello , ${name}"} ; 也可以用加號${"hello , " + name}
字符串截取:string[index]。index 可以是一個值,也可以是形如 0..2 表示下標從0開始,到下標爲2結束。一共是三個數。
比較運算符
== (等於),!= (不等於),gt(大於),gte(大於或者等於),lt(小於),lte(小於或者等於)。不建議用 >,< 可能會報錯!
一般和 if 配合使用
內建函數
FreeMarker 提供了一些內建函數來轉換輸出,其結構:變量?內建函數,這樣就可以通過內建函數來轉換輸出變量。
html: 對字符串進行HTML編碼;
cap_first: 使字符串第一個字母大寫;
lower_case: 將字符串轉成小寫;
upper_case: 將字符串轉成大寫;
size: 獲得集合中元素的個數;
int: 取得數字的整數部分。
變量空判斷
! 指定缺失變量的默認值;一般配置變量輸出使用
?? 判斷變量是否存在。一般配合if使用 <#if value??></#if>
字符串的比較
<#if target??>
xxxx
</#if>
<#if str == "success">
xxx
</#if>
<#if str !== "error">
xxx
</#if>
<sep></sep>標籤的使用
當您必須在每個項之間顯示某項時(但不是在第一項之前或最後一項之後),則使用SEP
標籤的使用僅從2.3.23版本開始支持
示例:
<#list users as user>
<div>
${user}<#sep>, </#sep>
</div>
</#list>
官方demo點擊打開鏈接
宏指令
可以理解爲java的封裝方法,供其他地方使用。宏指令也稱爲自定義指令,macro指令
語法很簡單:<#macro val > 聲明macro </#macro>; 使用macro <@val />
命名空間
可以理解爲java的import語句,爲避免變量重複。一個重要的規則就是:路徑不應該包含大寫字母,使用下劃線_分隔詞語,myName --> my_name
語法很簡單:<#import "xxx.ftl" as val>
其他沒有說明的語法是因爲和java一樣,沒什麼特別之處。所以沒有列出來。
4 Freemarker Web
這裏是和SpringMVC整合的,SpringMVC的配置就不多說了,筆者也寫過相關的文章,同時也會提供源碼
導入相關的jar pom.xml
<!-- freeMarker start -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
</dependencies>
<!-- freeMarker end -->
springmvc的配置文件:
<!-- 整合Freemarker -->
<!-- 放在InternalResourceViewResolver的前面,優先找freemarker -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/views/templates"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
<property name="contentType" value="text/html; charset=UTF-8"/>
</bean>
Controller 層
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloFreeMarkerController {
@RequestMapping("/helloFreeMarker")
public String helloFreeMarker(Model model) {
model.addAttribute("name","ITDragon博客");
return "helloFreeMarker";
}
}
最後是Freemarker文件
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FreeMarker Web</title>
</head>
<body>
<h1>Hello ${name} !</h1>
</body>
</html>