模板引擎
- 模板引擎的目標是“數據+模板=結果”
- 模板引擎將數據與展現有效的“解耦”
- 前端只需要知道怎麼編寫前端,後端只需關注後端,用模板引擎把兩者整合
主流的模板引擎
-
Java Server Page(jsp)
-
FreeMarker
-
Beetl
(擁有前兩者的優點,但是作爲新的模板,還未普及,前面兩個更常用)
FreeMarker和JSP
- 只要不是開發淘寶、京東這樣的大型軟件,兩者的執行效率相差不多
FreeMarker
FreeMarker
是免費開源的模板引擎技術- 要下載
jar
包 FreeMarker
腳本爲FreeMarker Template Language
FreeMarker
提供了大量內建函數來簡化開發(這就是很多人放棄jsp用FreeMarker的原因)
在java類中創建數據
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;
public class FreeMarkerSample {
public static void main(String[] args) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
//1、加載模板
//創建核心配置對象
/*傳入版本號,每個版本的FreeMarker語法和解析方式都略有不同*/
Configuration config=new Configuration(Configuration.VERSION_2_3_28);
//設置加載的目錄
/*第一個參數表示在這個類所在包中加載指定的ftl文件,第二個參數是空字符串,表示當前包 */
config.setClassForTemplateLoading(FreeMarkerSample.class, "");
//得到模板對象
/*因爲上面指定了只在特定的類所在的包中加載ftl文件,所以這裏直接寫文件名就行*/
Template t=config.getTemplate("sample1.ftl");
//2、創建數據
/*FreeMarker中的數據就是一個Map對象5*/
Map<String,Object> data=new HashMap<>();
data.put("site", "百度");
data.put("url","http://www.baidu.com");
data.put("date",Calendar.getInstance().getTime());
data.put("number",456654456.7889);
Map<String,Object> info=new HashMap<>();
info.put("cpu","i5");
Computer computer=new Computer("123","張三",7896.5f,info);
data.put("compu",computer);
//3、產生輸出(可以向控制檯、網絡中的流、文件中輸出)
/*第一個參數是數據,第二個參數是向哪裏輸出*/
t.process(data,new OutputStreamWriter(System.out));//像控制檯中輸出
}
}
語法(均在.ftl文件中進行演示)
-
FTL
取值只有輸出纔要加
${}
<#-- FreeMarker取值 -->
${site}-${url}
<#-- 默認值,如果取的值不存在則會輸出後面的默認值 -->
${author!"不存在的屬性"}
<#-- 日期格式化輸出,如果不格式化會拋異常(日期不能轉成字符串) -->
${date?string("yyyy年MM月dd日 HH:mm:ss")}
<#-- 數字格式化輸出,如果不指定格式,默認按國際化貨幣格式輸出(三位一逗號,保留三位小數),四捨五入 -->
${number?string("0,0000.00")}
<#-- ${屬性名.對象中的屬性名} -->
ID:${compu.id}
User:${compu.user}
Price:${compu.price?string("0.00")}
<#-- 對象中集合屬性中值的獲取 -->
<#-- 數據中(Map中)保存對象的輸出方式跟EL表達式差不多 -->
<#-- ${屬性名.對象中集合屬性的屬性名["集合中的key"]}通過key獲取value -->
CPU:${compu.info["cpu"]}
Memory:${compu.info["memory"]!"memory not exist"}
關於多級訪問的變量,比如 animals.python.price
, 書寫代碼:animals.python.price!0
當且僅當 animals.python
永遠存在, 而僅僅最後一個子變量 price
可能不存在時是正確的 (這種情況下我們假設價格是 0
)。 如果 animals
或 python
不存在, 那麼模板處理過程將會以"未定義的變量"錯誤而停止。爲了防止這種情況的發生, 可以如下這樣來編寫代碼 (animals.python.price)!0
。 這種情況就是說 animals
或 python
不存在時, 表達式的結果是 0
。對於 ??
也是同樣用來的處理這種邏輯的; 將 animals.python.price??
對比(animals.python.price)??
來看。
if
分支判斷
<#-- if分支 -->
<#-- FreeMarker中字符串的判斷直接用== -->
<#if compu.id=="123">
這是重要設配
<#elseif compu.id=="456">
正常保護等級
<#else>
接近廢棄的電腦
</#if>
<#-- ??用於判斷該對象是否爲空,不爲空返回true,爲空返回false -->
<#if compu.user??>
這臺電腦有人使用
<#else>
這臺電腦無人使用
</#if>
switch
分支判斷
<#--在FreeMarker中,空格也會輸出,所以這裏爲了格式不留空格書寫-->
<#-- switch分支 -->
<#switch compu.id>
<#case "123">
這臺電腦很重要
<#break>
<#case "456">
正常保護等級
<#break>
<#default>
廢棄電腦
</#switch>
list
迭代列表
<#-- 迭代List,並把值賦給arr,其中arr_index代表迭代的索引,從0開始 -->
<#list arrayList as arr>
${arr_index+1}-${arr}
</#list>
list
迭代Map
<#-- 把Map中的key取出來(linkedMap?keys)當作一個List,再迭代 -->
<#list linkedMap?keys as key>
${key}-${linkedMap[key]}
</#list>
FreeMarker內建函數
${words?replace("blood","*****")}
將字符串words
中的blood
子字符串替換爲*****
輸出
用?string
實現三目運算符的操作${(words?index_of("blood")!=-1)?String("包含敏感詞彙",words)}
${name?cap_first}
${brand?upper_case}
${brand?length}
${words?replace("blood" , "*****")}
${words?index_of("blood")}
<#-- 利用?string實現三目運算符的操作 -->
${(words?index_of("blood") != -1)?string("包含敏感詞彙","不包含敏感詞彙")}
${n?round}
${n?floor}
${n?ceiling}
公司共有${computers?size}臺電腦
第一臺:${computers?first.model}
最後一臺:${computers?last.model}
排序
<#-- 默認按照指定屬性升序排列,可以調用reverse函數進行降序排列 -->
<#list computers?sort_by("price")?reverse as c>
${c.sn}-${c.price}
</#list>
Freemarker與Servlet的整合
ftl文件怎麼在web項目中被執行
Freemarker
對整合servlet
有良好的支持,在FreeMarker.jar
包中存在支持Servlet的類
- 需要使用這個Servlet類就必須在
web.xml
中註冊
<!--註冊FreemarkerServlet -->
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<!--配置初始化參數,通知FreemarkerServlet在哪個目錄下尋找.ftl文件(設置加載的目錄) -->
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/WEB-INF/ftl</param-value>
</init-param>
</servlet>
<!--FreemarkerServlet映射地址,只要瀏覽器地址欄中的URL是以.ftl結尾,就會被FreemarkerServlet處理 -->
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
</servlet-mapping>
在配置初始化參數的時候,我們指定了FreemarkerServlet
在哪個目錄下尋找.ftl
腳本文件,所以我們的.ftl
文件都要保存在這個文件中
通過在瀏覽器中輸入http://localhost:8080/項目名/test.ftl
就可以輸出這個腳本文件中的內容(並不要把完整的路徑輸入到瀏覽器中)
**執行原理:**當瀏覽器地址欄中輸入的URL以.ftl
結尾,就會被FreemarkerServlet
類處理,FreemarkerServlet
類就會到web.xml
配置文件指定的加載目錄中(就是init-param
中配置的templatePath
參數值)尋找和URL中同名的.ftl
腳本文件進行輸出(上面是在/WEB-INF/ftl
文件下尋找test.ftl
文件進行輸出)
Freemarker與servlet
ListServlet.java
@WebServlet("/list")
public class ListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ListServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Employee> employees=new ArrayList<>();
employees.add(new Employee(7823l,"李四","技術部","java高級工程師",15000f));
employees.add(new Employee(7824l,"張丹","市場部","客戶經理",14500f));
request.setAttribute("employees", employees);
//FreemarkerServlet會檢測到是以.ftl結尾的URL,進行處理(尋找對應的.ftl腳本文件進行輸出)
request.getRequestDispatcher("/employee.ftl").forward(request, response);
}
}
employee.ftl
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>序號</th>
<th>員工編號</th>
<th>姓名</th>
<th>部門</th>
<th>職務</th>
<th>工資</th>
<th> </th>
</tr>
</thead>
<tbody>
<#--按員工編號升序輸出-->
<#list employees?sort_by("empno") as emp>
<tr>
<td>${emp_index+1}</td>
<#-- 整數輸出 -->
<td>${emp.empno?string("0")}</td>
<td>${emp.name}</td>
<td>${emp.department}</td>
<td>${emp.job}</td>
<td style="color: red;font-weight: bold">¥${emp.salary?string("0,000.00")}</td>
</tr>
</#list>
</tbody>
</table>
.ftl
腳本文件中的數據是從哪裏獲取的?
從當前頁面的請求、會話、ServletContext
中自動依次查找,如果都沒查找到,又沒有做其他處理,則會拋出異常。