利用freemarker标签生成静态页面时,有时候没有静态页面处理 需要自定义标签来简化处理;
实现步骤:
主要通过实现TemplateDirectiveModel接口来实现
repeat.ftl标签代码:
-----------要求后台返回一个字符串-----------
<@repeat1 returnType='string'>
${returnParam}
</@repeat1>
-----------要求后台返回一个指定大小的的list-----------
<@repeat1 returnType='list' size=5>
<#list returnParam as param>
===${param.name}
</#list>
</@repeat1>
-----------要求后台返回一个map-----------
<@repeat1 returnType='map' >
${returnParam.name}
</@repeat1>
java代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import freemarker.core.Environment;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
/**
* FreeMarker 自定义标签实现重复输出内容体。
*/
public class RepeatDirective implements TemplateDirectiveModel {
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException {
env.setAutoFlush(true);
String returnType=""+params.get("returnType");
if(returnType.equals("string")){
env.setVariable("returnParam", new DefaultObjectWrapper().wrap("自定义标签返回的字符串 "));
}
if(returnType.equals("list")){
Map<String, TemplateModel> paramWrap = new HashMap<String, TemplateModel>(params);
List list = new ArrayList();
int size =Integer.parseInt(params.get("size")+"");
for(int i=0;i<size;i++){
Map root = new HashMap();
root.put("name", "return list item "+i);
list.add(root);
}
env.setVariable("returnParam", new DefaultObjectWrapper().wrap(list));
}
if(returnType.equals("map")){
Map root = new HashMap();
root.put("name", "return map===========");
env.setVariable("returnParam", new DefaultObjectWrapper().wrap(root));
}
body.render(env.getOut());
}
/**
* @param templatePath 模板文件存放目录
* @param htmlPath html路径
* @param templateName 模板文件名称
* @param root 数据模型根对象
* @param templateEncoding 模板文件的编码方式
*
*/
public static void processTemplate(String templatePath,String htmlPath, String templateName, String templateEncoding, Map<?,?> root){
try {
Configuration config=new Configuration();
// 设置要解析的模板所在的目录,并加载模板文件
File file=new File(templatePath);
// 设置包装器,并将对象包装为数据模型
config.setDirectoryForTemplateLoading(file);
// 获取模板,并设置编码方式,这个编码必须要与页面中的编码格式一致
config.setObjectWrapper(new DefaultObjectWrapper());
// 合并数据模型与模板
Template template=config.getTemplate(templateName,templateEncoding);
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(htmlPath),"UTF-8");
template.process(root, out);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}catch (TemplateException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Map<String,Object> root=new HashMap<String, Object>();
root.put("repeat1", new RepeatDirective()); // repeat1为页面上需要访问的标签名称
processTemplate(
"WebRoot\\WEB-INF\\template",//模板路径
"WebRoot\\WEB-INF\\template\\repeat.html",//html保存路径
"repeat.ftl", "gb2312",
root);
}
}
执行main方法后输出的html内容为:
-----------要求后台返回一个字符串-----------
自定义标签返回的字符串
-----------要求后台返回一个指定大小的的list-----------
===return list item 0
===return list item 1
===return list item 2
===return list item 3
===return list item 4
-----------要求后台返回一个map-----------
return map===========
-----------要求后台返回一个map-----------
return map===========
以上只是一个简单的demo;
在实际生成环境使用中,一般将freemarker与spring结合使用,可以将自定义的标签交给spring容器进行管理,然后在业务层注入自定义的标签;
spring配置文件参考配置方法:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- freemarker标签配置 --><!-- 此处配置freemarker标签 -->
<!-- 文章列表标签 -->
<bean id="data_list"
class="自定义标签的包名">
</bean>
<!-- freemarker 控制上下文方式加载。(可自定义编写) -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="contentType" value="text/html;charset=UTF-8" />
</bean>
<!-- freemarker 配置文件加载 -->
<bean id="freeMarkerConfigurer"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="freemarkerVariables">
<map>
<!-- 此处映射freemarker标签 与配置标签时的id名相同 -->
<entry key="data_list" value-ref="data_list" />
</map>
</property>
<property name="templateLoaderPath" value="" />
<!-- freemarker格式管理 -->
<property name="freemarkerSettings">
<props>
<prop key="tag_syntax">auto_detect</prop><!-- 此处配置模版里标签的显示方式为<>或[] ,注意模版内标签显示方式不可混用。此处设置为自动匹配 -->
<prop key="template_update_delay">5</prop>
<prop key="defaultEncoding">UTF-8</prop>
<prop key="url_escaping_charset">UTF-8</prop>
<prop key="locale">zh_CN</prop>
<prop key="boolean_format">true,false</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="time_format">HH:mm:ss</prop>
<prop key="number_format">0.######</prop>
<prop key="whitespace_stripping">true</prop>
</props>
</property>
</bean>
</beans>
spring service代码结构:
@Component("staticPageSvc")
public class StaticPageSvcImpl implements StaticPageSvc, InitializingBean {
@Resource(name = "freeMarkerConfigurer") //与spring配置文件中beanId保持一致
private FreeMarkerConfigurer freeMarkerConfigurer;
public Configuration getFreeMarkerConfigurer() {
return freeMarkerConfigurer.getConfiguration();
}
public void setFreeMarkerConfigurer(FreeMarkerConfigurer freeMarkerConfigurer) {
this.freeMarkerConfigurer = freeMarkerConfigurer;
}
public void html(String tempPath, String htmlPath, Map<String, Object> data) throws IOException, TemplateException {
long time = System.currentTimeMillis();
if (data == null)
data = new HashMap<String, Object>();
File f = new File(htmlPath.substring(0, htmlPath.lastIndexOf("/") + 1));
if (!f.exists())
f.mkdirs();
f = new File(htmlPath);
if (!f.exists())
f.createNewFile();
Writer out = null;
try {
out = new OutputStreamWriter(new FileOutputStream(f), "UTF-8");
Template template = getFreeMarkerConfigurer().getTemplate(tempPath);//spring 注入getFreeMarkerConfigurer()
template.process(data, out);
} finally {
if (out != null) {
out.flush();
out.close();
}
}
}
}
ftl中使用方法:
<@data_list param1="xx" param2="8">
<#list tag_list as article>
</#list>
</@data_list>
data_list为spring文件中配置 ,tag_list 为标签返回的参数,相当于demo中的returnParam