Freemarker源碼解析

FreeMarker 自定義模版文件加載器

       模版文件加載器用來告訴 FreeMarker 引擎到什麼地方去加載模版文件。 FreeMarker 自帶了三種文件加載器,分別是:文件目錄加載器、類路徑加載器以及 Web 上下文加載器。當在 Web 環境中使用 FreemarkerServlet 來加載模版文件時,默認使用第三種加載器,並通過 Servlet 的配置 TemplatePath 來指定模版文件所存放的路徑,該路徑是相對於 Web 的根目錄的。

       在某種情況下,我們可能會希望把模版文件的源碼進行加密處理,例如我們使用 DES 加密方式將模版源文件加密後進行存儲,然後我們通過自行實現一個加密的模版文件加載器來讀取這些模版文件,解密後交給 FreeMarker 引擎解釋執行並得到執行的結果。 FreeMarker 爲模版文件加載器定義了一個統一的接口 —— TemplateLoader ,該接口有以下四個方法:closeTemplateSource 關閉模版資源
findTemplateSource 根據名稱返回指定的模版資源
getLastModified 返回模版資源最後一次修改的時間
getReader 返回讀取模版資源的 Reader

      爲了簡單起見,我們可以在 FreeMarker 自帶的加載器上進行擴展,重寫 getReader 方法對讀取到的模版文件內容進行解密後生成一個新的 Reader 實例並返回(詳細過程不再敘述)。

FreeMarker 自帶的幾個 TemplateLoader 分別是:
ClassTemplateLoader :基於類路徑的模版加載器
FileTemplateLoader :基於文件目錄的模版加載器
MultiTemplateLoader :多種加載器的混合
StringTemplateLoader :基於字符串的模版加載器
URLTemplateLoader :基於 URL 的模版加載器
WebappTemplateLoader :基於 Web 上下文的模版加載器

重載模版加載器後通過下面代碼使之生效:cfg.setTemplateLoader(loader)

FreeMarker 緩存處理

FreeMarker 的緩存處理主要用於模版文件的緩存,一般來講,模版文件改動不會很頻繁,在一個流量非常大的網站中,如果頻繁的讀取模版文件對系統的負擔還是很重的,因此 FreeMarker 通過將模版文件的內容進行緩存,來降低模版文件讀取的頻次,降低系統的負載。

當處理某個模版時,FreeMarker 直接從緩存中返回對應的 Template 對象,並有一個默認的機制來保證該模版對象是跟模版文件同步的。如果使用的時候 FreemarkerServlet 時,有一個配置項 template_update_delay 用來指定更新模版文件的間隔時間,相當於多長時間檢測一下是否有必要重新加載模版文件,0 表示每次都重新加載,否則爲多少毫秒鐘檢測一下模版是否更改。

FreeMarker 定義了一個統一的緩存處理接口 CacheStorage ,默認的實現是 MruCacheStorage 最近最少使用的緩存策略。一般情況下,很少需要對緩存進行擴展處理。您可以通過下面的代碼指定最大緩存的模版數:cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250))

其中第一個參數是最大的強引用對象數,第二個爲最大的弱引用對象數。這兩個值 FreeMarker 默認的是 0 和 Integer.MAX_VALUE,表明模版緩存數是無限的

 

freemarker頁面數據

基本思路爲:利用Struts2對自定義result type的支持,自定義能夠生成靜態頁面的result type,結合模板引擎Freemarker可以實現大批量靜態頁面的生成。
 參看org.apache.struts2.views.freemarker.FreemarkerResult的代碼實現,自定義了自己的生成靜態頁面的result type。

源代碼:
 package com.mobilesoft.esales.webapp.action; 
