eXtreme Table 说明
==================
eXtreme Table 是ExtremeCompontents(http://extremecomponents.org)中一个功能强大而又容易配置、扩展、自定义的Table控件,其功能包括分页、排序、过滤、导出Excel、pdf和汇总等。
扩展eXtreme Table:extremetable-ext.jar是我们自己编写的eXtreme Table扩展包,里面的类继承了原eXtreme Table中的类,并根据我们自己的需要进行了修改和扩展。主要扩展内容包括:显示分页页号、CSV导出表头等。
其样子类似这样:
---------
基本配置:
---------
1)首先下载发行包 http://sourceforge.net/projects/extremecomp;
2)将包内的extremecomponents.jar 文件拷贝到项目的 WEB-INF/lib 目录中
5)将 images 文件夹拷贝到 webroot目录中
6)将 extremecomponents.css 拷贝到 webroot/css目录中
7)将eXtreme Table扩展包extremetable-ext.jar拷贝到项目的 WEB-INF/lib 目录中
8)eXtremeTable支持在properties文件里方便的统一配置丰富的全局属性,可以在/source/org/extremecomponents/table/core目录找到extremetable.properties文件,可以把它复制到src/里面并进行修改,也可以在src/里新建一个extremetable.properties文件,在里面只写需要修改的属性,其他属性会自动去jar包中的extremetable.properties文件获取。
还要在web.xml中加上:
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]extremecomponentsPreferencesLocation/extremetable.propertieseXtremeExportorg.extremecomponents.table.filter.ExportFiltereXtremeExport/*
--------------------------------------------
本项目用到的一些extremetable.properties配置:
--------------------------------------------
table.filterable=false 不允许过滤
table.sortable=false 不允许排序
table.imagePath=/images/table/*.gif 图片路径
table.locale=ja_JP 使用日语
table.view.html=org.extremecomponents.table.view.UserCompactView 使用extremetable-ext中的html视图类
export.view.csv=org.extremecomponents.table.view.UserCsvView 使用extremetable-ext中的CSV视图类
row.highlightRow=true 鼠标经过时高亮显示行
column.format.date=yyyy-MM-dd HH:mm:ss 当列设置为cell="date"时采用的显示格式
column.format.currency=###,###,###,###,#00.00 当列设置为cell="currency"时采用的显示格式
table.pageDisplayed=7 在页号选择中显示7个页号 (如图中1所示位置)
table.rowsDisplayed=20 表格每页显示20行
---------------
基本原理和流程:
---------------
1、首先,从action中按指定的每页n行获取第一页的数据,即获取前n个数据。
2、Action将数据发给JSP页面,由eXtremeTable的标签显示出第一页。
3、JSP中的本质上是一个form,在选择其他页时,eXtremeTable将把上次传入的参数加上要显示的页号等参数作为该form的参数,把该form提交给指定的action。
4、Action将按照传入的上次检索条件和本次的页号等参数重新获取一遍要显示的数据,然后再发给JSP中的。每次只取得一页显示需要的结果集,不获取多余的数据,从而减轻了数据库的负荷。
--------------
使用Limit特性:
--------------
默认的情况下eXtremeTable取得所有的结果集然后处理Beans集合,这样的好处是你可以随意进行排序、过滤和分页操作。你只需要组装Beans集合并让eXtremeTable知道如何引用它。这样的操作对于小到中等数据量的结果集非常有效,但结果集很大时这将非常糟糕。为了提高性能,正如前面基本原理和流程所描述的,我们希望每次只取得一页显示需要的结果集,不获取多余的数据,即数据库端分页的方案。为此我们使用eXtremeTable的Limit特性。
Limit这个名字来自MySQL的limit命令,Limit接口的目的就是如何对表的结果集进行limit处理。Limit实现知道当排序、过滤、分页、导出时,用户如何与表互相作用。有了这些信息你将能够使用可能是最有效的方式显示正确的过滤、排序、分页后的请求页面。
使用Limit时,eXtremeTable会使用Limit对象向Action传递PageNo,PageSize,OrderBy等分页信息。而服务端将向EC返回总记录数和当前页的内容。
---------
基本用法:
---------
下面以一个简单的例子说明最基本的用法:
1) JSP中:
一个简单的eXtreme Table类似于这个样子:
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]
该表格从集合operators中获取每行的元素,赋值给变量operator,用作每行处理的数据。
下面说明各项属性:
标签:
items="operators" 按page、request、session和application范围的顺序搜索并遍历集合operators,从中迭代获取数据
var="operator" 把每次从集合operators中取出的单个元素赋值给名为operator的bean,存放在page范围中
action="${pageContext.request.contextPath}/sample.do" 指定处理此表单的Action
retrieveRowsCallback="limit" 指定检索Callback使用LimitCallback。为了使用Limit特性,eXtremeTable需要使用limit特定的RetrieveRowsCallback
sortRowsCallback="limit" 指定排序Callback使用LimitCallback。为了使用Limit特性,eXtremeTable需要使用limit特定的SortRowsCallback
filterRowsCallback="limit" 指定过滤Callback使用LimitCallback。为了使用Limit特性,eXtremeTable需要使用limit特定的FilterRowsCallback
filterable="false" 设定可否过滤(因为extremetable.properties已经进行了设置,所以本例中此处其实不用设置此属性)
sortable="false" 设定可否排序(因为extremetable.properties已经进行了设置,所以本例中此处其实不用设置此属性)
showExports="true" 设定是否显示导出功能 (默认为true,所以本例中其实可以不写此项)
autoIncludeParameters="${empty param.autoInc?true:false}" 设定是否包含参数,设置为true时,它会把你上次传过来的参数自动生成为ec form的hidden input, 这好处是在查询的时候,使每次翻页的查询参数都是相同的。
注:其中,autoIncludeParameters之所以设置成${empty param.autoInc?true:false},是为了更灵活地控制是否包含上次传过来的参数——当你不希望它包含上次传过来的参数时,只要在传过来的参数中加上一条autoInc=false。比方说,你在ec form中提供了一列checkbox控件用来指定要删除的记录,如果你只是简单地把autoIncludeParameters设置成了true,就会带来一个问题:如果第一次删除了N18, 等二次删除N9的时候,因为N18被auto include进ec form作为参数了,所以会同时删除 N18和N9。而N18此时已经不存在了,于是就会导致执行第二次删除的时候失败。解决办法就是进行删除操作的时候加多一个参数autoInc=false,并且在中设置autoIncludeParameters="${empty param.autoInc?true:false}",则删除时就不会把参数带到下一次了。
标签:提供CSV导出功能,可以把表格中的数据导出
fileName 设置导出的目标文件名
tooltip 设置鼠标悬浮时显示的提示文字
其他的导出标签还有:
xls导出功能
pdf导出功能
其中的属性与标签相同。
标签:和括来的内容就是每行中显示的内容
标签:设置行中的每个列,即单元格
property="updateDate" 从page范围中取得名为operator的bean,并得到它对应的updateDate属性值。如果你正使用 Beans集合请确认具有对应的getter方法;如果使用Maps集合则不需要任何别的动作, eXtremeTable能够通过属性名从Map中得到对应的值。
cell="date" 使用date格式,即extremetable.properties中设置的column.format.date
title="更新日付" 设置表头,即列标题
其他常用属性:
alias alias(别名)属性用来唯一地标识这列。当同样的属性被多列使用时用来唯一地标识一列。
viewsAllowed viewsAllowed属性指定类允许使用的视图。视图包括:html、pdf、xls、csv,以及任何定制的视图。 如果你指定一个或几个视图,那么列仅能使用这些指定的视图。例如:你指定viewsAllowed="pdf",这意味着这列只允许PDF导出,而不能进行其他格式的导出或html视图。
viewsDenied viewsDenied属性指定类不允许使用的视图。视图包括:html、pdf、xls、csv,以及任何定制的视图。 如果你指定一个或几个视图,那么列仅这些指定的视图不能被使用。例如:你指定viewsDenied="html",这意味着这列不允许使用html试图,但能进行任何形式的导出。
2) Action中:
前面JSP中已经指明了使用Limit特性。下面在Action中也需要增加一些关于Limit的语句。
首先需要创建一个Limit。
本项目中已经把提供了现成Limit的获取方法,位于cn.bestwiz.jhf.admin.common.page.ExtremeTablePage方法中。
一般用这么一条语句即可获得所需的Limit对象:Limit limit = ExtremeTablePage.getLimit(request);
本例中的相关Action语句如下:
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]SampleService sampleService = new SampleService();
//ExtremeTable分页
Limit limit = ExtremeTablePage.getLimit(request); //获取得所需的Limit对象
Page etpage = sampleService.getOperatorList(limit.getPage(), limit.getCurrentRowsDisplayed()); //向Service方法传入要显示的页号limit.getPage()和每页的行数limit.getCurrentRowsDisplayed(),以实现数据库端分页查询
//返回ExtremeTable分页结果
request.setAttribute("operators", etpage.getResult()); //把要显示的结果集etpage.getResult()传给JSP,其中的operators就是JSP的标签中items="operators"属性定义的变量名
request.setAttribute("totalRows", etpage.getTotalCount()); //把总记录数(即总行数)etpage.getTotalCount()传给JSP,其中totalRows是eXtremeTable内定的总行数的变量名,不可随意更改。
其中,Page是本项目中自定义的一个类,是为了方便分页处理,它把分页所需的各项参数都封装到了一个类里,使得用起来更加方便。
3) Service中:
从前面Action部分的
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]Page etpage = sampleService.getOperatorList(limit.getPage(), limit.getCurrentRowsDisplayed());
我们已经看到,对应的Service方法需要接受两个传入的参数:要显示的页号、每页的行数。所以本例中对应的Service方法应该是类似这样的:
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]public Page getOperatorList(int pageNo, int pageSize) throws ServiceException {
Page page = null;
……
try {
DbSessionFactory.beginTransaction(DbSessionFactory.INFO);
……
SampleDao sampleDao = new SampleDao();
page = sampleDao.getOperatorList(pageNo, pageSize, null);
……
DbSessionFactory.commitTransaction(DbSessionFactory.INFO);
} catch ……
……
return page;
}
其中,pageNo是要显示的页号、pageSize是每页的行数,在Service中只要把传入的这两个参数忠实地传给Dao方法就行了,不必也不应进行任何处理。
总的来说,Service中的变化一共只有三处:
1、返回值为Page类型
2、传入的参数多了int pageNo, int pageSize两项
3、在调用Dao方法时,要把pageNo和pageSize两个参数传过去
除此之外,不用做任何其他改变。
4) Dao中:
从前面Service部分的
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]page = sampleDao.getOperatorList(pageNo, pageSize, null);
我们已经看到,对应的Dao方法需要接受两个传入的参数:要显示的页号pageNo、每页的行数pageSize。所以本例中对应的Dao方法应该是类似这样的:
……
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]public class SampleDao extends BaseHibernateDao { //因为要用到分页查询,所以必须继承自BaseHibernateDao
public SampleDao(){
this.setSession(DbSessionFactory.infoSession()); //设置要使用的数据库
}
……
public Page getOperatorList(int pageNo, int pageSize, Object[] args){ //其中Object[] args是参数数组,用于往hql语句中传参
……
String hql = "from JhfCsOperator"; //构建一个HQL语句
……
try {
……
Page page = pagedQuery(hql, pageNo, pageSize, args); //进行分页查询。
……
} catch ……
……
return page;
}
……
}
其中pagedQuery方法是BaseHibernateDao中定义的方法,用于分页查询。该方法接受HQL语句、页号、每页大小以及传入hql语句的参数数组这四个参数,执行相应的查询,然后返回Page对象。
至此,本例就完成了。
-------------
更复杂的应用:
-------------
1) 设定初始每页行数:
默认情况下,初始每页行数就是extremetable.properties中的table.rowsDisplayed属性值。
如果想要自定义某个表的初始每页行数(假设为10),需要如下操作:
1、JSP中:
在标签中设置属性
rowsDisplayed="10"
这样在JSP中显示时就将以10作为初始的每页行数来显示。
2、Action中:
因为运行时的流程是先到Action,然后再转到JSP,所以当第一次进入Action时,并不能得到JSP中设置的任何参数,所以上一条中设置的rowsDisplayed无法影响到Action第一次的查询动作。以本例来说,虽然在JSP中设置了rowsDisplayed="10",但是Action在第一次获取结果集时仍将按照extremetable.properties中设置的默认20行来查询,虽然在JSP页面中能够按照10行来显示,但剩下的10条数据就成了冗余数据了。而如果JSP中设置了rowsDisplayed="30",Action在第一次获取结果集时仍将只查询20行,这样显示的时候就会出问题了。
所以必须在Action中设置初始每页行数。
为此,只要把上面的
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]Limit limit = ExtremeTablePage.getLimit(request);
改成
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]Limit limit = ExtremeTablePage.getLimit(request, 10); //其中10就是初始每页行数
即可。其他部分都不需要修改,Service和Dao也不需要修改。
另外,为了便于以后维护,建议仅在一个地方定义此参数,具体做法可以类似下面这样(仅供参考):
Action中:
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]int pageSize = 10; //以后要改的话只须改这一个地方
Limit limit = ExtremeTablePage.getLimit(request, pageSize);
request.setAttribute("pageSize", pageSize);
JSP的标签中:
rowsDisplayed="${pageSize}"
2) 在同一页面中使用多个eXtremeTable
要在同一JSP页面中互不干扰地使用两个或多个不同的eXtremeTable,必须进行一些特别的设置:
1、JSP中:
在每个标签中设置属性 tableId ,为每个表格设置一个ID,例如:
tableId="table1"
这个ID将在其他各项操作中唯一地标识这个表。
2、Action中:
Action中需要把前面示例中的相关各句如下修改:
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]SampleService sampleService = new SampleService();
//ExtremeTable分页
Limit limit = ExtremeTablePage.getLimit(request, "table1"); //指明对应的tableId
Page etpage = sampleService.getOperatorList(limit.getPage(), limit.getCurrentRowsDisplayed()); //这句不变
//返回ExtremeTable分页结果
request.setAttribute("operators", etpage.getResult()); //这句不变
request.setAttribute("table1_totalRows", etpage.getTotalCount()); //把属性名由原来的 totalRows 改成 tableId + "totalRows"
Service和Dao都不需要修改。
这样,只要给不同的表格设置不同的tableId,就可以互不干扰地使用了。
注:ExtremeTablePage.getLimit方法还有一个形式:ExtremeTablePage.getLimit(HttpServletRequest request, String tableId, int defautPageSize) ,可以同时传入这三个参数。
3) 把eXtremeTable嵌套在其他form中
有时需要把eXtremeTable嵌入到其他form中,作为其他form的一部分来使用和提交。但是默认情况下eXtremeTable本身就是一个form(就是说标签最终会生成标签),所以不能直接嵌套。如果你想在表体中包含一些定制的form元素, 或者想将eXtremeTable嵌入到另外的form中,那么你就要使用表标签的form属性用来参照最近的form。
例如,如果在标签中设置了属性
form="form1"
那么将不再生成标签,只生成表中的其他内容,这样只要把eXtremeTable放在name="form1"的form中,eXtremeTable中的所有内容都将作为form1的一部分来显示和提交。
在Struts框架中,标签生成的form,其name值为其action定义的name。
例如,如果struts-config.xml中定义了
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]
那么JSP中
Java代码 [img]http://www.iteye.com/images/icon_copy.gif" alt="复制代码[/img]
[code="java"]
最终生成的form的name就等于currencyPairForm。如果要把eXtremeTable嵌套到该form中,就要在中设置
form = "currencyPairForm"
并把整个块放到块内。
-------------
一些实际例子:
-------------
下面是jhf项目中一些可供参考的实际模块:
基本示例: http://localhost:8080/jhf_admin/sample.do
在同一页面中使用多个eXtremeTable: http://localhost:8080/jhf_admin/asset.do
把eXtremeTable嵌套在其他form中 http://localhost:8080/jhf_admin/operator.do