1. 程式人生 > >FreeMarker學習總結

FreeMarker學習總結

FreeMarker簡介

在java領域,表現層技術主要有三種:jsp、freemarker、velocity。

jsp是大家最熟悉的技術

優點:
1、功能強大,可以寫java程式碼
2、支援jsp標籤(jsp tag)
3、支援表示式語言(el)
4、官方標準,使用者群廣,豐富的第三方jsp標籤庫
5、效能良好。jsp編譯成class檔案執行,有很好的效能表現
缺點:jsp沒有明顯缺點,由於可以編寫java程式碼,如使用不當容易破壞mvc結構。

velocity是較早出現的用於代替jsp的模板語言

優點:
1、不能編寫java程式碼,可以實現嚴格的mvc分離
2、效能良好,據說比jsp效能還要好些
3、使用表示式語言,據說jsp的表示式語言就是學velocity的
缺點:
1、不是官方標準
2、使用者群體和第三方標籤庫沒有jsp多。
3、對jsp標籤支援不夠好

freemarker

優點:
1、不能編寫java程式碼,可以實現嚴格的mvc分離
2、效能非常不錯
3、對jsp標籤支援良好
4、內建大量常用功能,使用非常方便
5、巨集定義(類似jsp標籤)非常方便
6、使用表示式語言
缺點:
1、不是官方標準
2、使用者群體和第三方標籤庫沒有jsp多
選擇freemarker的原因:
1、效能。velocity應該是最好的,其次是jsp,普通的頁面freemarker效能最差(雖然只是幾毫秒到十幾毫秒的差距)。但是在複雜頁面上(包含大量判斷、日期金額格式化)的頁面上,freemarker的效能比使用tag和el的jsp好。
2、巨集定義比jsp tag方便
3、內建大量常用功能。比如html過濾,日期金額格式化等等,使用非常方便
4、支援jsp標籤
5、可以實現嚴格的mvc分離

FreeMarker是java的免費模板引擎,主要用於MVC中的view層,生成html展示資料給客戶端,可以完全替代jsp。 FreeMarker是一個模板引擎,一個基於模板生成文字輸出的通用工具,使用純Java編寫,模板中沒有業務邏輯,外部java程式通過資料庫操作等生成資料傳入template中, 然後輸出頁面。它能夠生成各種文字:HTML、XML、JSP、RTF、Java原始碼等等,而且不需要Servlet環境,並且可以從任何源載入模板,如本地檔案、資料庫等等。

FreeMarker外掛下載

這裡寫圖片描述

FreeMarker模板檔案詳解

1.註釋

<#--註釋內容--
>

2.文字: 直接輸出的部分,比如HTML標籤及文字內容
3.插值:${ }或#{ }部分,使用資料模型中的資料代替,比如controller中model儲存的資料

避免空值插值
    !: 指定缺失變數的預設值
    ${sss!} <#--沒有定義這個變數,預設值是空字串! -->  
    ${sss!"abc"} <#--沒有定義這個變數,預設值是字串abc! -->  
    ??:判斷變數是否存在
    variable??,如果變數存在,返回true,否則返回false。

插值規則
a) 表示式放置在插值語法${}之中,用於輸出表達式的值。
b) 表示式的值的型別可以是:字串、 數字、布林、日期時間、序列、Hash結構
c) 表示式支援Java中的所有運算子:
     算術運算子:+、-、*、/、%
     比較運算子:==(eq)、!=(ne)、>(gt)、>=(gte)、<(lt)、<=(lte)
     邏輯運算子:&&(and)、||(or)、!(not)
     三目運算子:? :
d) 內建函式:
    Ⅰ) 使用方式:表示式?函式名[(實參)]
    Ⅱ) 字串的常用內建函式: substring(from[, to])、html、length、trim、url 示例:<#setting url_escaping_charset="UTF-8"> 、exp?url[("UTF-8")]
    Ⅲ) 數字的常用內建函式:c、string[(數字模式串)]、
    Ⅳ) 布林的內建函式:string[("男", "女")]
    Ⅴ) 內建的常用日期時間函式:string[("格式模式串")]、datetime、datetime
e) 序列:
在FTL中定義的序列:由方括號包括,各元素用英文逗號分隔如:<#assign seq=["winter", "spring", "summer",  "autumn"]>也可以用數字範圍(遞增、反遞增)定義數字序列: <#assign nums=101..105>  或 <#assign nums=105..101> 在資料模型中可以是List物件、Set物件,序列的常用內建函式:size、sort[("指定欄位作排序依據")]
f) Hash結構: 
在FTL檔案中直接定義時:由大括號包括,由逗號分隔鍵/值列表,鍵和值之間用冒號分隔。鍵必須是字串。如: <#assign scores={"語文":78, "數學":89, "英語":87}> ${scores.語文} 在資料模型中可以是Map物件,Hash結構的內建函式:size、keys、values

