终于讲到排序了,这一部分应该说还是比较好理解的。
jqGrid通过colModel选项中的sortable来控制是否可以以某列的值排序。sortable的默认值是true,当设为false时,即此列不能用于排序。
view plaincopy to clipboardprint?
01.$(function(){
02. $("#gridTable").jqGrid({
03.
04. ...
05.
06. colModel: [
07. {name:"id",index:"id",label:"编码",width:40},
08. {name:"lastName",index:"lastName",label:"姓",width:80},
09. {name:"firstName",index:"firstName",label:"名",width:80},
10. {name:"email",index:"email",label:"电子邮箱",width:160,sortable:false},
11. {name:"telNo",index:"telNo",label:"电话",width:120,sortable:false}
12. ],
13.
14. ...
15.
16. });
17.});
$(function(){
$("#gridTable").jqGrid({
...
colModel: [
{name:"id",index:"id",label:"编码",width:40},
{name:"lastName",index:"lastName",label:"姓",width:80},
{name:"firstName",index:"firstName",label:"名",width:80},
{name:"email",index:"email",label:"电子邮箱",width:160,sortable:false},
{name:"telNo",index:"telNo",label:"电话",width:120,sortable:false}
],
...
});
});
当点击sortable为true的列首时,jqGrid会向Server发送排序请求,例如:
http://localhost:8085/Hare/jqGridTest/jqGrid05.action?search=false&nd=1279006749246&rows=15&page=3&sidx=firstName&sord=asc
注:其中sord和sidx参数名都是在jqGrid的prmNames选项中设定的(可参考本系列文章的第一篇)。而sidx参数的值即各列的colModel的index选项值。(在查询和排序时,发送的关于列的参数都是基于colModel的index属性的)
后面的事情就交给服务器端的Action来处理了,还拿我们的Contact联系人列表为例。
既然我们可能会分别使用不同的字段来排序,那么就必须为Contact提供不同的Comparator来简化比较操作。因此我写了一个针对Contact的Comparator的工厂类,用来根据不同的字段提供不同的Comparator。
ContactComparatorFactory的代码:
view plaincopy to clipboardprint?
01.package cn.gengv.struts2ex.jqGrid;
02.import java.text.Collator;
03.import java.util.Comparator;
04.import com.byzl.hare.model.Contact;
05.public class ContactComparatorFactory {
06. private static Collator collator_Chinese = Collator.getInstance(java.util.Locale.CHINA);
07. private final static Comparator<Contact> idComparator = new IdComparator();
08. private final static Comparator<Contact> firstNameComparator = new FirstNameComparator();
09. private final static Comparator<Contact> lastNameComparator = new LastNameComparator();
10. private final static Comparator<Contact> fullNameComparator = new FullNameComparator();
11. private final static Comparator<Contact> idCardNoNoComparator = new IdCardNoComparator();
12. private final static Comparator<Contact> nationalityComparator = new NationalityComparator();
13.
14.
15. public static Comparator<Contact> getComparator(String compareType) {
16. if ("id".equalsIgnoreCase(compareType)) {
17. return idComparator;
18. } else if ("firstName".equalsIgnoreCase(compareType)) {
19. return firstNameComparator;
20. } else if ("lastName".equalsIgnoreCase(compareType)) {
21. return lastNameComparator;
22. } else if ("fullName".equalsIgnoreCase(compareType)) {
23. return fullNameComparator;
24. } else if ("idCardNoNo".equalsIgnoreCase(compareType)) {
25. return idCardNoNoComparator;
26. } else if ("nationality".equalsIgnoreCase(compareType)) {
27. return nationalityComparator;
28. } else {
29. return null;
30. }
31. }
32.
33. public static class IdComparator implements Comparator<Contact> {
34. public int compare(Contact c1, Contact c2) {
35. if (c1 == null && c2 == null) {
36. return 0;
37. } else if (c1 == null && c2 != null) {
38. return -1;
39. } else if (c1 != null && c2 == null) {
40. return 1;
41. } else {
42. int id1 = c1.getId();
43. int id2 = c2.getId();
44. return id1 == id2 ? 0 : (id1 < id2 ? -1 : 1);
45. }
46. }
47. }
48.
49. public static class FirstNameComparator implements Comparator<Contact> {
50. public int compare(Contact c1, Contact c2) {
51. if (c1 == null && c2 == null) {
52. return 0;
53. } else if (c1 == null && c2 != null) {
54. return -1;
55. } else if (c1 != null && c2 == null) {
56. return 1;
57. } else {
58. String s1 = c1.getFirstName();
59. String s2 = c2.getFirstName();
60.
61. if (s1 == null && s2 == null) {
62. return 0;
63. } else if (s1 == null && s2 != null) {
64. return -1;
65. } else if (s1 != null && s2 == null) {
66. return 1;
67. } else {
68. return collator_Chinese.compare(s1, s2);
69. }
70. }
71. }
72. }
73.
74. public static class LastNameComparator implements Comparator<Contact> {
75. public int compare(Contact c1, Contact c2) {
76. if (c1 == null && c2 == null) {
77. return 0;
78. } else if (c1 == null && c2 != null) {
79. return -1;
80. } else if (c1 != null && c2 == null) {
81. return 1;
82. } else {
83. String s1 = c1.getLastName();
84. String s2 = c2.getLastName();
85.
86. if (s1 == null && s2 == null) {
87. return 0;
88. } else if (s1 == null && s2 != null) {
89. return -1;
90. } else if (s1 != null && s2 == null) {
91. return 1;
92. } else {
93. return collator_Chinese.compare(s1, s2);
94. }
95. }
96. }
97. }
98.
99. public static class FullNameComparator implements Comparator<Contact> {
100. public int compare(Contact c1, Contact c2) {
101. if (c1 == null && c2 == null) {
102. return 0;
103. } else if (c1 == null && c2 != null) {
104. return -1;
105. } else if (c1 != null && c2 == null) {
106. return 1;
107. } else {
108. String s1 = c1.getFullName();
109. String s2 = c2.getFullName();
110.
111. if (s1 == null && s2 == null) {
112. return 0;
113. } else if (s1 == null && s2 != null) {
114. return -1;
115. } else if (s1 != null && s2 == null) {
116. return 1;
117. } else {
118. return collator_Chinese.compare(s1, s2);
119. }
120. }
121. }
122. }
123.
124. public static class IdCardNoComparator implements Comparator<Contact> {
125. public int compare(Contact c1, Contact c2) {
126. if (c1 == null && c2 == null) {
127. return 0;
128. } else if (c1 == null && c2 != null) {
129. return -1;
130. } else if (c1 != null && c2 == null) {
131. return 1;
132. } else {
133. String s1 = c1.getIdCardNo();
134. String s2 = c2.getIdCardNo();
135.
136. if (s1 == null && s2 == null) {
137. return 0;
138. } else if (s1 == null && s2 != null) {
139. return -1;
140. } else if (s1 != null && s2 == null) {
141. return 1;
142. } else {
143. return s1.compareToIgnoreCase(s2);
144. }
145. }
146. }
147. }
148.
149. public static class NationalityComparator implements Comparator<Contact> {
150. public int compare(Contact c1, Contact c2) {
151. if (c1 == null && c2 == null) {
152. return 0;
153. } else if (c1 == null && c2 != null) {
154. return -1;
155. } else if (c1 != null && c2 == null) {
156. return 1;
157. } else {
158. String s1 = c1.getNationality();
159. String s2 = c2.getNationality();
160.
161. if (s1 == null && s2 == null) {
162. return 0;
163. } else if (s1 == null && s2 != null) {
164. return -1;
165. } else if (s1 != null && s2 == null) {
166. return 1;
167. } else {
168. return collator_Chinese.compare(s1, s2);
169. }
170. }
171. }
172. }
173.
174.
175.}
package cn.gengv.struts2ex.jqGrid;
import java.text.Collator;
import java.util.Comparator;
import com.byzl.hare.model.Contact;
public class ContactComparatorFactory {
private static Collator collator_Chinese = Collator.getInstance(java.util.Locale.CHINA);
private final static Comparator<Contact> idComparator = new IdComparator();
private final static Comparator<Contact> firstNameComparator = new FirstNameComparator();
private final static Comparator<Contact> lastNameComparator = new LastNameComparator();
private final static Comparator<Contact> fullNameComparator = new FullNameComparator();
private final static Comparator<Contact> idCardNoNoComparator = new IdCardNoComparator();
private final static Comparator<Contact> nationalityComparator = new NationalityComparator();
public static Comparator<Contact> getComparator(String compareType) {
if ("id".equalsIgnoreCase(compareType)) {
return idComparator;
} else if ("firstName".equalsIgnoreCase(compareType)) {
return firstNameComparator;
} else if ("lastName".equalsIgnoreCase(compareType)) {
return lastNameComparator;
} else if ("fullName".equalsIgnoreCase(compareType)) {
return fullNameComparator;
} else if ("idCardNoNo".equalsIgnoreCase(compareType)) {
return idCardNoNoComparator;
} else if ("nationality".equalsIgnoreCase(compareType)) {
return nationalityComparator;
} else {
return null;
}
}
public static class IdComparator implements Comparator<Contact> {
public int compare(Contact c1, Contact c2) {
if (c1 == null && c2 == null) {
return 0;
} else if (c1 == null && c2 != null) {
return -1;
} else if (c1 != null && c2 == null) {
return 1;
} else {
int id1 = c1.getId();
int id2 = c2.getId();
return id1 == id2 ? 0 : (id1 < id2 ? -1 : 1);
}
}
}
public static class FirstNameComparator implements Comparator<Contact> {
public int compare(Contact c1, Contact c2) {
if (c1 == null && c2 == null) {
return 0;
} else if (c1 == null && c2 != null) {
return -1;
} else if (c1 != null && c2 == null) {
return 1;
} else {
String s1 = c1.getFirstName();
String s2 = c2.getFirstName();
if (s1 == null && s2 == null) {
return 0;
} else if (s1 == null && s2 != null) {
return -1;
} else if (s1 != null && s2 == null) {
return 1;
} else {
return collator_Chinese.compare(s1, s2);
}
}
}
}
public static class LastNameComparator implements Comparator<Contact> {
public int compare(Contact c1, Contact c2) {
if (c1 == null && c2 == null) {
return 0;
} else if (c1 == null && c2 != null) {
return -1;
} else if (c1 != null && c2 == null) {
return 1;
} else {
String s1 = c1.getLastName();
String s2 = c2.getLastName();
if (s1 == null && s2 == null) {
return 0;
} else if (s1 == null && s2 != null) {
return -1;
} else if (s1 != null && s2 == null) {
return 1;
} else {
return collator_Chinese.compare(s1, s2);
}
}
}
}
public static class FullNameComparator implements Comparator<Contact> {
public int compare(Contact c1, Contact c2) {
if (c1 == null && c2 == null) {
return 0;
} else if (c1 == null && c2 != null) {
return -1;
} else if (c1 != null && c2 == null) {
return 1;
} else {
String s1 = c1.getFullName();
String s2 = c2.getFullName();
if (s1 == null && s2 == null) {
return 0;
} else if (s1 == null && s2 != null) {
return -1;
} else if (s1 != null && s2 == null) {
return 1;
} else {
return collator_Chinese.compare(s1, s2);
}
}
}
}
public static class IdCardNoComparator implements Comparator<Contact> {
public int compare(Contact c1, Contact c2) {
if (c1 == null && c2 == null) {
return 0;
} else if (c1 == null && c2 != null) {
return -1;
} else if (c1 != null && c2 == null) {
return 1;
} else {
String s1 = c1.getIdCardNo();
String s2 = c2.getIdCardNo();
if (s1 == null && s2 == null) {
return 0;
} else if (s1 == null && s2 != null) {
return -1;
} else if (s1 != null && s2 == null) {
return 1;
} else {
return s1.compareToIgnoreCase(s2);
}
}
}
}
public static class NationalityComparator implements Comparator<Contact> {
public int compare(Contact c1, Contact c2) {
if (c1 == null && c2 == null) {
return 0;
} else if (c1 == null && c2 != null) {
return -1;
} else if (c1 != null && c2 == null) {
return 1;
} else {
String s1 = c1.getNationality();
String s2 = c2.getNationality();
if (s1 == null && s2 == null) {
return 0;
} else if (s1 == null && s2 != null) {
return -1;
} else if (s1 != null && s2 == null) {
return 1;
} else {
return collator_Chinese.compare(s1, s2);
}
}
}
}
}
然后再来看JqGridBaseAction,其中添加了一个抽象方法,用来将数据结果进行排序。
view plaincopy to clipboardprint?
01.package cn.gengv.struts2ex.jqGrid;
02.
03.// import ...
04.
05.@SuppressWarnings("serial")
06.public abstract class JqGridBaseAction<T> extends ActionSupport {
07. ...
08.
09. // (1)添加排序方法
10. public abstract void sortResults(List<T> results, String field, String order);
11.
12. public String refreshGridModel() {
13. try {
14. List<Criterion> criteria = Collections.emptyList();
15.
16. if(search == true) {
17. criteria = new ArrayList<Criterion>();
18.
19. if(filters != null && filters.length()>0) {
20. criteria.addAll(this.generateSearchCriteriaFromFilters(filters));
21. }
22.
23. Criterion criterion = this.generateSearchCriterion(searchField, searchString, searchOper);
24. if(criterion != null) {
25. criteria.add(criterion);
26. }
27. }
28.
29. List<T> results = Collections.emptyList();
30.
31.
32. int from = rows * (page - 1);
33. int length = rows;
34.
35. if(loadonce) {
36. from = 0;
37. length = 100;
38. }
39.
40. if(!criteria.isEmpty()) {
41. record = this.getResultSize(criteria);
42. results = this.listResults(criteria, from, length);
43.
44. } else {
45. record = this.getResultSize();
46. results = this.listResults(from, length);
47.
48. }
49.
50. // (2)将结果排序
51. if(sidx != null && sord != null) {
52. sortResults(results, sidx, sord);
53. }
54.
55. this.setGridModel(results);
56. total = (int) Math.ceil((double) record / (double) rows);
57. return SUCCESS;
58. } catch (Exception e) {
59. e.printStackTrace();
60. this.addActionError(e.getMessage());
61. return ERROR;
62. }
63. }
64.
65. ...
66.}
package cn.gengv.struts2ex.jqGrid;
// import ...
@SuppressWarnings("serial")
public abstract class JqGridBaseAction<T> extends ActionSupport {
...
// (1)添加排序方法
public abstract void sortResults(List<T> results, String field, String order);
public String refreshGridModel() {
try {
List<Criterion> criteria = Collections.emptyList();
if(search == true) {
criteria = new ArrayList<Criterion>();
if(filters != null && filters.length()>0) {
criteria.addAll(this.generateSearchCriteriaFromFilters(filters));
}
Criterion criterion = this.generateSearchCriterion(searchField, searchString, searchOper);
if(criterion != null) {
criteria.add(criterion);
}
}
List<T> results = Collections.emptyList();
int from = rows * (page - 1);
int length = rows;
if(loadonce) {
from = 0;
length = 100;
}
if(!criteria.isEmpty()) {
record = this.getResultSize(criteria);
results = this.listResults(criteria, from, length);
} else {
record = this.getResultSize();
results = this.listResults(from, length);
}
// (2)将结果排序
if(sidx != null && sord != null) {
sortResults(results, sidx, sord);
}
this.setGridModel(results);
total = (int) Math.ceil((double) record / (double) rows);
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
this.addActionError(e.getMessage());
return ERROR;
}
}
...
}
而在ListContactsAction中提供了方法实现:
view plaincopy to clipboardprint?
01.package cn.gengv.struts2ex.jqGrid;
02.
03.import java.util.Collections;
04.import java.util.Comparator;
05.import java.util.List;
06.import com.byzl.hare.dao.impl.Criterion;
07.import com.byzl.hare.model.Contact;
08.import com.byzl.hare.service.ContactService;
09.
10.@SuppressWarnings("serial")
11.public class ListContactsAction extends JqGridBaseAction<Contact> {
12.
13. ...
14.
15. @Override
16. public void sortResults(List<Contact> results, String field, String order) {
17. // (1)根据field获得对应的Comparator
18. Comparator<Contact> comparator = ContactComparatorFactory.getComparator(field);
19.
20. if(comparator != null) {
21. // (2)使用Comparator排序
22. Collections.sort(results, comparator);
23.
24. // (3)如果需要的排序顺序为desc,则颠倒顺序
25. if("desc".equals(order)) {
26. Collections.reverse(results);
27. }
28. }
29.
30. }
31.
32. ...
33.}
package cn.gengv.struts2ex.jqGrid;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.byzl.hare.dao.impl.Criterion;
import com.byzl.hare.model.Contact;
import com.byzl.hare.service.ContactService;
@SuppressWarnings("serial")
public class ListContactsAction extends JqGridBaseAction<Contact> {
...
@Override
public void sortResults(List<Contact> results, String field, String order) {
// (1)根据field获得对应的Comparator
Comparator<Contact> comparator = ContactComparatorFactory.getComparator(field);
if(comparator != null) {
// (2)使用Comparator排序
Collections.sort(results, comparator);
// (3)如果需要的排序顺序为desc,则颠倒顺序
if("desc".equals(order)) {
Collections.reverse(results);
}
}
}
...
}
不过这个例子存在一定的局限性,即只能将当前页中的数据根据某列进行排序;而不能跨页间进行数据排序。之所以存在这种局限,也是源于实际应用中的客观限制。还以这个例子来说,数据库里总共模拟了两万多条数据记录。如果每次要将这些记录进行排里的话,除非有数据库索引支持,否则所要消耗的时间也是相当客观的,对于用户体验来说,几乎就是灾难。如果数据量更多的话,结果可想而知。
因此,我们应该换一个角度来看这个问题,用户之所以使用排序,更多的目的还是在于查找数据方便,既然我们可以提供条件查询(尤其是复杂条件查询),那么用户对于排序的需求也就不会那么迫切了。同时也可以体会到,排序更多地应用在少量数据的场合下