一:创建一个Configuration实例

// Where the application is initialized; in general you do this ONLY ONCE in the application life-cycle!
    Configuration cfg = new Configuration();
    cfg.setSomeSetting(...);
    cfg.setOtherSetting(...);
    ...
    
    // Later, whenever the application needs a template (so you may do this a lot, and from multiple threads):
    Template myTemplate = cfg.getTemplate("myTemplate.html");
    myTemplate.process(dataModel, out);

上面是摘自freemarker.template.Configuration类的注释,介绍了这个类的使用方法。(本文的freemarker版本为2.3.20)

这个类是进入freemarker API的主要入口类

从注释可以知道这个类主要的功能:封装了freemarker的配置设置,并可用于模板加载,提供缓存(模板)的能力。

下面从代码里来一一看看是如何实现这些功能的。

public Configuration() {
        cache = new TemplateCache();
        cache.setConfiguration(this);
        cache.setDelay(5000);
        loadBuiltInSharedVariables();
    }

可以看到,默认构造器中涉及一个缓存行为,原来上面说的缓存能力是这个TemplateCache类里面写的。先不用管TemplateCache类的细节。先将这个构造流程看一遍。

cache.setConfiguration(this);

这一句将当前这个Configuration类通过setConfiguration方法注入到TemplateCache这个类中。

loadBuiltInSharedVariables方法加载了freemarker内建的配置,包括xml、html格式的文件的特殊字符转义工具类,还有空格等的处理。

构造了Configuration的实例后,要做一些自定义配置,比如设置编码

configuration.setDefaultEncoding("utf-8");

二:创建数据模型

这里是按照官方文档顺序,非入门可跳过直接看三:获取模板。

可以使用java.lang和java.util包中的类,还可以自定义Java Bean类型来构建数据对象。

 

三:获取模板

设置模板加载路径

configuration.setClassForTemplateLoading(this.getClass(), "/template");

上面的方法是告诉freemarker模板加载路径,具体看代码:

public void setClassForTemplateLoading(Class clazz, String pathPrefix) {
        setTemplateLoader(new ClassTemplateLoader(clazz, pathPrefix));
    }

ClassTemplateLoader用于保存传入的参数,构造一个可以确定模板路径的对象,freemarker可以调用其父类URLTemplateLoader的findTemplateSource方法获取模板在运行时的路径。

Freemarker将模板加载的工作抽象为TemplateLoader接口:

freemarker script给model赋值_freemarker

ClassTemplateLoader是TemplateLoader接口的一种实现,查找模板路径的方法一般定义在findTemplateSource方法中,然而ClassTemplateLoader本身没有复写findTemplateSource方法,而是使用父类URLTemplateLoader的findTemplateSource方法,URLTemplateLoader的findTemplateSource方法又需要使用到ClassTemplateLoader的getURL方法,所以ClassTemplateLoader的模板加载是在getURL方法中完成的。

URLTemplateLoader的findTemplateSource方法:

public Object findTemplateSource(String name)
    throws
    	IOException
    {
        URL url = getURL(name);
        return url == null ? null : new URLTemplateSource(url);
    }

使用构造ClassTemplateLoader传入的path和后面将要设置的模板名称name拼接出模板全路径,然后使用类加载器的方式去查找资源,返回运行时的统一资源定位符URL。

protected URL getURL(String name)
    {
        String fullPath = path + name;
        
        // Block java.net.URLClassLoader exploits:
        if (path.equals("/") && !isSchemeless(fullPath)) {
            return null;
        }
        
        return loaderClass.getResource(fullPath);
    }

通过查看setTemplateLoader方法的注释文档可以知道,官方支持三种方式设置模板加载路径:

1. 通过 Class.getResource():setClassForTemplateLoading(Class, String);

2. 通过设置具体目录:setDirectoryForTemplateLoading(File)

3. 如果是web项目,也可以通过ServletContext加载:setServletContextForTemplateLoading(Object, String)

 

TemplateLoader接口层次:

freemarker script给model赋值_缓存_02

由上图可知,TemplateLoader还有多种实现,即其他的获取模板路径的方式。后面会再写一篇Spring集成freemarker,是如何加载freemarker模板的。

接着看:

public synchronized void setTemplateLoader(TemplateLoader loader) {
        createTemplateCache(loader, cache.getCacheStorage());
    }

setTemplateLoader中调用createTemplateCache方法,可以想象,这里涉及缓存模板的逻辑了。

cache.getCacheStorage(),返回一个CacheStorage实例,CacheStorage是真正缓存模板的,它有几种实现:

freemarker script给model赋值_java_03