freemarker从试用到放弃

    前两天,周末在家无事,想起以前的项目是基于struts2开发的,而在struts2中又大量运用了freemarker,所以就想也去试用下freemarker。

    在struts2的guide文章中,说明了为什么要使用freemarker的理由。

The framework utilizes FreeMarker because the engine includes strong error reporting, 
built-in internationalization and powerful macro libraries.

    即准确的错误地方以及内置的国际化处理以及强大的自定义宏处理。

 

    从网上下载了一个简单的freemarker中文文档以及官方的手册,简单看了下,然后开始处理中。首先根据每个界面都需要引用相同的html代码以及结尾处理。写了一个简单的html.ftl信息,然后在每个界面都包含进来。如下

<#assign g=JspTaglibs["/WEB-INF/gtip.tld"] />
<#macro body title="标题">
<!DOCTYPE html>
<html>
<head>
	<title>${title}</title>
	<#include "header.ftl" />
</head>
<body>
	<#nested />
</body>
</html>
</#macro>

 

就是简单的一个宏处理,以及声明包含一个自定义的jsptag信息,将title信息写进head中的title标签,然后引用公共使用的header.ftl(即相应的js以及css),最后在body标签中调用相应的代码信息。

 

    这样在其他界面中,只需要<#include "html.ftl"/>,然后再调用<@body>这个宏即可。

    接下来,就是将每个界面的jsp修改为ftl了,除了在struts.xml中修改每个result的type为freemarker之外,还需要将每个jsp重新copy成ftl,然后进行改造。

    对于每个ftl,首先将原来的<s:调用方式,修改为freemarker的<@s.的调用方式。如<s:iterator>修改为<@s.iterator>这样的形式。我使用了一个正则表达式来进行字符替换,使用 (?<=<(?:/)?)(\w): 来匹配相应的标签,并使用 @\$1. 来替换掉。上面的字符会匹配<s:iterator中的<s:,也可以匹配</s:iterator中的</s:,直接将其替换即可。

    其次,将其中的<s:property value="XX"/>的形式(经第一步之后,变成了<@s.property value="XX"/>了),修改为${xxx}的形式。因为使用freemarker嘛,所以要修改过来。这里也使用了一个正则表达式进行替换,由 <@s.property value="#?([\w\.]+)"/> 替换为 \\$\{\$1} ,即可实现这个修改。

 

    接下来修改其他标签。

    将<@s.iteraotr标签,修改为<#list >的形式;

    将<@s.if></@s.if><@s.else>修改为<#if><#else>的形式。

   

    花了近一天的时候,终于将相应的界面修改了。最后重新启动工程进行运行,结果出问题了。问题有以下几个:

1,如果ftl界面不能完全解析,则相应的界面将完全以源代码的形式显示在界面上。

    这个问题,由于比如其中的某些type没有正则的匹配相应的ftl,而后台以dispatcher的形式返回回来之后,界面就直接将整个ftl文件完整地显示在界面上了。这样对于文件的保护,而且对于开发来说都是不大好的。

2,首页以及登陆界面的问题。

    如果将首页以及相应的前台界面修改为ftl的形式,那么在进行访问的时候就必须以非ftl的形式进行访问了,如通过xxx.do的形式进行访问,这样还必须给相应的ftl文件追加相应的action匹配。如原来的login.jsp,现在就必须以login.do进行访问,而且需要给这个映射追加一个action映射信息。如果前面界面有很多,面分散在不同的目录中,那么就需要有多个不同的匹配来进行, 这样无凝增加了无谓的工作。

    当然有一个解决办法就是保存前台界面为jsp不变,但又出现新的问题,即当前台界面引用其他界面时,又会出现相同的问题。即其他界面均修改为ftl,而ftl中有相应的freemarker解析标签。如login.jsp引用error.ftl时,将会出现error.ftl中的信息不能被解析的问题。当然可以保存error.ftl和error.jsp同时存在。但这样就失去了freemarker的作用了。

3,最重要的,toString问题和null问题以及map问题

    3.1 freemarker没有对list以及map结构有一个很好的toString支持,即直接调用${x}时,如果x为一个list时,将直接显示一个List@xxx的形式。这样,就要求我们必须为其编写一个sequenceToString的macro,而且还需要在调用中对x的类型进行判断(通过?_isXXX的形式),再进行相应的处理。

    3.2 map问题,即freemarker中不能支持非string的key值,这样在进行一些复杂迭代时就需要作一些其他的转换,如将一个map拆分为两个或多个map。

    3.3 三元运算符的支持。由于缺少三元运行符,所以在一些复杂的判断中,为一个变量进行赋值时,就需要用多个<#if和<#else>进行处理。本来只需要一个三元运算就能解决的问题,由用<#if和<#else>就需要写很长一段代码。

    3.4 null问题。这是最重要的,freemarker没有一个默认的null处理,甚至也不接受一个null值。如x=null(X变量是存在的),打印${x}时,将直接报一个错误,而不是打印类似的""值或null等。这样在进行很多显示中,都需要在相应的变量后面加一个!,如${x!}这样的形式,很是麻烦。

    在<#list中,也需要使用类似<#if (list)!>的形式。而由于缺少对null的支持,需要写一个类似x==null这样的判断时,就需要写成!(x??)的特殊形式,而且到处均需要写成(XX?method?method)?或!的形式以进行null的处理。

 

    导致我决定不使用freemarker的原因,就是现阶段没有发现其比struts2标签更方便。尤其在对于null的处理上,ognl标签相比来说更容易使用,当碰到出现类似nullPointer的时候,struts2标签在处理时将直接采用默认的处理方式,如显示为""(对于iterator或if时,将直接返回false,以结束迭代或判断)。这样就不需要开发人员再去进行无谓的null处理,而这个结果正是在web开发中所需要的。

 

    网上再找了下,freemarker对于一些模板文件的生成还是很有用的,比如在项目中,就依照struts2的标签开发用freemarker生成一个tree树,再采用标签进行封装来调用。如下所示:

<#-- 写一个子集列表 -->
<#macro writeOne node expand>
<li>
	<input type="checkbox" name="${node.nameParam}" value="${node.id}"
			<#if node.checked>
		   checked="checked"
			</#if>
			/>
	<span>${node.name}</span>
	<#if expand && (node.childList?? && node.childList?size > 0)>
	<ul>
		<@write nodeList=node.childList expand=expand/>
	</ul>
	</#if>
</li>
</#macro>

<#-- 写上级结点 -->
<#macro write nodeList expand>
<#list nodeList as node>
<@writeOne node=node expand=expand/>
</#list>
</#macro>
		<@write nodeList=parameters.nodeList expand=parameters.expand/>

 

   最后决定,在进行jsp开发上,还是使用jsp+struts2标签进行开发,而使用一些模板文件生成的时候,或许可以考虑一下freemarker。至少对于我来说,freemarker已经没有那么大的吸引力了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值