继续在Open-open.com逛,看到排名很靠前的一个java taglib项目。因为一直觉得taglib没产生什么有意义的东西,只不过是规范化了很多,看到排名靠前的taglib挺奇怪,就仔细看了看。
发现原来是个表格组件。前一段时间看讲座对Dorado那个界面比较感兴趣,使用了Ajax和组件化的表格技术,数据对象通过Javascript+dom解析,类似IBM的SDO概念。觉得如果能够真正的弄好,这种可服用的表格组件非常有前途。
当然SDO已经在IBM的JSF组件里面应用了,帮定起来真的很方便,而且客户端的体验也非常的好。可是JSF的最大缺陷就是手动开发太麻烦了,培植非常繁琐,所以就依赖于IDE来自动实现JSF组件的配置,所以JSF的IDE都是由背景的,代表某一方利益的东西。比如SUN的NetBeans、IBM的那个什么5.1,而我喜欢用的Eclipse下面还没有很好的辅助IDE,Nitrox新版支持JSF了,可是没有破解,正版又老贵,Myeclipse 4.0支持了JSF,但看了看很初级。
撤了老远,其实我想说我对这种实现的很Fine的组建太感兴趣了。
马上去它的网站看:
http://displaytag.sourceforge.net/
首页的几张截图非常吸引人,它产生的表格看起来非常的棒!
听Open-open介绍,这个东西和Struts结合很顺畅,我们的项目用的Struts+Hibernate+Spring,马上加进来试验。
遇上问题,session里面的变量访问不到,很奇怪,这个东西难住我了,找不到问题。看了它们的PDF,本以为会比网站讲得详细,后来发现不过就是网站的内容的PDF版本,基本也就是个入门指南,可怜。
网站总提到TestList这个东西用来测试,找不到这个类,下了它的源码,发现在源码的例子中有,产生测试List。
然后就用这个TestList测试了一下分页、排序、导出其它格式这些功能,发现非常吸引人,一下子觉得发现了宝藏!
然后不管是否能在我们项目应用,开始修改css,把它弄到我们的项目里,然后问项目其它同仁为何不能显示出我们的List。
修改Css很顺手,嘿嘿,目前我改css已经驾轻就熟了,很快修改出自己的漂亮的样式,很满足,哈哈。
而后,我的朋友郑浩发现了不能显示的问题,因为我们用了Hibernate,它返回的List是离线的,访问的时候需要用iterator访问,可能Displaytag的机制问题,所以无法访问到。
解决方法是每次new一个新的List,复制一遍再过去。我考!这是多大的浪费呀。把它放到DAO是不可以的,这样DAO移植后绝对是浪费,把它放到bussiness层也不合理,放到MVC的Controller还差不多,但是也感觉浪费的利害。
这时有些失望,所以去Google下,发现无数人说到这个问题。尤其是使用它的自动分页,每次如果取出所有的,然后复制List,估计性能会彻底完蛋!
所以,有些失望,Displaytag最有用的功能aotopagging不能使用了……
为了做试验,进一步修改,不用它的自动分页,但是修改了MVC,让它可以访问到一个复制过的List,来显示数据。配合刚才修改的css,效果和以前的Struts tag不相上下。(靠,完全是写css的缘故,这个有什么兴奋的!)
它的表格的控制都是英文的,应该可以中文。然后google,和问郑浩,他们用了如下代码:
<display:table name="list" width="100%" cellspacing="0" cellpadding="0" class="liebiao" pagesize="15">
<display:setProperty name="basic.msg.empty_list">没有可显示的内容</display:setProperty>
<display:setProperty name="paging.banner.placement">bottom</display:setProperty>
<display:setProperty name="paging.banner.full"><span class="liebiao">[<a href="{1}">首页</a>/ <a href="{2}">前一页</a>] {0} [ <a href="{3}">下一页</a>/ <a href="{4}">最后一页 </a>]</span></display:setProperty>
<display:setProperty name="paging.banner.first"><span class="liebiao">[首页/前一页] {0} [<a href="{3}">下一页</a> <a href="{4}">最后一页</a>]</span></display:setProperty>
<display:setProperty name="paging.banner.all_items_found"><span class="liebiao"><br><br>本栏目共{0}条,已经全部列出</span></display:setProperty>
<display:setProperty name="paging.banner.onepage"><span></span></display:setProperty>
<display:setProperty name="paging.banner.one_item_found"><span class="liebiao">共一条,已经列出</span></display:setProperty>
<display:setProperty name="paging.banner.last"><span class="liebiao">[<a href="{1}">首页</a>/ <a href="{2}">前一页</a>] {0} [下一页/最后一页]</span></display:setProperty>
<display:setProperty name="paging.banner.some_items_found"><span class="liebiao"><br><br>共有{0}条,显示第{2}至{3}条<br></span></display:setProperty>
<display:setProperty name="paging.banner.page.link"><a href="{1}" title="前往第{0}页">{0}</a></display:setProperty>
<display:column property="title" title="标 题" href="detail.jsp" paramId="id" paramProperty="id" maxLength="10" width="40%" align="left"/>
<display:column property="reportername" title="作者" maxLength="4" width="20%" align="left"/>
<display:column property="readtimes" title="阅读次数" align="left"/>
<display:column property="newsdate" decorator="cn.gov.bjmy.util.SimpleDateDecorator" title="新闻日期" width="16%" align="left"/>
</display:table>
哈哈,这么用真的够累。不过想了想,在中小项目,利用它的自动分页还是不错的。
不过每次设置太麻烦了,查阅了下,1.0版本支持用displaytag.properties配置了,这样可以全局使用。
displaytag.properties的内容如下:(那些中文我已经转码了,使用了PropertiesEditor,这个Eclipse插件自动转码非常方便!)
basic.msg.empty_list=\u6ca1\u6709\u53ef\u663e\u793a\u7684\u5185\u5bb9
paging.banner.placement=bottom
paging.banner.full=<div class="pagelinks">[<a href="{1}">\u9996\u9875</a>/ <a href="{2}">\u524d\u4e00\u9875</a>] {0} [ <a href="{3}">\u4e0b\u4e00\u9875</a>/ <a href="{4}">\u6700\u540e\u4e00\u9875 </a>]</div>
paging.banner.first=<div class="pagelinks">[\u9996\u9875/\u524d\u4e00\u9875] {0} [<a href="{3}">\u4e0b\u4e00\u9875</a> <a href="{4}">\u6700\u540e\u4e00\u9875</a>]</div>
paging.banner.all_items_found=<div class="pagebanner"><br><br>\u672c\u680f\u76ee\u5171{0}\u6761\uff0c\u5df2\u7ecf\u5168\u90e8\u5217\
u51fa</div>
paging.banner.onepage=<div class="pagelinks">{0}</div>
paging.banner.one_item_found=<div class="pagebanner">\u5171\u4e00\u6761\uff0c\u5df2\u7ecf\u5217\u51fa</div>
paging.banner.last=<div class="pagelinks">[<a href="{1}">\u9996\u9875</a>/ <a href="{2}">\u524d\u4e00\u9875</a>] {0} [\u4e0b\u4e00\u9875/\u6700\u540e\u4e00\u9875]</div>
paging.banner.some_items_found=<div class="pagebanner">\u5171\u6709{0}\u6761\uff0c\u663e\u793a\u7b2c{2}\u81f3{3}\u6761</div>
paging.banner.page.link=<a href="{1}" title="\u524d\u5f80\u7b2c{0}\u9875">{0}</a>
export.banner=<div class="exportlinks">\u5bfc\u51fa\u4e3a\u5176\u5b83\u683c\u5f0f: {0}</div>
export.pdf=true
export.csv=false
把这个文件放到Web项目的Class目录下就可以了。解决了问题了。
用了下导出功能,支持pdf需要把itext-0.99.jar拷贝到WEB-INF/lib下面,然后再propertis配置中“export.pdf=true”。
不过发现这个用不了,后来发现原来是无法解析Struts的.do,我都是映射到/去的,而我的jsp文件不在/下面,所以路径出了问题。查了下,用这个参数指定,“requestURI="getUser.do?back=yes"”就可以了,里面是我用的struts的action的路径。
修改以后,自动排序和导出都正常了,不过发现导出csv的时候后缀是.do,靠,禁用它。(BTW:集图的时候天天CSV,哈哈,别的地方估计不常用吧。怀念COC,现在BOB却很少去)
下面是全部可运行的一个代码:
<display:table name="tablecontent" class="<%=lClass%>" defaultsort="1"
defaultorder="descending" export="true"
requestURI="getUser.do?back=yes">
<display:column property="userId" title="ID" sortable="true"
headerClass="sortable" />
<display:column property="name" sortable="true" headerClass="sortable" />
<display:column property="realname" />
<display:column property="password" sortable="true"
headerClass="sortable" />
<display:column property="addr" title="Comments" />
</display:table>
对比一下Struts下面的相同代码:
<logic:iterate name="users" id="userlist" scope="session">
<tr>
<td class="frh"><bean:write name="userlist" property="userId"
filter="true" /></td>
<td class="fr"><bean:write name="userlist" property="name"
filter="true" /></td>
<td class="frh"><bean:write name="userlist" property="realname"
filter="true" /></td>
<td class="fr"><bean:write name="userlist" property="password"
filter="true" /></td>
<td class="frh"><bean:write name="userlist" property="addr"
filter="true" /></td>
<td class="fr"><bean:write name="userlist" property="level"
filter="true" /></td>
<td class="frh"><a
href="/viewUser.do?id=<bean:write name="userlist" property="userId" filter="true" />">详细</a></td>
<td class="fr"><a
href="/deleteUser.do?id=<bean:write name="userlist" property="userId" filter="true" />">删除</a></td>
</tr>
</logic:iterate>
对比下发现差距也不大吧,不过,有了自动排序和导出,看起来满酷的。
酷是一方面,失望才是更大的。简单尝试和运行还是留下了遗憾,记录一下,如果有心人看到可以去改进:
1、不能读取Hibernate返回的离线List,这是个硬伤!不知道是不是我的使用问题。但是如果必须是在线的,那么内存浪费巨大。大的项目就用不了了!
2、所有的自动排序,自动分页,导出都是通过传统的服务器回写来实现的,看似酷,但是实际上过于简单。在Ajax很火爆的现在,技术有点落后了。
3、没有结合SDO这样的数据模型。其实和Ajax那个问题一样,没有SDO就不是组件模型。而只是一个傻瓜化的封装而已。
4、网站的文档不够详细,也不严谨,我觉得开源没有好的文档就永远火不起来。
5、我很欣赏所有的样式都依赖于css,而且东西很好扩展。但是居然网上有人抨击这种方式。我想反问那些满脑子程序的人,那些看不起美工的程序员,你们懂得程序是艺术么?你不懂css、不懂web standards、不懂xhtml、不懂xml,还有什么可混的么?
6、另一个问题。分页实现的太不优雅了。也许是taglib的限制。一次读取所有的数据,并且要求是在线的,仅仅为了分页,这太恐怖了。Hibernate不能这么用,JDBC也不能这么用!好的分页封装看来还要用别的。如此一看,这里面除了CSS提供看起来很好的表格外就只有导出功能了。
7、而悲观的是,导出功能除了花哨以外没有别的作用了,而导出功能还有更好的选择吧。
所以,一句话说。上手还算容易,可是深入难,看不到好的手册。Sample写的不错,可是缺乏与其它框架结合的例子,比如Hibernate、Struts。好多人说它好用,但是估计都是从简单的角度考虑的,性能的考虑是个问题。配置看起来还算容易,可是配置却没有文档来介绍,只能摸着石头过河。
所以,仅仅是结绳记事。小项目可以用。大项目用它没法发挥它带来的优势,只能使用可怜的一点点功能(我的例子只用了自动排序和导出)。不过开源项目,谁知道,没准麻雀变凤凰了呢。毕竟它的思想是对的,提供可用的Web组件(它声称要实现table、Tree等等),我也想找到一个这样的组件,那样就真的可以轻松些工作了!
等待那一天!
十分赞同。
失望!