DisplayTag应用指南

   DisplayTag是一个非常好用的表格显示标签,适合MVC模式,其主页在http://displaytag.sourceforge.net  
一、最简单的情况,未使用<display:column/>标签
   <%request.setAttribute( "test", new ReportList(6) );%>
   <display:table name="test" />
   标签遍历List里的每一个对象,并将对象里的所有属性显示出来。一般用于开发的时候检查对象数据的完整性。
  
二、使用<display:column/>标签的情况
<display:table name="test">
   <display:column property="id" title="ID" />
   <display:column property="name" />
   <display:column property="email" />
   <display:column property="status" />
   <display:column property="description" title="Comments"/>
</display:table>
    property对应List里对象的属性(用getXXX()方法取得),title则对应表格表头里的列名。定义列有两种方式:
    A、<display:column property="email" />
       使用<display:column/>标签里的property属性来定义
    B、<display:column title="email">email@it.com</display:column>
       在<display:column/>标签体里增加内容,可以是常量,也可以用其他标签等等
    两种方式比较,用property属性来定义更加快速和利于排序。
   
三、表格显示样式的定义
   A、在<display:table/>和<display:column/>标签里指定标准的html属性,烦琐
   B、修改样式表
<display:table name="test" class="mars">
   <display:column property="id" title="ID" class="idcol"/>
   <display:column property="name" />
   <display:column property="email" />
   <display:column property="status" class="tableCellError" />
   <display:column property="description" title="Comments"/>
</display:table>
    通过class属性来指定所要应用的样式。可以在其默认样式表里(./css/screen.css)直接修改
   
四、标签取得数据的数据源
   有四种范围
    pageScope
    requestScope (默认)   <display:table name="test2" >
    sessionScope   <display:table name="sessionScope.holder.list" > 注意,这里要指定范围,非默认
    applicationScope
   
五、通过增加id属性创建隐含的对象
<display:table name="test" id="testit">
     <display:column property="id" title="ID" />
     <display:column property="name" />
     <display:column title="static value">static</display:column>
     <display:column title="row number (testit_rowNum)"><%=pageContext.getAttribute("testit_rowNum")%></display:column>
     <display:column title="((ListObject)testit).getMoney()"><%=((ListObject)pageContext.getAttribute("testit")).getMoney()%></display:column>
</display:table>
    注意到在<display:table/>里增加了id属性,这时就在page context里创建了一个隐含对象,指向List里的当前对象,
    可以通过(ListObject)pageContext.getAttribute("id")来捕获这个对象。同时还创建了一个id_rowNum对象,同样,可
    通过pageContext.getAttribute("testit_rowNum")来捕获,它仅仅代表当前行的行数。
    有了这两个隐含对象,就可以通过其他标签来访问,例如Jstl:
   <display:table id="row" name="mylist">
     <display:column title="row number" >
       <c:out value="${row_rowNum}"/>
     </display:column>
     <display:column title="name" >
       <c:out value="${row.first_name}"/>
       <c:out value="${row.last_name}"/>
     </display:column>
   </display:table>
  
六、显示部分数据
    显示开始五条数据:通过设定length属性
<display:table name="test" length="5">
   <display:column property="id" title="ID" />
   <display:column property="email" />
   <display:column property="status" />
</display:table>
    显示第三到第八条数据:通过设定offset和length属性
<display:table name="test" offset="3" length="5">
   <display:column property="id" title="ID" />
   <display:column property="email" />
   <display:column property="status" />
</display:table>  

七、对email和url地址的直接连接
<display:table name="test" >
   <display:column property="id" title="ID" />
   <display:column property="email" autolink="true" />
   <display:column property="url" autolink="true" />
</display:table>
如果要显示的对象里包含email和url地址,则可以在display:column里直接设定autolink="true"来直接连接

八、使用装饰模式转换数据显示(写自己的 decorator )
   A、对整个表格应用decorator
   <display:table name="test" decorator="org.displaytag.sample.Wrapper" >
       <display:column property="id" title="ID" />
       <display:column property="email" />
       <display:column property="status" />
       <display:column property="date" />
       <display:column property="money" />
   </display:table>
     org.displaytag.sample.Wrapper即自己写的decorator,它要继承TableDecorator类,看看它的一个方法:
         public String getMoney()
     {
         return this.moneyFormat.format(((ListObject) this.getCurrentRowObject()).getMoney());
     }
     很明显,它通过父类的getCurrentRowObject()方法获得当前对象,然后对其getMoney()方法进行‘油漆’
   B、对单独的column应用decorator
   <display:table name="test">
      <display:column property="id" title="ID" />
      <display:column property="email" />
      <display:column property="status" />
      <display:column property="date" decorator="org.displaytag.sample.LongDateWrapper" />
   </display:table>
     org.displaytag.sample.LongDateWrapper要实现ColumnDecorator接口,它的方法:
         public final String decorate(Object columnValue)
     {
         Date date = (Date) columnValue;
         return this.dateFormat.format(date);
     }
     显然,它获得不了当前对象(因为它实现的是接口),仅仅是获得该对象的columnValue,然后‘油漆’
    
