学习Java模版引擎FreeMarker截至到现在20个小时,记录一下整个学习过程,发现学习中的问题,同时留下对FreeMarker最初时的认知,待假以时日项目组的数据和视图层分离使用FreeMarker的时侯不至于因为时间长了不知从何开始,又要重新走一步Hello FreeMarker的过程,又能够温故知新发现更多,更奇妙的东西。
1.百度百科:FreeMarker http://baike.baidu.com/link?url=204dZtLs4TQhVPp2V_gFfJrv9EzewLu3R4AXHOWIhr9CLxbgnxu0AewyWDmoxWhqGtNH0Dk9PlF-Wpd-rLPpwa
很牛,很强大,能做表现出,也能当工具使,Java语言编写的模版引擎且对Web容器无与依赖性。
2.找一篇博文看看Iteye 曾Java著名社区
http://relive123-yahoo-com-cn.iteye.com/blog/818013
基本了解FreeMarker基本写法,功能特性,怎么弄个Hello FreeMarker出来
3.出自何门何派,官方网站走一圈
http://freemarker.org/index.html
惊喜,有部分中文文档,窃喜,英文文档也很清晰可读。
4.尝试我的Hello FreeMarker
新建一个web工程,将freemarker.jar放置lib(classpath)目录
配置web.xml文件,配置方式和普通的Servlet配置相同
<servlet> <servlet-name>freemarker</servlet-name> <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class> <init-param> <param-name>TemplatePath</param-name> <param-value>/</param-value> </init-param> <init-param> <param-name>NoCache</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>ContentType</param-name> <param-value>text/html</param-value> </init-param> <init-param> <param-name>template_update_delay</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>locale</param-name> <param-value>zh_CN</param-value> </init-param> <init-param> <param-name>default_encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>output_encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>date_format</param-name> <param-value>yyyy-MM-dd</param-value> </init-param> <init-param> <param-name>time_format</param-name> <param-value>HH:mm:ss</param-value> </init-param> <init-param> <param-name>datetime_format</param-name> <param-value>yyyy-MM-dd HH:mm:ss</param-value> </init-param> </servlet>
注意:初始化的参数很多可以根据需要配置,或者在使用的时候在进行设置,在FreeMarker的帮助文档中写的很清楚。
创建一个test1.html模版内容如下:
<div><#assign v="hello freemarker"> ${v}</div>
部署web工程打开test1.html
OK,模版就是这么搞定,关于更多的指令等信息有第二步的博文,也有第三步的官方清晰可读的文档。
下面是在探索中的一些总结:
FreeMarker数据模型+模版==输入内容,可产生友好的表现
数据模型有简单数据类型,Sequence类型(Java的List,Array),Hasher类型(Map, Bean等),总体概况数据模型是一棵树,保证数据以树的形式组织,从而就有个root的概念
实际使用过程中遇到的问题有很好的页面异常信息显示,并仔细阅读文档都可以解决,注意留心每一个条目说明后的Note信息
特性丰富:内置的特性strings,numbers,booleans,dates等;指令特性声明,导入,包含,循环,判断,分支,功能函数,表达式等高频率使用
最后一条,学习一个没有接触过的东西,还是从Hello XX开始是一个良好的起端,另外与其在网上找各种帖子,代码段学习不如试试这三步,末了看看官方文档初学遇到的问题基本都有清晰的说明并且能够发现更多的东西。
问题:自定义方法模型
解决:官方文档中有TemplateMethodModel接口配合源代码模仿一个判断字符串A是否包含字符串B的方法
源码:
接口TemplateMethodModel继承TemplateModel接口;
接口TemplateMethodModelEx继承了TemplateMethodModel接口;
TemplateMethodModelEx接口的实现中有一个类是:SimpleMethodModel看看他的源码就豁然开朗知道如何去实现我们自己的SimpleMethodIsContainsModel类。
类:
public final class SimpleMethodModel extends SimpleMemberModel implements TemplateMethodModelEx, TemplateSequenceModel
核心实现方法:
public Object exec(List arguments)
自己实现:
package com.broncho.fm; import java.util.List; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateModelException; @SuppressWarnings("deprecation") public class SimpleMethodIsContainsModel implements TemplateMethodModel { @Override public Object exec(List arguments) throws TemplateModelException { if (arguments.size() != 2) { throw new TemplateModelException( "template model arguments is wrong !"); } return ((String) arguments.get(0)).contains((CharSequence) arguments .get(1)); } }
用法测试:
编写一个servlet和一个模版
1.Servlet实现
package com.broncho.fm; import java.io.IOException; 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.Template; import freemarker.template.TemplateException; public class TestMethodServlet extends HttpServlet { private static final long serialVersionUID = -8862621014491094117L; private Template template; public TestMethodServlet() { super(); } public void destroy() { super.destroy(); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); Map<String, SimpleMethodIsContainsModel> root = new HashMap<String, SimpleMethodIsContainsModel>(); root.put("iscontains", new SimpleMethodIsContainsModel()); try { template.process(root, response.getWriter()); } catch (TemplateException e) { e.printStackTrace(); } } public void init() throws ServletException { try { template = FreeMarkerTemplateFactory.getConfiguration( this.getServletContext(), "/").getTemplate("block2.ftl"); } catch (IOException e) { e.printStackTrace(); } } }
这里servlet依赖一个工具助手类
package com.broncho.fm; import javax.servlet.ServletContext; import freemarker.template.Configuration; /** * Template Configuration * */ public class FreeMarkerTemplateFactory { public static Configuration cfg; public static void init() { if (cfg == null) { cfg = new Configuration(); } } public static Configuration getConfiguration(ServletContext servletContext, String path) { init(); if (path == null) { path = "/"; } cfg.setServletContextForTemplateLoading(servletContext, path); return cfg; } }
2.模版
<div> <#assign arg1="tomcat" arg2="cat"> ${arg1} is contains ${arg2} <br/> ${iscontains(arg1, arg2)} </div>
说明:root很重要,创建的SimpleMethodIsContainsModel对象要作为方法使用,而在模版在的方法名就是root这个hasher的key值。
3.部署运行
运行之后报一大堆错误,摘取前部分重点信息,可以看出模版中的部分信息输出,计算后的结果没有输出。
上面这段异常提示信息的信息量足够大,这也是个人感觉FreeMarker很牛的一点。
分析:
isContains方法的返回值是boolean类型,FreeMarker template不具备boolean自动转string;
不能转还不能说FreeMarker template能力不行,接下来他给的解释说 boolean_format设置为true,false,恰好这是他默认的计算语言格式,这么一说就不能怪他了;
还没完,他给了两个处理建议,一个是解决当前问题,另一个是解决此类转换的方法,更人性化的是他还给了如何写的例子,如:${myboolean?string('yes','no');
至此,还有惊喜的是FreeMarker Template异常提示的位置相当精确,而且还具备从哪里开始错就在哪那里开始报的优秀品质。
修改后的模版信息:
<div> <#assign arg1="tomcat" arg2="cat"> ${arg1} is contains ${arg2} <br/> ${iscontains(arg1, arg2)?string("true","false")} </div>
末尾:实际上官方的帮助文档这一点写的很清楚,唯一要做的是习惯读英文资料。
本文出自 “野马红尘” 博客,谢绝转载!