扩展在任何时候都是必要的,前面讲过在FreeMarker做扩展,用的是宏处理,这里使用java代码做扩展。
Java程序员可以使用TemplateDirectiveModel接口在Java代码中实现自定义指令。
先把上章代码模拟实践下:现在要求在html文件中输出”你好,Freemarker!“
package com.vs.freemarker; import java.io.IOException; import java.io.Writer; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; 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.Template; import freemarker.template.TemplateException; public class ActionServletFM extends HttpServlet { private Configuration cfg; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //创建数据模型 Map<String,String> map=new HashMap<String,String>(); map.put("msg", "hello,FreeMarker!"); Template t=this.cfg.getTemplate("free.html");//得到模板,从设置的目录中查找模板 Writer out = response.getWriter(); try { t.process(map, out); //t为模板,加入数据模型root ,合并数据模型+模板: } catch (TemplateException e) { throw new ServletException( "Error while processing template", e); } } public void init() throws ServletException { this.cfg=new Configuration(); // cfg.setSharedVariable("upper", new UpperDirective()); this.cfg.setServletContextForTemplateLoading(getServletContext(), null);//设置模板路径:此种方式是设置为应用程序根目录下: } }
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${msg}
</body>
</html>
好了,接着讲扩展。自定义标签
1. 使用TemplateDirectiveModel
package com.vs.freemarker;
import java.io.IOException;
import java.util.Map;
import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
public class UpperDirective implements TemplateDirectiveModel {
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException {
/**
* 下面方法基本固定
*/
if (!params.isEmpty()) {
throw new TemplateModelException(
"This directive doesn't allow parameters.");
}
if (loopVars.length != 0) {
throw new TemplateModelException(
"This directive doesn't allow loop variables.");
}
if (body != null) {
body.render(new UpperCaseFilterWriter(env.getOut())); //需要实现的方法体
} else {
throw new RuntimeException("missing body");
}
}
}
上面的代码基本固定,变化主要在于需要实现的方法不一样。
import java.io.IOException;
import java.io.Writer;
public class UpperCaseFilterWriter extends Writer {
private Writer out;
public UpperCaseFilterWriter(Writer _out){
this.out=_out;
}
@Override
public void close() throws IOException {
out.close();
}
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
char[] transformedCbuf = new char[len];
for (int i = 0; i < len; i++) {
transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);
}
out.write(transformedCbuf);
}
}
当然上面的方法网上实在是多,应该基本都围绕着Freemarker的官方例子做的吧。
好了,既然方法实现了,然后注册它。在最上面的ActionServletFM【Servlet类】注册该方法。
public void init() throws ServletException {
this.cfg=new Configuration();
cfg.setSharedVariable("upper", new UpperDirective()); //注册方法
this.cfg.setServletContextForTemplateLoading(getServletContext(), null);//设置模板路径:此种方式是设置为应用程序根目录下:
}
好了,现在就是看结果的时候了。下面一起把用宏的写法放下面。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${msg}
<@upper>Welcome to http://www.oschina.net</@upper><!--用java实现的自定义指令-->
<#assign upp = "com.vs.freemarker.UpperDirective"?new()> <!-- 用这种方式也可以创建嘛 -->
<@upp>
<#list ["oracle","SQL Server","DB2"] as db>
${db}
</#list><br/>
</@upp>
</body>
</html>
代码说话,网上到处可见的代码,不做多的解释。