九、创建动态连接
    有两种方法创建动态连接:
    A、在<display:column/>里通过增加href、paramId、paramName、paramScope、paramProperty属性
       href              基本的URL 地址
       paramId           加在URL 地址后的参数名称
       paramName         数据bean的名称,一般为null(即使用当前List里的对象)
       paramScope        数据bean的范围,一般为null
       paramProperty     数据bean的属性名称,用来填充URL 地址后的参数值
<display:table name="sessionScope.details">
   <display:column property="id" title="ID" href="details.jsp" paramId="id" />
   <display:column property="email" href="details.jsp" paramId="action" paramName="testparam" paramScope="request" />
   <display:column property="status" href="details.jsp" paramId="id" paramProperty="id" />
</display:table>  
     这种方法简便直接,但缺点是无法产生类似details.jsp?id=xx&action=xx的复合URL
    B、应用decorator 创建动态连接:
<display:table name="sessionScope.details" decorator="org.displaytag.sample.Wrapper" >
   <display:column property="link1" title="ID" />
   <display:column property="email" />
   <display:column property="link2" title="Actions" />
</display:table>
    org.displaytag.sample.Wrapper里的方法:
     public String getLink1()
     {
         ListObject lObject= (ListObject)getCurrentRowObject();
         int lIndex= getListIndex();
         return "<a href=/"details.jsp?index=" + lIndex + "/">" + lObject.getId() + "</a>";
     }


     public String getLink2()
     {
         ListObject lObject= (ListObject)getCurrentRowObject();
         int lId= lObject.getId();

         return "<a href=/"details.jsp?id=" + lId
             + "&action=view/">View</a> | "
             + "<a href=/"details.jsp?id=" + lId
             + "&action=edit/">Edit</a> | "
             + "<a href=/"details.jsp?id=" + lId
             + "&action=delete/">Delete</a>";
     }

十、分页
    实现分页非常的简单,增加一个pagesize属性指定一次想显示的行数即可
<display:table name="sessionScope.test" pagesize="10">
     <display:column property="id" title="ID" />
     <display:column property="name" />
     <display:column property="email" />
     <display:column property="status" />
</display:table>

十一、排序
    排序实现也是很简单,在需要排序的column里增加sortable="true"属性,headerClass="sortable"仅仅是
    指定显示的样式。column里的属性对象要实现Comparable接口,如果没有的话可以应用decorator
    defaultsort="1"               默认第一个column排序
    defaultorder="descending"     默认递减排序
<display:table name="sessionScope.stest" defaultsort="1" defaultorder="descending">
   <display:column property="id" title="ID" sortable="true" headerClass="sortable" />
   <display:column property="name" sortable="true" headerClass="sortable"/>
   <display:column property="email" />
   <display:column property="status" sortable="true" headerClass="sortable"/>
</display:table>
   注意的是,当同时存在分页时如果不指定sort=list,则排序仅仅针对的是当前页面,而不是整个List都进行排序
  
十二、column 分组
    分组只是需要在column里增加group属性
<display:table name="test" class="simple">
   <display:column property="city" title="CITY" group="1"/>
   <display:column property="project" title="PROJECT" group="2"/>
   <display:column property="amount" title="HOURS"/>
   <display:column property="task" title="TASK"/>
</display:table>

十三、导出数据到其他格式(页面溢出filter??)
    在<display:table/>里设定export="true"
    在<display:column/>里设定media="csv excel xml pdf" 决定该字段在导出到其他格式时被包不包含,不设定则都包含
    <display:setProperty name="export.csv" value="false" />
    决定该种格式能不能在页面中导出
<display:table name="test" export="true" id="currentRowObject">
   <display:column property="id" title="ID"/>
   <display:column property="email" />
   <display:column property="status" />
   <display:column property="longDescription" media="csv excel xml pdf" title="Not On HTML"/>
   <display:column media="csv excel" title="URL" property="url"/>
   <display:setProperty name="export.pdf" value="true" />
   <display:setProperty name="export.csv" value="false" />
