FreeMarker使用教程


做者:永恆の_☆ 地址:http://blog.csdn.net/chenghui0317/article/details/7832474
1、Freemarker的介紹

    Freemarker 是一款模板引擎,是一種基於模版生成靜態文件的通用 工具,它是爲java程序員提供的一個開發包,或者說是一個類庫,它不是面向最終用戶的,而是爲程序員提供了一款能夠嵌入他們開發產品的應用程序。

    Freemarker 是使用純java編寫的,爲了提升頁面的訪問速度,須要把頁面靜態化, 那麼Freemarker就是被用來生成html頁面。

    到目前爲止,Freemarker使用愈來愈普遍,不光光只是它強大的生成技術,並且它可以與spring進行很好的集成。

    如今開始一層層揭開它的神祕面紗。。


2、Freemarker的準備條件

    freemarker.2.3.16.jar   下載地址:http://download.csdn.net/detail/ch656409110/4494067 (這個jar包其實在struts2裏面)


3、Freemarker生成靜態頁面的原理

    Freemarker 生成靜態頁面,首先須要使用本身定義的模板頁面,這個模板頁面能夠是最最普通的html,也能夠是嵌套freemarker中的 取值表達式, 標籤或者自定義標籤等等,而後後臺讀取這個模板頁面,解析其中的標籤完成相對應的操做, 而後採用鍵值對的方式傳遞參數替換模板中的的取值表達式,作完以後 根據配置的路徑生成一個新的html頁面, 以達到靜態化訪問的目的。


4、Freemarker提供的標籤

Freemarker提供了不少有用 經常使用的標籤,Freemarker標籤都是<#標籤名稱>這樣子命名的,${value} 表示輸出變量名的內容 ,具體以下:

一、list:該標籤主要是進行迭代服務器端傳遞過來的List集合,好比:
[html] view plaincopyprint?

    <#list nameList as names>   
      ${names}  
    </#list> 

name是list循環的時候取的一個循環變量,freemarker在解析list標籤的時候,等價於:

[java] view plaincopyprint?

    for (String names : nameList) { 
        System.out.println(names); 
    } 

二、if:    該標籤主要是作if判斷用的,好比:

[html] view plaincopyprint?

    <#if (names=="陳靖仇")> 
     他的武器是: 十五~~ 
    </#if> 

這個是條件判斷標籤,要注意的是條件等式必須用括號括起來, 等價於:

[java] view plaincopyprint?

    if(names.equals("陳靖仇")){ 
        System.out.println("他的武器是: 十五~~"); 
    } 


三、include:該標籤用於導入文件用的。

[html] view plaincopyprint?

    <#include "include.html"/> 

這個導入標籤很是好用,特別是頁面的重用。

另外在靜態文件中可使用${} 獲取值,取值方式和el表達式同樣,很是方便。

下面舉個例子(static.html):

[html] view plaincopyprint?

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
    <html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title>Insert title here</title> 
    </head> 
    <body> 
     
    描述:${description} 
    <br/> 
    集合大小:${nameList?size} 
    <br/> 
    迭代list集合: 
    <br/> 
    <#list nameList as names> 
    這是第${names_index+1}我的,叫作:<label style="color:red">${names}</label> 
    if判斷: 
    <br/> 
    <#if (names=="陳靖仇")> 
     他的武器是: 十五~~ 
    <#elseif (names=="宇文拓")>       <#--注意這裏沒有返回而是在最後面-->  
     他的武器是: 軒轅劍~· 
    <#else> 
    她的絕招是:蠱毒~~ 
    </#if> 
    <br/> 
    </#list> 
    迭代map集合: 
    <br/> 
    <#list weaponMap?keys as key> 
    key--->${key}<br/> 
    value----->${weaponMap[key]!("null")} 
    <#--  
    fremarker 不支持null, 能夠用! 來代替爲空的值。 
    其實也能夠給一個默認值   
    value-----${weaponMap[key]?default("null")} 
    還能夠 在輸出前判斷是否爲null 
    <#if weaponMap[key]??></#if>均可以 
    --> 
     
    <br/> 
    </#list> 
    include導入文件: 
    <br/> 
    <#include "include.html"/> 
     
    </body> 
    </html> 

實際代碼:

