学习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配置相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
<
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模版内容如下:
1
|
<
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类。
类:
1
2
3
4
|
public
final
class
SimpleMethodModel
extends
SimpleMemberModel
implements
TemplateMethodModelEx,
TemplateSequenceModel
|
核心实现方法:
1
|
public
Object exec(List arguments)
|
自己实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
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依赖一个工具助手类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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.模版
1
2
3
4
5
6
|
<
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异常提示的位置相当精确,而且还具备从哪里开始错就在哪那里开始报的优秀品质。
修改后的模版信息:
1
2
3
4
5
6
|
<
div
>
<#assign arg1="tomcat" arg2="cat">
${arg1} is contains ${arg2}
<
br
/>
${iscontains(arg1, arg2)?string("true","false")}
</
div
>
|
末尾:实际上官方的帮助文档这一点写的很清楚,唯一要做的是习惯读英文资料。
本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1332579,如需转载请自行联系原作者