</display:table>

十四、配置属性,覆盖默认
   两种方法:
   A、在程序classpath下新建displaytag.properties文件
   B、对于单个表格,应用<display:setProperty>标签
   具体可配置的属性:http://displaytag.sourceforge.net/configuration.html
  
十五、一个完整的例子
<display:table name="test" export="true" sort="list" pagesize="8">
   <display:column property="city" title="CITY" group="1" sortable="true" headerClass="sortable"/>
   <display:column property="project" title="PROJECT" group="2" sortable="true" headerClass="sortable"/>
   <display:column property="amount" title="HOURS"/>
   <display:column property="task" title="TASK"/>
</display:table>
    sort="list" 对整个list进行排序
    导出数据到其他格式时,group无效

 

 

=====================第二篇===================================

DisplayTag七宗罪最近比较乱,很长时间没更新空间了,正好今天有话题,准备更新下^_^ Display Tag Lib是一个标签库,主要用来处理jsp网页上的Table,功能非常强,可以对的Table进行分页、数据导出、分组、对列排序等等,而且使用起来非常的方便,能够大大减少代码量. 记得有N多朋友问过分页问题如何可以更加方便、快速的处理,我的回答好象每次都是"DisplayTag",然后步骤相同的向朋友讲它有什么功能、能减少多少编码量、发文档、如何看war例子.以至于当时都想把操作过程录下来,来降低我的口水消耗量. 俗话说得好"路遥知马力",经过不断的使用,感觉DisplayTag"肾虚"了,问题与缺陷越来越多.现在还在使用它的朋友,如果已经放弃不用,那么就别浪费时间看这个了;如果还在使用的朋友,最好能看看我总结的DisplayTag罪状,倒能弥补些缺陷,不至于问题出现时记恨在下.呵呵. 1.中文翻页、排序问题:对于中文无法翻页、排序,最简单的办法是修改Tomcat下的server.xml文件.找到HTTP的Connector标签,在里面添加一项URIEncoding="...",引号里面的内容取决于你的页面编码,比如可以是GBK,UTF-8等. 2.分页数据加载问题:DisplayTag的分页机制是这样的,它把所有的数据放入集合中,然后再进行分页处理.这样在数据量比较大的情况下,很容易造成性能下降或者内存超支等问题.目前解决方法有两个,一是在<displaytag>中增加两个属性:partialList="true"size="resultSize",每次只加再当前页数据.还有就是实现 org.displaytag.pagination.PaginatedList接口,自定义分页算法.个人推荐第二种,详细的实现方法可参考DisplayTag 1.1所带的例子. PS:第二种方法还不完善,DisplayTag中仍存在一些Bug. 3.导出中文Excel问题:当导出中文列表名和中文表格数据Excel时,会产生乱码现象. 解决: 更改配置文件displaytag.properties,使用displaytag-export-poi.jar包.更改export.excel.class=org.displaytag.export.ExcelView为export.excel.class=org.displaytag.excel.ExcelHssfView,这样可以解决中文表格数据的问题.对于中文列表名乱码的问题,必须更改org.displaytag.excel.ExcelHssfView源代码: old: HSSFCell cell = xlsRow.createCell((short) colNum++); cell.setCellValue(columnHeader); cell.setCellStyle(headerStyle); cell.setEncoding(HSSFCell.ENCODING_UTF_16); new: HSSFCell cell = xlsRow.createCell((short) colNum++); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(columnHeader); cell.setCellStyle(headerStyle); 还有一种通过修改编码方式来支持中文的方法,那就是将org.displaytag.export.ExcelView.java中的getMimeType()方法内容修改为return "application/vnd.ms-excel;charset=GB2312";但是这样修改后,导出速度将会非常慢,呵呵. 4.decorator内容无法导出问题和Html标签导出问题:如果对table进行了decorator,那么decorator后的内容将无法导出.目前此问题无法解决.所以最好不用decorator.如果显示的内容使用了html标签进行了修饰,那么它会将html标签一起导出.也是没有什么好的解决方法. 5.导出Excel兼容性问题:有时会出现兼容性问题,导出的Excel在Office 2003下打不开. PS:导出问题不少,尤其是Excel.建议使用Apache POI自己实现Excel的导出. 6.同页面使用多个displayTag翻页问题.DisplayTag翻页时,页面上所有的displayTag元素都翻页.解决办法:对页面中的每个表格,先判断它的记录是否为0,如果为0则不使用DisplayTag. 7.未知Bug比较多:正式发布版本总是存在很多Bug.在1.1版本发布时,居然分页算法出现了明显Bug,无语.