[java] view plaincopyprint?

    package com.chenghui.test; 
     
    import java.io.File; 
    import java.io.FileOutputStream; 
    import java.io.IOException; 
    import java.io.OutputStreamWriter; 
    import java.io.Writer; 
    import java.util.ArrayList; 
    import java.util.HashMap; 
    import java.util.List; 
    import java.util.Map; 
     
    import freemarker.template.Configuration; 
    import freemarker.template.DefaultObjectWrapper; 
    import freemarker.template.Template; 
    import freemarker.template.TemplateException; 
     
    public class CreateHtml { 
        public static void main(String[] args) { 
            try { 
                //建立一個合適的Configration對象 
                Configuration configuration = new Configuration(); 
                configuration.setDirectoryForTemplateLoading(new File("D:\\project\\webProject\\WebContent\\WEB-INF\\template")); 
                configuration.setObjectWrapper(new DefaultObjectWrapper()); 
                configuration.setDefaultEncoding("UTF-8");   //這個必定要設置,否則在生成的頁面中 會亂碼 
                //獲取或建立一個模版。 
                Template template = configuration.getTemplate("static.html"); 
                Map<String, Object> paramMap = new HashMap<String, Object>(); 
                paramMap.put("description", "我正在學習使用Freemarker生成靜態文件!"); 
                 
                List<String> nameList = new ArrayList<String>(); 
                nameList.add("陳靖仇"); 
                nameList.add("玉兒"); 
                nameList.add("宇文拓"); 
                paramMap.put("nameList", nameList); 
                 
                Map<String, Object> weaponMap = new HashMap<String, Object>(); 
                weaponMap.put("first", "軒轅劍"); 
                weaponMap.put("second", "崆峒印"); 
                weaponMap.put("third", "女媧石"); 
                weaponMap.put("fourth", "神農鼎"); 
                weaponMap.put("fifth", "伏羲琴"); 
                weaponMap.put("sixth", "崑崙鏡"); 
                weaponMap.put("seventh", null); 
                paramMap.put("weaponMap", weaponMap); 
                 
                Writer writer  = new OutputStreamWriter(new FileOutputStream("success.html"),"UTF-8"); 
                template.process(paramMap, writer); 
                 
                System.out.println("恭喜,生成成功~~"); 
            } catch (IOException e) { 
                e.printStackTrace(); 
            } catch (TemplateException e) { 
                e.printStackTrace(); 
            } 
             
        } 
    } 

附:freemarker教程

    這樣子基本上能夠算的上能夠簡單的去作一點簡單的生成了,可是要在實際中去運用,仍是差的很遠的,由於freemarker給的標籤徹底知足不了咱們的須要,這時候就須要自定義標籤來完成咱們的需求了。。
5、Freemarker自定義標籤

Freemarker自定義標籤就是本身寫標籤,而後本身解析,徹底由本身來控制標籤的輸入輸出,極大的爲程序員提供了很大的發揮空間。

基於步驟:

       之前寫標籤須要在<後加# ,可是freemarker要識別自定義標籤須要在後面加上@,而後後面能夠定義一些參數,當程序執行 template.process(paramMap, out);,就會去解析整個頁面的全部的freemarker標籤。

     自定義標籤 須要自定義一個類,而後實現TemplateDirectiveModel,重寫execute方法,完成獲取參數,根據參數do something等等。。

    將自定義標籤與解析類綁定在一塊兒須要在paramMap中放入該解析類的實例,存放的key與自定義標籤一致便可。。

    注意:在自定義標籤中,若是標籤內什麼也沒有,開始標籤和結束標籤絕對不能再同一行,否則會報錯 freemarker.log.JDK14LoggerFactory$JDK14Logger error

  我曾經上當過,這是freemarker 存在的bug。

下面是static.html的例子:

[html] view plaincopyprint?

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
    <html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title>Insert title here</title> 
    </head> 
    <body> 
    <#--自定義變量--> 
    <#assign num='hehe'/> 
    ${num} 
    <br/> 
    自定義標籤 
      <@content name="chenghui" age="120"> 
        ${output} 
        ${append} 
      </@content> 
       
    </body> 
    </html> 


下面是上面的static.html模板的解析類:

[java] view plaincopyprint?

    package com.chenghui.test; 
     
    import static freemarker.template.ObjectWrapper.DEFAULT_WRAPPER; 
     
    import java.io.IOException; 
    import java.io.Writer; 
    import java.util.Map; 
     
     
    import freemarker.core.Environment; 
    import freemarker.template.TemplateDirectiveBody; 
    import freemarker.template.TemplateDirectiveModel; 
    import freemarker.template.TemplateException; 
    import freemarker.template.TemplateModel; 
    import freemarker.template.TemplateModelException; 
    import freemarker.template.TemplateNumberModel; 
    import freemarker.template.TemplateScalarModel; 
     
    /**
     * 自定義標籤解析類
     * @author Administrator
     *
     */ 
    public class ContentDirective implements TemplateDirectiveModel{ 
     
        private static final String PARAM_NAME = "name"; 
        private static final String PARAM_AGE = "age"; 
         
        @Override 
        public void execute(Environment env, Map params,TemplateModel[] loopVars, 
                TemplateDirectiveBody body) throws TemplateException, IOException { 
            if(body==null){ 
                throw new TemplateModelException("null body"); 
            }else{ 
                String name = getString(PARAM_NAME, params); 
                Integer age = getInt(PARAM_AGE, params); 
                //接收到參數以後能夠根據作具體的操做,而後將數據再在頁面中顯示出來。 
                if(name!=null){ 
                    env.setVariable("output", DEFAULT_WRAPPER.wrap("從ContentDirective解析類中得到的參數是:"+name+", ")); 
                } 
                if(age!=null){ 
                    env.setVariable("append", DEFAULT_WRAPPER.wrap("年齡:"+age)); 
                } 
                Writer out = env.getOut(); 
                out.write("從這裏輸出能夠再頁面看到具體的內容,就像document.writer寫入操做同樣。<br/>"); 
                body.render(out); 
                 
                /*
                若是細心的話,會發現頁面上是顯示out.write()輸出的語句,而後再輸出output的內容,
                可見 在body在解析的時候會先把參數放入env中,在頁面遇到對應的而來表單時的纔會去取值
                可是,若是該表單時不存在,就會報錯,  我以爲這裏freemarker沒有作好,解析的時候更加會把錯誤暴露在頁面上。
                能夠這樣子彌補${output!"null"},始終感受沒有el表達式那樣好。
                */ 
            } 
        } 
         
        /**
         * 獲取String類型的參數的值
         * @param paramName
         * @param paramMap
         * @return
         * @throws TemplateModelException
         */ 
        public static String getString(String paramName, Map<String, TemplateModel> paramMap) throws TemplateModelException{ 
            TemplateModel model = paramMap.get(paramName); 
            if(model == null){ 
                return null; 
            } 
            if(model instanceof TemplateScalarModel){ 
                return ((TemplateScalarModel)model).getAsString(); 
            }else if (model instanceof TemplateNumberModel) { 
                return ((TemplateNumberModel)model).getAsNumber().toString(); 
            }else{ 
                throw new TemplateModelException(paramName); 
            } 
        } 
         
        /**
         * 
         * 得到int類型的參數
         * @param paramName
         * @param paramMap
         * @return
         * @throws TemplateModelException 
         */ 
        public static Integer getInt(String paramName, Map<String, TemplateModel> paramMap) throws TemplateModelException{ 
            TemplateModel model = paramMap.get(paramName); 
            if(model==null){ 
                return null; 
            } 
            if(model instanceof TemplateScalarModel){ 
                String str = ((TemplateScalarModel)model).getAsString(); 
                try { 
                    return Integer.valueOf(str); 
                } catch (NumberFormatException e) { 
                    throw new TemplateModelException(paramName); 
                } 
            }else if(model instanceof TemplateNumberModel){ 
                return ((TemplateNumberModel)model).getAsNumber().intValue(); 
            }else{ 
                throw new TemplateModelException(paramName); 
            } 
        } 
    } 

而後再前面的實際代碼中加上:
[java] view plaincopyprint?

    //自定義標籤解析 
    paramMap.put("content", new ContentDirective()); 

這樣子基本上可使用,freemarker完成自定義標籤了,解決一寫簡單的業務邏輯, 可是在實際的項目中不可能這樣子去作,由於尚未和spring進行集成使用,每次都須要在解析的時候把解析類的實例放進去。。                    html

相關文章
相關標籤/搜索