4.FTL指令:FreeMarker指令,和HTML標籤類似,名字前加#予以區分,不會輸出。

FTL指令詳解:

assign 指令:用於為該模板頁面建立或替換一個頂層變數。

<#--定義變數-->
<#assign id=1 name="zhangsan" sex="男">
<#--定義陣列-->
<#assign hobbyArr=['籃球','足球','排球']>
<#--定義Map集合-->
<#assign people={"name":"mouse","age":25,"weight":140}>

if else 指令:做if判斷用的。

<#assign age=20>
<#if age gt 60>老年人
<#elseif age gt 40>中年人
<#elseif age gt 20>青年人
<#else> 少年人
</#if>
<#if (age==20)>
我今年20歲
</#if>

list 指令:主要是進行迭代伺服器端傳遞過來的List集合。
item_index:當前變數的索引值
item_has_next:是否存在下一個物件
break:跳出迭代

<#list 1..9 as i>
    ${i}
</#list>
<br/>
<#list hobbyArr as hobby>
    下標:${hobby_index}
    值:${hobby}<br/>
    <#if !hobby_has_next>
        已經是最後一個
        <#break>
    </#if>
 </#list>
 長度:${hobbyArr?size}

<#--迭代Map集合-->
<#assign keys = people?keys>        <#--map的key集合-->
<#list keys as key>
    ${key} = ${h[key]}
</#list>

switch 指令:作用類似於Java的switch語句。

<#assign age=10>
<#switch age>
    <#case 0>0<#break>
    <#case 10>10<#break>
    <#case 20>20<#break>
    <#default>30
</#switch>

include 指令:用於匯入檔案,它可以在模版中插入其他的靜態檔案,或者是freemarker模版。

<#--parse=true 是否作為ftl語法解析,預設是true-->
<#include "inc.ftl" encoding="UTF-8" parse=true>

import 指令:類似於java裡的import,它匯入檔案,然後就可以在當前檔案裡使用被匯入檔案裡的巨集元件。

<#--訪問時使用 inc.-->
<#import "inc.ftl" as inc>
${inc.name}

** noparse 指令:**noparse指令指定FreeMarker不處理該指定裡包含的內容。