======================第三篇=====================================

displayTag的应用   displayTag作为当前还算得上比较流行的表现层工具插件,在sourceForge官方网站(http://displaytag.sourceforge.net/)上,平均每天的访问量数以万计,本文是建立在实际开发过程中 碰到的导出excel报表的实际需求,所获得的一些学习心得与技巧与大家分享. 默认的displayTag导出的Excel格式会有中文乱码,网上大部分文章都说只有改一下,org.displaytag.export.ExcelView类中, public String getMimeType() { return "application/vnd.ms-excel"; //$NON-NLS-1$ } 方法,在方法后面追加;chartset=gbk;其它不尽然,如果这样改的话在tomcat作为web服务端的话,如果列表中有中文,很慢很慢才会有导出(不过,我至今尚未在tomcat下导出过中文), 把WEB应用布署在JBOSS下面,导出的话,如果数据量大的话也会有20-40秒不等,后来到displayTag的官网上,去看它的bugtrack,发现其实不尽然。其它displayTag如果在你需要导出excel并且想自已利用apache的 POI的话,要再去到官方网上下载一个displaytag-export-poi-1.1.jar的包,详细操作请看http://displaytag.sourceforge.net/11/install.html

其中里面谈到,如果,每次导出的excel数据总是有缓存的话,可以在web.xml文件中加入如下配置进行过滤,这样就可以导出实时数据了。 Configure the Filter in your web.xml:

<filter> <filter-name>ResponseOverrideFilter</filter-name> <filter-class>org.displaytag.filter.ResponseOverrideFilter</filter-class> </filter>And add mappings for the pages that you will intercept, for example:

<filter-mapping> <filter-name>ResponseOverrideFilter</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> <filter-mapping> <filter-name>ResponseOverrideFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>

从以上内容来看,也只是告诉你,如果要用apache的最新的POI的话,需要把displaytag-export-poi-1.1.jar从官网下载下来,放入你的工程文件中, 并没有说如何调用写自己的所需的excel的报表格式.下面就实际问题,来讨论一下如何让displayTag导出自己所需的excel格式. 在displayTag所提供的接口类中,导出自已所需的Excel有两种方式,一种是通过指定的excel模板,一种是对excel的所有的格子,一个个样式的处理, 后一种方式完全体现了“慢工出细活”的格言,而前一种方式实现起来显然要好用得多,只用读模板的样式就行了。如何调用displayTag对导出自定制的Excel文件 所提供的接口呢,请看下文,(不要急噢!^_^) 要调用displayTag给Poi所提供的接口操作步骤如下: 1,先要在你的appfuse工程中新建一个类,让其实现org.displaytag.export.BinaryExportView接口,其中关键的方法是 public void doExport(OutputStream out) throws JspException { String captionvalue = this.model.getCaption(); // ExcelHssfView1 tempExcelView=new ExcelHssfView1(); // try { // BeanUtils.setProperty(tempExcelView, "action",captionvalue); // } catch (IllegalAccessException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (InvocationTargetException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } if (captionvalue != null) { captionvalue = captionvalue.replaceAll("(//r)|(//n)|(//t)", "");

doExportCommon(out);

} else { System.out.println("exec Common"); doExportCommon(out); } } 对这个方法按照你的POI的定制excel报表的的方法,然后实现它,再把内容写入outputStream中去,基本上就可以了,当然如果有上面的

this.model.getCaption()是读取displayTag的页面标签<displayTag:caption/>标签中的内容,可以在不同的JSP页面放入不同的caption的值 从而判断调用不同的方法,生成不同的excel样式的报表,灵活性兼而有之. 写完以上类以后,最好先写个测试方法,用main或junit工具都成,看看你的调用poi的逻辑有没有问题。 当以上的类及方法写完后,就要在你的appfuse工程中找displaytag.properties文件了,一般就在web/class/目录下,找到后,打开此文件,添加如下一段配置: export.excel.class=org.displaytag.export.excel.ExcelHssfView1 后面一段是你的新建的类的文件的路径 因为是多国语言系统,所以最好把display_en.properties及display_zh_Cn.properties都加上. 到此就完成了,使用自己的POI来在appfuse中导出指定格式样式的excel文件.先别急噢,还有更精彩的等着你。这个时候又有一个问题来了,如果你 页面想要显示某些列表字段列,而导出的excel文件中又不出现这样的字段,又该如何处理呢,嘿嘿,请接着看下文。 如果要实现以上功能请如下操作: 1,调整页面上的displayTag标签的参数值,呵,比如:

<display:table name="testList" cellspacing="0" cellpadding="0" requestURI="" sort="list" id="testList" pagesize="5" class="table testList" export="true" defaultsort="1" defaultorder="descending" > <display:caption media="excel">ExportByCommon</display:caption> <display:column title="ID" sortable="true" media="html"> <a href="/aaa.html?id=<c:out value="${testList.id }" /> " target="operationFrame"> <c:out value="${testList.id }" /> </a>

</display:column> <display:column title="Status" sortable="true" media="html"> <img src="<c:out value="${testList.status}" />.gif" title="<c:out value="Status:${testList.status}" />"> </display:column>

<display:column property="remarks" escapeXml="true" sortable="true" title="Remarks" style="word-wrap: break-word;word-break: break-all; width:90px;"/> <display:footer media="excel"> <c:out value="${aa }"></c:out>| <c:out value="(${bb })"></c:out>| <c:out value="${currentDate }"></c:out> </display:footer> <display:setProperty name="item_name" value="Info"/> <display:setProperty name="items_name" value="Infos"/> <display:setProperty name="export.excel" value="true" /> <display:setProperty name="export.excel.filename" value="<%=exportFileName%>"/> <display:setProperty name="export.csv" value="false" /> <display:setProperty name="export.xml" value="false" /> <display:setProperty name="export.pdf" value="false" /> </display:table> </form> 注意上面用了多种配置需求,可以自已加链接,自定义导出名,自定义表头表尾,自定义是否全排序,自定义样式等,这些网上都有,就不细说了, 关键的需求点media的配置参数噢,如果media="excel"表示只在excel中显示,如果media=html表示仅在页面出现,没有此参数是两个都显示噢 其它的格式也类同设置,到此displayTag的点点心得分享与大家完毕,谢谢大家花费时间分享我的快乐!^_^ 噢,上文提到中文问题,用POI后就解决了! 

==============================第四篇============================= displaytag-1.1.1之中文(乱码)解决方案 1,displaytag页面的汉化:把displaytag.properties考到项目里,同时复制一份displaytag.properties,修改文件名displaytag_zh_CN.properties,把文件里面的对应条目改成中文即可;同时,文件里的对应两条配置注意选择合适的使用,下面是struts的配置 locale.provider=org.displaytag.localization.I18nStrutsAdapter locale.resolver=org.displaytag.localization.I18nStrutsAdapter

