利用FreeMarker模板引擎创建动态调用
作者:胡志刚 发布时间:June 29, 2009 分类:所谓技术
比较郁闷,这个标题不知道怎么起,以前写过关于FreeMarker生成静态页面,还有调用的一些文章,但这次好像又稍微有点不同,说不同呢,又差不多,搞得都不知道自己在捣鼓些什么了,- -#,暂且就这样说好了。
自己平常在用到一些程序的时候,比较喜欢关注程序的模板方面,现在大部分的程序都能实现了灵活的模板设计,将模板和程序分离开来,一直都在想在java下的解决方案,每次想到这块,脑子里第一就会想到FreeMarker,总感觉能实现,但自己又说不清楚怎么来实现,正好,今天有点时间,抽空自己写了个简单的实力来实现这个功能,就类似于说,我可以自己定义一个方法的调用,然后决定我调用多少条文章,是否调用置顶了之类的东东,唉,说是不好说,直接来代码好了。
主要的文件一共有三个,一个Servlet,一个标记解析的类,一个模板文件,代码如下:
package com.fm.study;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/**
* 访问的Servlet
*
* @author HuZhigang
* @date 2009-6-29
*/
public class FMDemo extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 8295505224176026191L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@SuppressWarnings("unchecked")
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
Configuration cfg = new Configuration();
//设置FreeMarker需要读取的模板路径
String path = this.getServletContext().getRealPath("/")
+ "WEB-INF\\ftl";
cfg.setDirectoryForTemplateLoading(new File(path));
cfg.setObjectWrapper(new DefaultObjectWrapper());
cfg.setDefaultEncoding("utf-8");
//模板文件名
Template temp = cfg.getTemplate("index.ftl");
Map root = new HashMap();
//写入一个变量,key对应value
root.put("user", "Hmilyld");
//创建一个回调变量
root.put("call", new CallFactory());
temp.process(root, out);
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
代码很简单,主要就是读取模板文件然后输出就可以了,主要注意的是这句:root.put("call", new CallFactory());我们定义一个变量,然后可以调用我们的方法。
下面是我们需要操作的方法,CallFactory需要实现TemplateMethodModel这个接口,然后我们所传入的参数以List的形式传入,这个时候,可以读取List来获取我们相关传入的参数,代码如下:
package com.fm.study;
import java.util.ArrayList;
import java.util.List;
import com.fm.bean.ArticleBean;
import com.fm.bean.ProductBean;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModelException;
/**
* 解析标记的相关方法
*
* @author HuZhigang
* @date 2009-6-29
*/
public class CallFactory implements TemplateMethodModel {
@SuppressWarnings("unchecked")
public Object exec(List arg0) throws TemplateModelException {
String type = (String) arg0.get(0);
if ("article".equals(type)) {
// 如果标记为article,则调用文章的相关方法
return article(arg0);
} else if ("product".equals(type)) {
// 如果标记为product,则调用商品的相关方法
return product(arg0);
} else {
throw new TemplateModelException("Error!");
}
}
/**
* 调用文章的相关方法
*
* @return
* @author HuZhigang
*/
private Object article(List<String> param) {
List<ArticleBean> list = new ArrayList<ArticleBean>();
int count = Integer.parseInt(param.get(1));
for (int i = 0; i < count; i++) {
ArticleBean ab = new ArticleBean();
ab.setTitle("这里是标题--" + i);
ab.setContent("这里是内容--" + i);
ab.setAuthor("这里是作者" + i);
ab.setUrl("这里是url--" + i);
list.add(ab);
}
return list;
}
/**
* 调用产品的相关方法
*
* @return
* @author HuZhigang
*/
private Object product(List<String> param) {
List<ProductBean> list = new ArrayList<ProductBean>();
int count = Integer.parseInt(param.get(1));
for (int i = 0; i < count; i++) {
ProductBean pb = new ProductBean();
pb.setName("这里是商品标题--" + i);
pb.setMeta("这里是商品简介--" + i);
pb.setPrice((float) Math.random());
list.add(pb);
}
return list;
}
}
OK,主要实现的功能都在这个里面了,当然,你可以完全拆分开,不同的类来实现不同的方法,具体应用就看自己怎么用了,可以按照传入的条件判断需要调用多少内容,是否固定,是否推荐等等内容
下面就是我们最后的模板文件,很简单
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>FreeMarker标记解析演示</title>
<style>
body{
font-size:12px;
}
#article,#product{
float:left;
margin:5px;
}
td{
width:120px;
}
</style>
</head>
<body>
<h1>Hello,${user}</h1>
<div id="main">
<div id="article">
<h2>文章列表演示</h2>
<#--根据创建的call,调用我们需要调用的方法,我们这里传入article类型,然后数量为20条 -->
<#assign article = call("article",20,"true")>
<table border="1">
<tr>
<td>标题</td>
<td>内容</td>
<td>作者</td>
<td>url</td>
</tr>
<#--循环打印出所有内容-->
<#list article as art>
<tr>
<td>${art.title}</td>
<td>${art.content}</td>
<td>${art.author}</td>
<td>${art.url}</td>
</tr>
</#list>
</table>
</div>
<div id="product">
<h2>商品列表演示</h2>
<#--调用类型为商品,20条数据-->
<#assign product = call("product",20)>
<table border="1">
<tr>
<td>名称</td>
<td>价格</td>
<td>简介</td>
</tr>
<#list product as pro>
<tr>
<td>${pro.name}</td>
<td>${pro.price}</td>
<td>${pro.meta}</td>
</tr>
</#list>
</table>
</div>
</div>
</body>
</html>
OK,搞定,主要就是这么多的操作,还有其他的一些高级的应用,根据实际情况来自己修改,偶也没深入的去研究,只是翻开FreeMarker的API来看了下,大致的一个功能实现,嘿,对后面自己需要写的一个东西是用处大大啊。