<#noparse> 
    <#list hobbyArr as hobby> 
       <tr><td>${hobby.name}<td><td>${hobby.age></td></tr>
    </#list> 
</#noparse>

macro 指令:用於實現自定義指令,通過使用自定義指令,可以將一段模板片段定義成一個使用者指令,類似於java中的方法,定義不會執行,呼叫才會執行,定義引數可以給預設值。

<#--定義-->

<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>

name : 指定的是該自定義指令的名字,使用自定義指令時可以傳入多個引數
paramX : 指定使用自定義指令時報引數,使用該自定義指令時,必須為這些引數傳入值
nested : 輸出使用自定義指令時的中間部分
return : 可用於隨時結束該自定義指令.

<#macro addCalc p1 p2=10>
    <#if p2=0 && p1=0>
        <return>
    </#if>
    輸出結果為:${p1+p2}
</#macro>
<@addCalc p1=100 p2=200/>
<@addCalc p1=10/>

macro包含nested的巨集

<#macro myuser name>
    您的姓名是:${name}<br/>
    <#nested name?length>
</#macro>
<@myuser name='zs';len>名字長度:${len}</@myuser>

setting 指令:用於動態設定freeMarker的執行環境。

<#setting name=value>

name的取值範圍如下:
locale : 該選項指定該模板所用的國家/語言選項
number_format : 指定格式化輸出數字的格式 ,number(數字)、currency(金額)、percent(百分數)三個值。
boolean_format : 指定兩個布林值的語法格式,預設值是true,false
date_format,time_format,datetime_format : 指定格式化輸出日期的格式
time_zone : 設定格式化輸出日期時所使用的時區

<#--setting設定-->
<#setting locale="zh_CN"/>
<#setting number_format="number"/>
<#setting number_format="currency"/>
<#setting number_format="percent"/>
<#setting date_format="yyyy-MM-dd"/>
<#setting time_format="HH:mm:ss"/>
<#setting datetime_format="yyyy-MM-dd HH:mm:ss"/>
<#setting time_zone="zzzz">

<#--string函式格式化-->
<#assign answer=42/>
${answer}
${answer?string}
${answer?string.number}
${answer?string.currency}
${answer?string.percent}
<#--EEEE表示星期,MMMM中文月份,yy年份後二位,a(上、中、下午),zzzz時區-->
${time?string("yyyy-MM-dd HH:mm:ss zzzz")}
${time?string("EEE,MMM d,yy")}
${time?string("EEEE,MMMM dd,yyyy,hh:mm:ss a '('zzz')'")}

Java程式碼讀取ftl模板,輸出頁面

public class FreeMarkerUtil {
    @SuppressWarnings("deprecation")
    public Template getTemplate(String name){
        Template temp = null;
        // 通過Freemarker的Configuration讀取相應的FTL  
        Configuration cfg = new Configuration();
        // 設定去哪裡讀取相應的ftl模板 ,src/template/
        cfg.setClassForTemplateLoading(this.getClass(), "/template");
        try {
            // 在模板檔案目錄中尋找名稱為name的模板檔案  
            temp = cfg.getTemplate(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return temp;
    }
     /** 
     * 控制檯輸出檔案內容 
     * @param name 
     * @param rootMap 
     */  
    public void print(String name,Map<String,Object> rootMap){
        // 通過Template類可以將模板檔案輸出到相應的檔案  
        Template temp = this.getTemplate(name);
        try {
            temp.process(rootMap, new PrintWriter(System.out));
        } catch (TemplateException | IOException e) {
            e.printStackTrace();
        }
    }
    /** 
     * 將替換後的模板內容輸出到檔案 
     * @param name 
     * @param rootMap 
     * @param outFile 
     */  
    public void fprint(String name,Map<String,Object> rootMap,String outFile){
        File file = null;
        try {
            //獲取專案目錄
            file = new DefaultResourceLoader().getResource("").getFile();
            while(true){
                String fileName = file.getName();
                file = file.getParentFile();
                if("target".equals(fileName)||"src".equals(fileName)){
                    break;
                }
            }
            //獲取模板生成檔案位置
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        String viewName = file+"/src/main/webapp/";
        FileWriter out = null;
        try {
            out = new FileWriter(new File(viewName+outFile));
            Template template = this.getTemplate(name);
            template.process(rootMap, out);
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }finally{
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        Map<String,Object> rootMap = new HashMap<>();
        FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
        rootMap.put("time",new Date());
        //freeMarkerUtil.print("inc.ftl", rootMap);
        freeMarkerUtil.fprint("inc.ftl", rootMap, "01.html");
    }
}

與springmvc整合

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <context:component-scan base-package="com.ftl.controller"></context:component-scan>

     <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />  
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />  

    <!-- 配置Freemarker屬性檔案路徑 -->  
    <bean id="freemarkerConfiguration" class="org.springframework.beans.factory.config.PropertiesFactoryBean">  
        <property name="location" value="classpath:freemarker.properties" />  
    </bean>  

    <!-- 配置freeMarker模板載入地址 -->  
    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">  
        <!-- 檢視解析器在/tpl/路徑下掃描檢視檔案 -->  
        <property name="templateLoaderPath" value="/tpl/" />  
        <property name="freemarkerVariables">  
            <map>  
                <entry key="xml_escape" value-ref="fmXmlEscape" />  
            </map>  
        </property>  
        <property name="freemarkerSettings">
            <props>
                <!-- 模板編碼格式 -->
                <prop key="default_encoding">UTF-8</prop>
                <!-- 本地化設定 -->
                <prop key="locale">UTF-8</prop>
                <!-- url轉義編碼 -->
                <prop key="url_escaping_charset">UTF-8</prop>
            </props>
        </property>
    </bean>  
    <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />  

    <!-- 配置freeMarker檢視解析器 -->  
    <bean id="freemakerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">  
        <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />  
        <!-- 掃描路徑內所有以ftl結尾的檔案 -->  
        <property name="viewNames">  
            <array>  
                <value>*.ftl</value>  
            </array>  
        </property>  
        <property name="contentType" value="text/html; charset=UTF-8" />  
        <property name="exposeRequestAttributes" value="true" />  
        <property name="exposeSessionAttributes" value="true" />  
        <property name="exposeSpringMacroHelpers" value="true" />  
        <property name="requestContextAttribute" value="request" />  
        <!-- 給檢視解析器配置優先順序,你可以給之前jsp檢視解析器的值配為2 -->  
        <property name="order" value="1" />  
    </bean>  
</beans>