2,excel导出中文内容乱码:重载类org.displaytag.export.ExcelView,复写 public String getMimeType(){       return "application/vnd.ms-excel;charset=gbk"; //$NON-NLS-1$ } 原代码是return "application/vnd.ms-excel"; //$NON-NLS-1$ 修改displaytag_zh_CN.properties中对应条目: export.excel.class=yourpackage.SimpleChineseExcelView

3,Excel导出文件名中文乱码:重载类org.displaytag.tags.SetPropertyTag,复写 private String value; public void setValue(String propertyValue){   try{     this.value = new String(propertyValue.getBytes("GBK"),"ISO-8859-1");   }catch(Exception e){     this.value = propertyValue;   }   super.setValue(this.value); } 修改displaytag.tld对应条目 <name>setProperty</name> <!-- <tag-class>org.displaytag.tags.SetPropertyTag</tag-class> --> <tag-class>yourpackage.SimpleChineseSetPropertyTag</tag-class> 在jsp中应用时 <display:setProperty name="export.excel.filename" value="导出中文名称.xls"/> 注意,这种解决方案只能解决value的中文名称,而不能解决bodycontent内的中文名称,如 <display:setProperty name="export.excel.filename">导出菜单.xls</display:setProperty>

4,Excel导出文件名中文乱码bodycontent中的不完美解决方案 <display:setProperty name="export.excel.filename">   <%=new String("导出菜单.xls".getBytes("GBK"),"ISO-8859-1") %> </display:setProperty> 这种解决方案之所以称之为不完美适应为它要借助页面中的java代码实现

使用Mesources <display:setProperty name="export.excel.filename"> <%  MessageResources mrs = (MessageResources)request.getAttribute("org.apache.struts.action.MESSAGE");  String fileName = mrs.getMessage("menu.export.excel.filename");  fileName = new String(fileName.getBytes("GBK"),"ISO-8859-1");  out.print(fileName); %> </display:setProperty>

谁有好的解决方案可以回帖~~感激不尽~

DISPALYTAG的用法 1) Caption指标题 2) name:数据源 3) defaultsort:排序列,一般不需要 4) defaultorder:排序方式 5) class:表格显示的样式 6) varTotals:需要统计(总计) 7) decorator="totals":表示使用指定的decorator。现在仅在同时使用小计、合计时用到,自己也可以定制。 8) <display:column 部分:   property指数据中的列名   title指显示的标题   format指数据的格式化样式,   total表示该字段是否需要作统计。   style="width:20%"可以设置宽度。   也可以用   <display:column title="请假时间">   <fmt:formatDate value="${currentRowObject.QJSJ}" pattern="yyyy-MM-dd"/>   </display:column>表现。   group="1"表示进行group的字段。 9) 在表格中建立一个连接:   <display:column title="部别">   <a href="<c:out value="${pageContext.request.contextPath}"/>   /holidayDefaultSearchStatView.do?type=   <c:out value="${currentRowObject.CJDM}"/>&SYD=   <c:out value="${currentRowObject.DWDM}"/>" target="_blank">   <c:out value="${currentRowObject.DWMC}"/>   </a>   </display:column> 10) 由于该tag只有合计时,没有合计那一列,所以实现的时候以<display:footer>实现。   可以通过totalMap对象获取合计的数据,如totalMap.colomn1获取合计的第一列数值。 11) 标题头不显示<display:setProperty name="basic.show.header" value="false" /> 12) 自己定制表头:<display:caption>    使用decorator:    <jsp:scriptlet>    org.displaytag.decorator.TotalTableDecorator totals =    new org.displaytag.decorator.TotalTableDecorator();        totals.setTotalLabel("合计");        totals.setSubtotalLabel("小计");        pageContext.setAttribute("totals", totals);    </jsp:scriptlet> 实例: <display:caption>这是表标题</display:caption>  <display:table   name="${model.rowToColumnStatResult}" defaultsort="1"   class="simple" defaultorder="ascending" varTotals="totalMap">   <display:column property="GCWZ" title="部门"/>    <c:forEach items="${model.YList.YList}" var="yColumn">    <c:forEach items="${model.rowToColumnStatResult[0]}"       var="mapEntry">     <c:if test="${mapEntry.key == yColumn}">      <th>        <display:column property="${mapEntry.key}"        title="${mapEntry.key}"        format="{0,number,####.##}" total="true"/>      </th>     </c:if>    </c:forEach>    </c:forEach>   <display:column property="小计"       title="小计"       format="{0,number,####.##}" total="true"/>  <display:footer>  <tr>   <td>总计</td>   <c:forEach items="${model.YList.YColumn}" var="yColumn">   <td><fmt:formatNumber value="${totalMap[yColumn]}"         pattern="####.##"/>   </td>   </c:forEach>  </tr>  </display:footer> </display:table>  

另外一个例子: <display:table name="${model.statResult}" class="simple"  varTotals="totalMap">  <display:column property="XMMC" title="项目名称" />  <display:column property="KSRQ" title="开始日期" />  <display:column property="FZRXM" title="负责人姓名" />  <display:column property="GKDW" title="挂靠单位" />  <display:column property="JFLY" title="经费来源" />  <display:column property="XMZJF" title="项目总经费" total="true" />  <display:column property="DNDKJF" title="当年到款经费" total="true"/>  <display:footer>   <tr><td colspan="5">总计</td>    <td>     <fmt:formatNumber value="${totalMap.column6}"      pattern="####.####" />    </td>    <td>     <fmt:formatNumber value="${totalMap.column7}"      pattern="####.####" />    </td>   </tr>  </display:footer> </display:table> 总计某一列的方法: ${totalMap.column?}    ?为该列号 colspan="5":表示这个单元格占5个单元格项目名称 开始日期  负责人姓名 挂靠单位 经费来源 项目总经费 当年到款经费                                                    531      400                                                    151       10 -------------------------------------总计                              682     500 

 说说Displaytag      继续在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等等),我也想找到一个这样的组件,那样就真的可以轻松些工作了!等待那一天!

 

Displaytag用法整理一 1、 Displaytag提供的默认的系统提示均为英文,有两种方法进行汉化:

1)、将displaytag-1.1.1.jar中自带的org/display/properties/displaytag.properties 文件拷贝到项目的classes目录下

用java提供的native2ascii工具将文件进行汉化,汉化后的内容重新保存为displaytag.properties文件

2)、将jar包中的displaytag.properties汉化后替换jar包中原来的文件

2、 <display:column property="email" /> //property指定了列表中包含的bean(actionForm或vo)中包含的属性的名称,大小写必须一致

<display:column title="email">email@it.com</display:column> //列表中指定任意的列,不包含在bean中,比如显示按钮、图片等

3、 先来给出第一个具体的例子(实现列包装:显示一列checkbox,点击标题栏的checkbox完成全选):

<display:column style="width:5%;text-align:center"

headerClass="dataHead" property="columnId"

title="<input type='checkbox' name='checkall' value='all' οnclick='checkAll();' />" decorator="ainx.asiainfo.common.displaytag.CheckboxColumnWrapper" />

从该例可以看出:

1)、title属性定义了一个checkbox,点击后执行javascript函数checkAll()完成对checkbox的全选,该checkbox显示在该列的标题栏中

2)、headerClass属性指定了标题栏的css样式,dataHead是已经在css文件中定义了的

3)、property属性指定该列将要显示bean中的哪个变量的内容,大小写必须与bean中的定义一致

4)、各行都用了一个decorator将数据进行了包装,由ainx.asiainfo.common.displaytag.CheckboxColumnWrapper类实现了对该列数据的包装,该类具体内容如下:

package ainx.asiainfo.common.displaytag;

import javax.servlet.jsp.PageContext;

import org.displaytag.decorator.DisplaytagColumnDecorator;

import org.displaytag.exception.DecoratorException;

import org.displaytag.properties.MediaTypeEnum;

/**

* 用于丰富displaytag列显示的功能,在表格中显示一列checkbox

* @author lvping

*/

public class CheckboxColumnWrapper implements DisplaytagColumnDecorator {

/**

* 该列全部显示为checkbox,其value为该列带有的ID

*/

public Object decorate(Object arg0, PageContext arg1, MediaTypeEnum arg2) throws DecoratorException {

//arg0表示被包装的该列定义的property属性给定的值

//arg1表示pagecontext

//arg2表示……

String elementid = (String) arg0;

return "<input name=/"selected/" type=/"checkbox/" value=/""+elementid+"/" />";

//同理如果对于该列要显示为一个图片,可以返回”<input type=’image’ src=’…’ />”

}

}

4、 再给出第二个例子(前台分页+排序+分组功能):

<display:table class="data" cellpadding="0" sort="list" requestURI="/NetXpert/room/idcRoomAreaAction.do?actionType=doListIdcArea" pagesize="20" cellspacing="0" style="width:98%" name="areas">

<display:column property="roomname" sortable="true" group="1" title="所在机房"/>

</display:table>

从该例看出:

1)、table中的name属性指定了该表格的数据来自request的attribute中名称为"areas"的数据(即action中必须有如下的代码:

ArrayList alAreas = ……; //此处获取将要在列表中显示的数据

request.setAttribute("areas",alAreas);)

1)、table中的pagesize设定了表格中每页显示的记录个数

2)、table中的requestURI属性定义了每次分页时需要提交的请求

3)、table中的sort属性设为list,表示点击表中某列排序时可对整个表格排序

(Use 'page' if you want to sort only visible records, or 'list' if you want to sort the full list, or 'external' if the data is sorted outside displaytag)

4)、sortable属性设为true,则表示对该列支持排序(前台排序),显示出的该列的标题上会自动带有下划线,点击可排序

5)、group属性的设置表示对该列的数据自动分组,设为1表示该列数据为显示出的第一个分组

Displaytag用法整理二 1、 再给第三个例子(后台数据库分页)

<display:table class="data" cellpadding="0"

requestURI="/NetXpert/room/idcRoomShelfAction.do?actionType=doListIdcShelf" cellspacing="0" style="width:98%" name="shelfs" >

…… ……

</display:table>

从该例中可看出:

1)、table只设置了requestURI属性,没有设置pagesize属性,由requestURI指定的url来完成分页功能

2)、IdcRoomShelfAction.java中的相关函数的代码(红色部分的代码完成了分页):

