在JSF和Richfaces的官方示例里面没发现正经的数据库分页示例,于是自己轮了一个,还算比较满意,分享出来。
struts等框架,视图(jsp、freemarker等)直接获取action中准备好的数据结果集合,请求下一页数据的时候,同样后台action处理请求,把action中的数据集合用新的这一页数据替换掉,然后渲染页面,从而实现分页。每次请求action的处理过程可以拿到页号等信息,所以在action调用service的时候就可以使用这些信息,调用相应的方法做分页数据查询。
JSF结合Richfaces做这个事情和Struts等框架有有很大的区别。
rich:dataTable这个标记可以配合一个rich:dataScroller使用,达到ajax翻页的效果,但是这时候dataTable的value实际上要求是一个ExtendedDataModel对象。每次翻页的时候,页面组件调用这个ExtendedDataModel对象的walk方法获取目标页的数据——注意这个过程是不经过Action的。也就是说,页面第一次加载的时候,dataTable的value属性是#{action.data},其中data属性是一个ExtendedDataModel对象,此后翻页的过程中,不再经过action。
基于这样的不同,需要采用一种新的机制来实现数据查询过程。action返回给视图的data对象,不应该是查询出来的某一页的一个数据集合,
而是一种查询数据的能力。
最终Action中的代码如下:
1 public class CommonAction{
2 3 protected PagedDataModel data;
//用于列表展现的数据
4 5 @PostConstruct
6 public void init(){
7 Map<String,Object> parameters =
;
//查询条件
8 this.data =
this.findPage(parameters);
9 }
10 11 /**
12 * 使用Service分页查询数据
13 * @return
14 * 注意,由于JSF的结构,这里返回的其实并不是真正的查询结果,而是一种查询数据的能力。
15 * 这种能力返回给JSF的页面组件作为value,页面渲染的时候使用这个能力来获取数据
16 */17 protected PagedDataModel findPage(
final Map<String,Object> parameters) {
18 int count =
this.getService().count(propertyFilterList).intValue();
19 return new PagedDataModel(count,
new DataProvider(){
20 21 @Override
22 public List<?> getList(
int firstRow,
int maxResults) {
23 return CommonAction.
this.getService().find(parameters, firstRow, maxResults);
24 }
25 });
26 }
27 }
findPage返回的是一个PagedDataMode(继承ExtendedDataModel),其中包含了真正的查询数据的能力:DataProvider。
DataProvider很简单:
1 public interface DataProvider {
2
3 List<?> getList(int firstRow, int maxResults);
4
5 }
PagedDataMode稍微复杂一点,其中做了一下数据缓存:
1 /**
2 *
3 * 分页数据模型,用于rich:dataTable
4 *
5 * @author allan
6 *
8 */
9 public class PagedDataModel extends ExtendedDataModel {
10 private Integer currentId;
11 private Map<Integer, Object> dataMap = new LinkedHashMap<Integer, Object>();
12 protected Integer count;
13 private int lastFirstRow = 0;
14 private int lastMaxResults = 0;
15 private SortProperties sortFields;
16
17 private DataProvider dataProvider;
18
19 public PagedDataModel(int count,DataProvider dataProvider){
20 super();
21 super.count = count;
22 this.dataProvider = dataProvider;
23 }
24
25 /**
26 * 最终获取总记录数的方法
27 * @return
28 */
29 public int getCount() {
30 return super.count;
31 }
32
33 /**
34 * 最终获取数据的方法
35 * @param firstRow
36 * @param maxResults
37 * @return
38 */
39 public List<?> getList(int firstRow, int maxResults, SortProperties sortFields) {
40 return this.dataProvider.getList(firstRow, maxResults, sortFields);
41 }
42
43
44 @Override
45 public Object getRowKey() {
46 return this.currentId;
47 }
48
49 @Override
50 public void setRowKey(Object key) {
51 this.currentId = (Integer) key;
52 }
53
54 @Override
55 public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
56 int firstRow = ((SequenceRange) range).getFirstRow();
57 int maxResults = ((SequenceRange) range).getRows();
58 if(maxResults <= 0) maxResults = Integer.MAX_VALUE;
59 //数据是不存在
60 if(firstRow != this.lastFirstRow || maxResults != this.lastMaxResults) {
61 //获取所需数据
62 List<?> listRow = this.getList(firstRow, maxResults, this.sortFields);
63 //记录数据
64 dataMap.clear();
65 for(int i = 0; i < listRow.size(); i++) {
66 Object row = listRow.get(i);
67 int index = firstRow + i;
68 dataMap.put(index, row);
69 }
70
71 this.lastFirstRow = firstRow;
72 this.lastMaxResults = maxResults;
73 }
74 //设置数据
75 for(Integer index : dataMap.keySet()) {
76 visitor.process(context, index, argument);
77 }
78 }
79
80 @Override
81 public int getRowCount() {
82 if(count == null)
83 count = this.getCount();
84 return count;
85 }
86
87 @Override
88 public boolean isRowAvailable() {
89 if(dataMap == null) {
90 return false;
91 } else {
92 return dataMap.containsKey(currentId);
93 }
94 }
95
96 @Override
97 public Object getRowData() {
98 return dataMap.get(currentId);
99 }
100
101 @Override
102 public Object getWrappedData() {
103 return this.getList(0, Integer.MAX_VALUE, this.sortFields);
104 }
105
106 @Override
107 public void setWrappedData(Object arg0) {
108 throw new UnsupportedOperationException();
109 }
110
111 @Override
112 public int getRowIndex() {
113 throw new UnsupportedOperationException();
114 }
115
116 @Override
117 public void setRowIndex(int arg0) {
118 throw new UnsupportedOperationException();
119 }
120 }
121