一、综述
Pager,分页组件。在介绍分页组件前,首先了解一下SimpleFramework的数据访问集接口IDataObjectQuery,分页组件在接口设计上依赖于IDataObjectQuery,其目标是提供一个编程一致、可靠并且高性能的结果集。
目前IDataObjectQuery有三个实现:
List
DB
Lucene
如果你不了解SimpleFramework的数据访问机制(SimpleADO),建议参考一下:
http://simpleframework.net/doc/d2/3.4.html
1.1 Pager组件
分页组件的接口设计很简单,定义如下:
- public interface IPagerHandle extends IComponentHandle {
- int getCount(ComponentParameter compParameter) throws Exception;
- void process(ComponentParameter compParameter, int start) throws Exception;
- IDataObjectQuery<?> createDataObjectQuery(ComponentParameter compParameter)
- throws Exception;
- }
先看看标红的两个函数:
getCount定义了数据集的总数;
process将从某一位置(start)开始,然后获取之后的n条数据(n在PagerBean中定义了每次处理数据的条数,PagerBean可通过compParameter获取)
很简单的逻辑,但如果每次让用户来实现getCount和process,我想一定会头大:(
原因如下:
count、start和n处理起来比较繁琐
每一种数据源处理方式不一样,比如:db、缓存、lucense,甚至nosql
如何输出数据展示层
分页组件为了简化实现的难度,又定义了一个函数:
- IDataObjectQuery<?> createDataObjectQuery(ComponentParameter compParameter) throws Exception;
这岂不是越来越复杂吗?其实分页组件同时还提供了一个抽象类AbstractPagerHandle来达到简化的目的,你只要继承自AbstractPagerHandle,getCount和process就不需要实现了,只需要提供分页的数据集IDataObjectQuery即可。
说一下如何输出数据展示层。
Pager组件不像TablePager组件有固定的数据展示方式,数据如何展示则完全取决于使用者本身,Pager组件通过提供dataPath属性(定义的jsp路径)来处理数据展示。
那么在jsp文件中,又如何得到当前分页的数据呢?
因为AbstractPagerHandle已经实现了process函数,该函数会把当前页的数据以List的形式放在request中,为了方便调用,你可以在jsp定义如下代码:
- List data = PagerUtils.getPagerList(request);
1.2 TablePager组件
TablePager组件继承自Pager组件,因为是基于列和行的展示方式,所以其dataPath属性被设定了一个不可更改的值,可以理解为TablePager组件内置了数据展示的jsp文件,这个jsp文件会根据定义好的列属性来展示表格数据。
ITablePagerHandle还定义了什么呢:
- AbstractTablePagerData createTablePagerData(ComponentParameter compParameter)
- throws Exception;
这个函数的目的是告诉内置的jsp文件如何通过AbstractTablePagerData对象生成基于的表格数据展示(HTML),后续将会详细介绍这个对象。
1.3 GroupTablePager
GroupTablePager组件继承自TablePager组件,提供了按表格某一列(目前不支持多列)分组功能。
二、原理
见下图
三、实践
3.1 Pager组件
3.1.1 Pager组件的声明
- <pager name="testPager" containerId="idTestPager"
- handleClass="net.simpleframework.TestPagerHandle"
- dataPath="test_pager.jsp" pageItems="20">
- </pager>
声明一个名称为testPager的分页组件。
3.1.2 通过ID与HTML页面元素绑定
在HTML页面中,你需要定义一个区域,并且这个区域的ID和pager组件的containerId属性值一样,SimpleFramework将把Pager组件在后台产生的HTML代码放到这个指定的ID区域内。
- <div id="idTestPager"></div>
3.1.3 定义数据源
对于一般用户来讲,实现getCount和process是没有意义的,直接继承自抽象类AbstractPagerHandle会更简单(详见综述部分),如果数据来自缓存,代码如下:
- public IDataObjectQuery<?> createDataObjectQuery(
- final ComponentParameter compParameter) throws Exception {
- // 创建一些数据TestBean,并添加到List
- List<?> data = Arrays.asList(new TestBean(), new TestBean(), new TestBean());
- return new ListDataObjectQuery(data);
- }
如果来自数据库:
- public IDataObjectQuery<?> createDataObjectQuery(
- final ComponentParameter compParameter) throws Exception {
- // 从数据库查询
- return DataObjectManagerFactory.getQueryEntityManager(getApplication()).query(
- new SQLValue("select * from test"));
- }
3.1.4 编写数据展示层
数据源创建后,需要在属性dataPath指定的文件test_pager.jsp下编写数据展示。
如何在test_pager.jsp中获取当前分页的数据呢?在综述部分已经讲到,通过 List data = PagerUtils.getPagerList(request); 获取当前分页的数据。
剩下需要做的,就是遍历data,并输出HTML和样式了。
提出一个问题,data的大小是多少?(pageItems指定的个数)
3.2 TablePager组件
因为继承自分页组件,表格组件拥有分页组件的所有属性,属性dataPath已没有意义,因为总是调用内置的jsp页面。
3.2.1 TablePager组件的声明
- <tablePager name="testTablePager" containerId="idTestTablePager"
- handleClass="net.simpleframework.TestTablePagerHandle"
- pageItems="30">
- </tablePager>
声明一个名称为testTablePager的表格组件。
3.2.2 通过ID与HTML页面元素绑定
和分页组件一样,定义一个区域,并设置containerId属性。
- <div id="idTestTablePager"></div>
3.2.3 定义表格列
- <tablePager name="testTablePager" containerId="idTestTablePager"
- handleClass="net.simpleframework.TestTablePagerHandle"
- pageItems="30">
- <columns>
- <column columnName="n1" sort="false" />
- <column columnName="n2" sort="false" separator="true"
- headerStyle="width: 180px;" style="width: 180px;" />
- <column columnName="n3" separator="true"
- headerStyle="width: 120px;" style="width: 120px;" />
- <column columnName="n4" separator="true"
- headerStyle="width: 120px;" style="width: 120px;" />
- </columns>
- </tablePager>
如上,红色部分。其属性含义为:
columnName:列唯一名称,***英文,对应后台bean的属性值或Map的Key值
columnText:列的显示名称,即你在表格头所看见的,如果为空则显示columnName
columnSqlName:数据源的列名,等于columnName时可为空
sort:标识该列是否可以排序
defaultExport:是否导出该列
headerStyle:列头的样式,等同于HTML中style的值
style:行的样式
3.2.4 定义数据源
参考分页组件的数据源定义:)
3.2.5 实例化AbstractTablePagerData对象
表格组件的Handle接口ITablePagerHandle需要实例化AbstractTablePagerData对象,其目标是在数据源和表格展示层搭建一个转换器,这个转化器定义了表格Render(展示)所需要的所有信息。
下面列举AbstractTablePagerData定义的一些常用方法:
- // 定义了表格列,默认从表格组件定义(前面红色部分)中获取,所以可以覆盖此方法来动态生成表格列
- Map<String, TablePagerColumn> getTablePagerColumns();
- // 传递数据源中的对象dataObject,并转为表格需要的数据Map。
- // 比如,dataObject中含有日期类型,可以在put到Map中转为带格式的字符串(仍按日期排序)
- Map<Object, Object> getRowData(Object dataObject);
表格组件同样也提供了抽象类AbstractTablePagerHandle,目的是简化实例AbstractTablePagerData的操作。
四、高级特性
4.1 数据刷新
在客户端通过javascript来刷新分页组件,代码示例如下:
- $Actions["testPager"]();
- 或
- $Actions["testTablePager"].refresh(params);
数据刷新是基于ajax的,调用时可以动态传递一些参数。
4.2 定义操作事件
4.2.1 jsLoadedCallback
分页组件装载后,将触发此事件,数据刷新完成后也会触发此事件,举个例子:
- <tablePager name="testTablePager" containerId="idTestTablePager"
- handleClass="net.simpleframework.TestTablePagerHandle"
- pageItems="30">
- <jsLoadedCallback>
- // 初始化表格行,使之具备拖放操作
- TableRowDraggable.init("idTestTablePager", "tafelTreeselected");
- </jsLoadedCallback>
- </tablePager>
4.2.2 jsRowClick和jsRowDblclick
定义表格组件行的单击和双击事件,其函数原型为:
- function click(item) {
- // item为行TR对象
- }
示例如下:
- <tablePager name="testTablePager" containerId="idTestTablePager"
- handleClass="net.simpleframework.TestTablePagerHandle"
- pageItems="30">
- <jsRowClick>
- alert(item.getAttribute("id")); // 打印行id
- </jsRowClick>
- </tablePager>
4.3 一些不常用的属性
解释一些不经常使用的属性含义:
pagerBarLayout:分页按钮的布局,有四个值,top、bottom、both、none,含义为,在数据上方显示、在数据下方显示、上下方都显示、都不显示
title:组件左上方要显示的一些文本
indexPages:分页按钮(数字部分)显示个数
noResultDesc:当没有数据,显示的文本提示信息
csvExportAction:导出的js代码,空为系统提供的js代码,false将禁止导出功能
jobView:定义查看数据角色,需机构应用模块的支持
五、总结
还是留给读者吧:)
下次将介绍Window组件。