public ActionForward doListIdcShelf(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) {

int page = 1; // 默认值:第1页

PaginatedListHelper paginaredList = new PaginatedListHelper();

// 获取页号

if (request.getParameter("page") != null

&& !"".equals(request.getParameter("page"))) {

page = Integer.parseInt(request.getParameter("page"));

}

paginaredList.setObjectsPerPage(20); // 默认每页显示15条记录,可以重新赋值

paginaredList.setPageNumber(page); // 设置页号

ArrayList voList = new IdcRoomShelfBo().selectShelf();

ArrayList formList = ((IdcRoomShelfForm) form)

.getFormListFromVOList(voList);

paginaredList.setFullListSize(formList.size()); // 记录总数

paginaredList.setList(formList); // 全部的数据集

paginaredList.getCurrentPageRecord(); // 获取当前页号需要的数据集

request.setAttribute("shelfs", paginaredList);

return mapping.findForward("shelfList");

}

3)、分页类的代码:(display1.1的发布已经能够支持后台数据库分页,但必须实现其提供的PaginatedList接口)

package com.asiainfo.idc.room.util;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

//PaginatedList和SortOrderEnum为displaytag-1.1.1.jar提供的jar包中提供的类

import org.displaytag.pagination.PaginatedList;

import org.displaytag.properties.SortOrderEnum;

/**

* 针对displaytag标签扩展的后台分页功能

* @author lvping

*/

public class PaginatedListHelper implements PaginatedList {

private List list; // 数据集

private int pageNumber = 1;// 页号

private int objectsPerPage = 15;// 每页显示的记录数

private int fullListSize = 0;// 全部记录数

private String sortCriterion;

private SortOrderEnum sortDirection;

private String searchId;

public List getList() {

return list;

}

public void setList(List list) {

this.list = list;

}

public int getPageNumber() {

return pageNumber;

}

public void setPageNumber(int pageNumber) {

this.pageNumber = pageNumber;

}

public int getObjectsPerPage() {

return objectsPerPage;

}

public void setObjectsPerPage(int objectsPerPage) {

this.objectsPerPage = objectsPerPage;

}

public int getFullListSize() {

return fullListSize;

}

public void setFullListSize(int fullListSize) {

this.fullListSize = fullListSize;

}

public String getSortCriterion() {

return sortCriterion;

}

public void setSortCriterion(String sortCriterion) {

this.sortCriterion = sortCriterion;

}

public SortOrderEnum getSortDirection() {

return sortDirection;

}

public void setSortDirection(SortOrderEnum sortDirection) {

this.sortDirection = sortDirection;

}

public String getSearchId() {

return searchId;

}

public void setSearchId(String searchId) {

this.searchId = searchId;

}

/**

* 根据总的数据集和每页需要的首记录、尾记录索引,从总记录集中得到需要的记录集

* 这是一个取巧的分页方法,并非真正的根据每页请求拼sql进行查询,而是对于整个数据查询的结果从中取各页需要的数据集合,对于超大数据量的查询效率可能不会太高

*/

public void getCurrentPageRecord() {

ArrayList v = new ArrayList();

Iterator iterator = null;

try {

if (this.getList() != null) {

iterator = this.getList().iterator();

int i = 0;

int fromRow = 0;

int toRow = 0;

if (this.getPageNumber() == 1) { // 首页

fromRow = 1; // 从第一行开始

toRow = this.getObjectsPerPage();

} else {

fromRow = (this.getPageNumber() - 1)

* this.getObjectsPerPage() + 1;

toRow = fromRow + this.getObjectsPerPage();

}

if (toRow > this.getFullListSize()) // 如果尾行数超过list的大小

toRow = this.getFullListSize();

while (iterator.hasNext()) {

i++;

if (i < fromRow) {

iterator.next();

continue;

} else if (i > toRow) {

iterator.next();

continue;

} else {

v.add(iterator.next());

}

}

this.setList(v);

}

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

 

 Displaytag用法整理三 1、 再来一个(列中的超链接):

<display:column style="width:10%;text-align:center"

headerClass="dataHead" property="shelfcode"

href="/NetXpert/room/idcRoomShelfAction.do?actionType=doEditIdcShelf&" paramId="shelfid" paramProperty="shelfid" title="机柜编码" />

从该例中看到:

1)、列的href属性定义了点击超链接后请求的url

2)、列的paramId属性定义了url后面带有的参数的名称

3)、列的paramProperty属性定义了url给出的参数值

4)、根据该列的定义,点击该列数据的超链接后,会跳转至如下的url:

/NetXpert/room/idcRoomShelfAction.do?actionType=doEditIdcShelf&shelfid=XXX (XXX为property属性指定的bean中的shelfcode的值)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值