在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