public class FreemarkerResult extends StrutsResultSupport 
    private static final long serialVersionUID = -3778230771704661631L; 
    protected ActionInvocation invocation;
    protected Configuration configuration;
    protected ObjectWrapper wrapper;
    protected FreemarkerManager freemarkerManager;
    private Writer writer;
    protected String location;
    private String pContentType = “text/html”; 
    protected String fileName; // 要生成的靜態頁面名稱
    protected String filePath; // 要生成的靜態頁面的路徑
    protected String staticTemplate; // 用於生成靜態頁面Freemarker模板的路徑 

    public FreemarkerResult() {
        super();
    } 
    public FreemarkerResult(String location) {
        super(location);
    } 
    @Inject
    public void setFreemarkerManager(FreemarkerManager mgr) {
        this.freemarkerManager = mgr;
    } 
    public void setContentType(String aContentType) {
        pContentType = aContentType;
    } 
    public String getContentType() {
        return pContentType;
    } 
    public void doExecute(String location, ActionInvocation invocation)
            throws IOException, TemplateException {
        this.location = location;
        this.invocation = invocation;
        this.configuration = getConfiguration();
        this.wrapper = getObjectWrapper(); 
        this.fileName = (String) conditionalParse(fileName, invocation);
        this.staticTemplate = (String) conditionalParse(staticTemplate, invocation);
        this.filePath = ((String) conditionalParse(filePath, invocation)) == null ? “”
                : ((String) conditionalParse(filePath, invocation)); 
        if (!location.startsWith(”/”)) {
            ActionContext ctx = invocation.getInvocationContext();
            HttpServletRequest req = (HttpServletRequest) ctx
                    .get(ServletActionContext.HTTP_REQUEST);
            String base = ResourceUtil.getResourceBase(req);
            location = base + “/” + location;
        } 
        //生成html頁面的模板類
        Template template = configuration.getTemplate(location, deduceLocale());
        // 生成靜態頁面的的模板類
        Template staticTemplate = configuration.getTemplate(this.staticTemplate,
                deduceLocale()); 
        TemplateModel model = createModel();
        String path = ServletActionContext.getServletContext().getRealPath(
                filePath)
                + File.separator;
        Writer out = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(path + fileName))); 
        if (preTemplateProcess(template, model)) {
            try {
                staticTemplate.process(model, out);
                template.process(model, getWriter());
            } finally {
                postTemplateProcess(template, model);
                postTemplateProcess(staticTemplate, model);
            }
        }
    } 
    protected Configuration getConfiguration() throws TemplateException {
        return freemarkerManager.getConfiguration(ServletActionContext
                .getServletContext());
    } 
    protected ObjectWrapper getObjectWrapper() {
        return configuration.getObjectWrapper();
    } 
    public void setWriter(Writer writer) {
        this.writer = writer;
    } 
    protected Writer getWriter() throws IOException {
        if (writer != null) {
            return writer;
        }
        return ServletActionContext.getResponse().getWriter();
    } 
    protected TemplateModel createModel() throws TemplateModelException {
        ServletContext servletContext = ServletActionContext
                .getServletContext();
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpServletResponse response = ServletActionContext.getResponse();
        ValueStack stack = ServletActionContext.getContext().getValueStack(); 
        Object action = null;
        if (invocation != null)
            action = invocation.getAction(); // Added for NullPointException
        return freemarkerManager.buildTemplateModel(stack, action,
                servletContext, request, response, wrapper);
    } 
    protected Locale deduceLocale() {
        if (invocation.getAction() instanceof LocaleProvider) {
            return ((LocaleProvider) invocation.getAction()).getLocale();
        } else {
            return configuration.getLocale();
        }
    } 
    protected void postTemplateProcess(Template template, TemplateModel data)
            throws IOException {
    } 
    protected boolean preTemplateProcess(Template template, TemplateModel model)
            throws IOException {
        Object attrContentType = template.getCustomAttribute(”content_type”); 
        if (attrContentType != null) {
            ServletActionContext.getResponse().setContentType(
                    attrContentType.toString());
        } else {
            String contentType = getContentType(); 
            if (contentType == null) {
                contentType = “text/html”;
            } 
            String encoding = template.getEncoding(); 
            if (encoding != null) {
                contentType = contentType + “; charset=” + encoding;
            } 
            ServletActionContext.getResponse().setContentType(contentType);
        } 
        return true;
    } 
    public String getFileName() {
        return fileName;
    } 
    public void setFileName(String fileName) {
        this.fileName = fileName;
    } 
    public String getFilePath() {
        return filePath;
    } 
    public void setFilePath(String filePath) {
        this.filePath = filePath;
    } 
    public String getStaticTemplate() {
        return staticTemplate;
    } 
    public void setStaticTemplate(String staticTemplate) {
        this.staticTemplate = staticTemplate;
    }
}

2、struts.xml
 源代碼
 <action name=”staticViewAction” class=”com.mobilesoft.esales.webapp.action.StaticViewtAction”>
            <result name=”success” type=”staticview”>
                <param name=”location”>test/freemarkertest.ftl</param>
                <param name=”contentType”>text/html</param>
                 <param name=”fileName”>${filename}</param>
                <param name=”staticTemplate”>test/freemarkertest.ftl</param>
                <param name=”filePath”>static</param>
            </result>                    
        </action>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章