FreeMarker 自定义模版文件加载器
模版文件加载器用来告诉 FreeMarker 引擎到什么地方去加载模版文件。 FreeMarker 自带了三种文件加载器,分别是:文件目录加载器、类路径加载器以及 Web 上下文加载器。当在 Web 环境中使用 FreemarkerServlet 来加载模版文件时,默认使用第三种加载器,并通过 Servlet 的配置 TemplatePath 来指定模版文件所存放的路径,该路径是相对于 Web 的根目录的。
在某种情况下,我们可能会希望把模版文件的源码进行加密处理,例如我们使用 DES 加密方式将模版源文件加密后进行存储,然后我们通过自行实现一个加密的模版文件加载器来读取这些模版文件,解密后交给 FreeMarker 引擎解释执行并得到执行的结果。 FreeMarker 为模版文件加载器定义了一个统一的接口 —— TemplateLoader ,该接口有以下四个方法:closeTemplateSource 关闭模版资源
findTemplateSource 根据名称返回指定的模版资源
getLastModified 返回模版资源最后一次修改的时间
getReader 返回读取模版资源的 Reader
为了简单起见,我们可以在 FreeMarker 自带的加载器上进行扩展,重写 getReader 方法对读取到的模版文件内容进行解密后生成一个新的 Reader 实例并返回(详细过程不再叙述)。
FreeMarker 自带的几个 TemplateLoader 分别是:
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。
源代码:
2、struts.xml
源代码
模版文件加载器用来告诉 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>