`

jqGrid与Struts2的结合应用(七) —— 浅谈排序

 
阅读更多

终于讲到排序了,这一部分应该说还是比较好理解的。

jqGrid通过colModel选项中的sortable来控制是否可以以某列的值排序。sortable的默认值是true,当设为false时,即此列不能用于排序。

[javascript] view plaincopyprint?
  1. $(function(){
  2. $("#gridTable").jqGrid({
  3. ...
  4. colModel:[
  5. {name:"id",index:"id",label:"编码",width:40},
  6. {name:"lastName",index:"lastName",label:"姓",width:80},
  7. {name:"firstName",index:"firstName",label:"名",width:80},
  8. {name:"email",index:"email",label:"电子邮箱",width:160,sortable:false},
  9. {name:"telNo",index:"telNo",label:"电话",width:120,sortable:false}
  10. ],
  11. ...
  12. });
  13. });


当点击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的代码:

  1. packagecn.gengv.struts2ex.jqGrid;
  2. importjava.text.Collator;
  3. importjava.util.Comparator;
  4. importcom.byzl.hare.model.Contact;
  5. publicclassContactComparatorFactory{
  6. privatestaticCollatorcollator_Chinese=Collator.getInstance(java.util.Locale.CHINA);
  7. privatefinalstaticComparator<Contact>idComparator=newIdComparator();
  8. privatefinalstaticComparator<Contact>firstNameComparator=newFirstNameComparator();
  9. privatefinalstaticComparator<Contact>lastNameComparator=newLastNameComparator();
  10. privatefinalstaticComparator<Contact>fullNameComparator=newFullNameComparator();
  11. privatefinalstaticComparator<Contact>idCardNoNoComparator=newIdCardNoComparator();
  12. privatefinalstaticComparator<Contact>nationalityComparator=newNationalityComparator();
  13. publicstaticComparator<Contact>getComparator(StringcompareType){
  14. if("id".equalsIgnoreCase(compareType)){
  15. returnidComparator;
  16. }elseif("firstName".equalsIgnoreCase(compareType)){
  17. returnfirstNameComparator;
  18. }elseif("lastName".equalsIgnoreCase(compareType)){
  19. returnlastNameComparator;
  20. }elseif("fullName".equalsIgnoreCase(compareType)){
  21. returnfullNameComparator;
  22. }elseif("idCardNoNo".equalsIgnoreCase(compareType)){
  23. returnidCardNoNoComparator;
  24. }elseif("nationality".equalsIgnoreCase(compareType)){
  25. returnnationalityComparator;
  26. }else{
  27. returnnull;
  28. }
  29. }
  30. publicstaticclassIdComparatorimplementsComparator<Contact>{
  31. publicintcompare(Contactc1,Contactc2){
  32. if(c1==null&&c2==null){
  33. return0;
  34. }elseif(c1==null&&c2!=null){
  35. return-1;
  36. }elseif(c1!=null&&c2==null){
  37. return1;
  38. }else{
  39. intid1=c1.getId();
  40. intid2=c2.getId();
  41. returnid1==id2?0:(id1<id2?-1:1);
  42. }
  43. }
  44. }
  45. publicstaticclassFirstNameComparatorimplementsComparator<Contact>{
  46. publicintcompare(Contactc1,Contactc2){
  47. if(c1==null&&c2==null){
  48. return0;
  49. }elseif(c1==null&&c2!=null){
  50. return-1;
  51. }elseif(c1!=null&&c2==null){
  52. return1;
  53. }else{
  54. Strings1=c1.getFirstName();
  55. Strings2=c2.getFirstName();
  56. if(s1==null&&s2==null){
  57. return0;
  58. }elseif(s1==null&&s2!=null){
  59. return-1;
  60. }elseif(s1!=null&&s2==null){
  61. return1;
  62. }else{
  63. returncollator_Chinese.compare(s1,s2);
  64. }
  65. }
  66. }
  67. }
  68. publicstaticclassLastNameComparatorimplementsComparator<Contact>{
  69. publicintcompare(Contactc1,Contactc2){
  70. if(c1==null&&c2==null){
  71. return0;
  72. }elseif(c1==null&&c2!=null){
  73. return-1;
  74. }elseif(c1!=null&&c2==null){
  75. return1;
  76. }else{
  77. Strings1=c1.getLastName();
  78. Strings2=c2.getLastName();
  79. if(s1==null&&s2==null){
  80. return0;
  81. }elseif(s1==null&&s2!=null){
  82. return-1;
  83. }elseif(s1!=null&&s2==null){
  84. return1;
  85. }else{
  86. returncollator_Chinese.compare(s1,s2);
  87. }
  88. }
  89. }
  90. }
  91. publicstaticclassFullNameComparatorimplementsComparator<Contact>{
  92. publicintcompare(Contactc1,Contactc2){
  93. if(c1==null&&c2==null){
  94. return0;
  95. }elseif(c1==null&&c2!=null){
  96. return-1;
  97. }elseif(c1!=null&&c2==null){
  98. return1;
  99. }else{
  100. Strings1=c1.getFullName();
  101. Strings2=c2.getFullName();
  102. if(s1==null&&s2==null){
  103. return0;
  104. }elseif(s1==null&&s2!=null){
  105. return-1;
  106. }elseif(s1!=null&&s2==null){
  107. return1;
  108. }else{
  109. returncollator_Chinese.compare(s1,s2);
  110. }
  111. }
  112. }
  113. }
  114. publicstaticclassIdCardNoComparatorimplementsComparator<Contact>{
  115. publicintcompare(Contactc1,Contactc2){
  116. if(c1==null&&c2==null){
  117. return0;
  118. }elseif(c1==null&&c2!=null){
  119. return-1;
  120. }elseif(c1!=null&&c2==null){
  121. return1;
  122. }else{
  123. Strings1=c1.getIdCardNo();
  124. Strings2=c2.getIdCardNo();
  125. if(s1==null&&s2==null){
  126. return0;
  127. }elseif(s1==null&&s2!=null){
  128. return-1;
  129. }elseif(s1!=null&&s2==null){
  130. return1;
  131. }else{
  132. returns1.compareToIgnoreCase(s2);
  133. }
  134. }
  135. }
  136. }
  137. publicstaticclassNationalityComparatorimplementsComparator<Contact>{
  138. publicintcompare(Contactc1,Contactc2){
  139. if(c1==null&&c2==null){
  140. return0;
  141. }elseif(c1==null&&c2!=null){
  142. return-1;
  143. }elseif(c1!=null&&c2==null){
  144. return1;
  145. }else{
  146. Strings1=c1.getNationality();
  147. Strings2=c2.getNationality();
  148. if(s1==null&&s2==null){
  149. return0;
  150. }elseif(s1==null&&s2!=null){
  151. return-1;
  152. }elseif(s1!=null&&s2==null){
  153. return1;
  154. }else{
  155. returncollator_Chinese.compare(s1,s2);
  156. }
  157. }
  158. }
  159. }
  160. }


然后再来看JqGridBaseAction,其中添加了一个抽象方法,用来将数据结果进行排序。

  1. packagecn.gengv.struts2ex.jqGrid;
  2. //import...
  3. @SuppressWarnings("serial")
  4. publicabstractclassJqGridBaseAction<T>extendsActionSupport{
  5. ...
  6. //(1)添加排序方法
  7. publicabstractvoidsortResults(List<T>results,Stringfield,Stringorder);
  8. publicStringrefreshGridModel(){
  9. try{
  10. List<Criterion>criteria=Collections.emptyList();
  11. if(search==true){
  12. criteria=newArrayList<Criterion>();
  13. if(filters!=null&&filters.length()>0){
  14. criteria.addAll(this.generateSearchCriteriaFromFilters(filters));
  15. }
  16. Criterioncriterion=this.generateSearchCriterion(searchField,searchString,searchOper);
  17. if(criterion!=null){
  18. criteria.add(criterion);
  19. }
  20. }
  21. List<T>results=Collections.emptyList();
  22. intfrom=rows*(page-1);
  23. intlength=rows;
  24. if(loadonce){
  25. from=0;
  26. length=100;
  27. }
  28. if(!criteria.isEmpty()){
  29. record=this.getResultSize(criteria);
  30. results=this.listResults(criteria,from,length);
  31. }else{
  32. record=this.getResultSize();
  33. results=this.listResults(from,length);
  34. }
  35. //(2)将结果排序
  36. if(sidx!=null&&sord!=null){
  37. sortResults(results,sidx,sord);
  38. }
  39. this.setGridModel(results);
  40. total=(int)Math.ceil((double)record/(double)rows);
  41. returnSUCCESS;
  42. }catch(Exceptione){
  43. e.printStackTrace();
  44. this.addActionError(e.getMessage());
  45. returnERROR;
  46. }
  47. }
  48. ...
  49. }


而在ListContactsAction中提供了方法实现:

  1. packagecn.gengv.struts2ex.jqGrid;
  2. importjava.util.Collections;
  3. importjava.util.Comparator;
  4. importjava.util.List;
  5. importcom.byzl.hare.dao.impl.Criterion;
  6. importcom.byzl.hare.model.Contact;
  7. importcom.byzl.hare.service.ContactService;
  8. @SuppressWarnings("serial")
  9. publicclassListContactsActionextendsJqGridBaseAction<Contact>{
  10. ...
  11. @Override
  12. publicvoidsortResults(List<Contact>results,Stringfield,Stringorder){
  13. //(1)根据field获得对应的Comparator
  14. Comparator<Contact>comparator=ContactComparatorFactory.getComparator(field);
  15. if(comparator!=null){
  16. //(2)使用Comparator排序
  17. Collections.sort(results,comparator);
  18. //(3)如果需要的排序顺序为desc,则颠倒顺序
  19. if("desc".equals(order)){
  20. Collections.reverse(results);
  21. }
  22. }
  23. }
  24. ...
  25. }


不过这个例子存在一定的局限性,即只能将当前页中的数据根据某列进行排序;而不能跨页间进行数据排序。之所以存在这种局限,也是源于实际应用中的客观限制。还以这个例子来说,数据库里总共模拟了两万多条数据记录。如果每次要将这些记录进行排里的话,除非有数据库索引支持,否则所要消耗的时间也是相当客观的,对于用户体验来说,几乎就是灾难。如果数据量更多的话,结果可想而知。

因此,我们应该换一个角度来看这个问题,用户之所以使用排序,更多的目的还是在于查找数据方便,既然我们可以提供条件查询(尤其是复杂条件查询),那么用户对于排序的需求也就不会那么迫切了。同时也可以体会到,排序更多地应用在少量数据的场合下。

终于讲到排序了,这一部分应该说还是比较好理解的。

jqGrid通过colModel选项中的sortable来控制是否可以以某列的值排序。sortable的默认值是true,当设为false时,即此列不能用于排序。

[javascript] view plaincopyprint?
  1. $(function(){
  2. $("#gridTable").jqGrid({
  3. ...
  4. colModel:[
  5. {name:"id",index:"id",label:"编码",width:40},
  6. {name:"lastName",index:"lastName",label:"姓",width:80},
  7. {name:"firstName",index:"firstName",label:"名",width:80},
  8. {name:"email",index:"email",label:"电子邮箱",width:160,sortable:false},
  9. {name:"telNo",index:"telNo",label:"电话",width:120,sortable:false}
  10. ],
  11. ...
  12. });
  13. });


当点击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的代码:

  1. packagecn.gengv.struts2ex.jqGrid;
  2. importjava.text.Collator;
  3. importjava.util.Comparator;
  4. importcom.byzl.hare.model.Contact;
  5. publicclassContactComparatorFactory{
  6. privatestaticCollatorcollator_Chinese=Collator.getInstance(java.util.Locale.CHINA);
  7. privatefinalstaticComparator<Contact>idComparator=newIdComparator();
  8. privatefinalstaticComparator<Contact>firstNameComparator=newFirstNameComparator();
  9. privatefinalstaticComparator<Contact>lastNameComparator=newLastNameComparator();
  10. privatefinalstaticComparator<Contact>fullNameComparator=newFullNameComparator();
  11. privatefinalstaticComparator<Contact>idCardNoNoComparator=newIdCardNoComparator();
  12. privatefinalstaticComparator<Contact>nationalityComparator=newNationalityComparator();
  13. publicstaticComparator<Contact>getComparator(StringcompareType){
  14. if("id".equalsIgnoreCase(compareType)){
  15. returnidComparator;
  16. }elseif("firstName".equalsIgnoreCase(compareType)){
  17. returnfirstNameComparator;
  18. }elseif("lastName".equalsIgnoreCase(compareType)){
  19. returnlastNameComparator;
  20. }elseif("fullName".equalsIgnoreCase(compareType)){
  21. returnfullNameComparator;
  22. }elseif("idCardNoNo".equalsIgnoreCase(compareType)){
  23. returnidCardNoNoComparator;
  24. }elseif("nationality".equalsIgnoreCase(compareType)){
  25. returnnationalityComparator;
  26. }else{
  27. returnnull;
  28. }
  29. }
  30. publicstaticclassIdComparatorimplementsComparator<Contact>{
  31. publicintcompare(Contactc1,Contactc2){
  32. if(c1==null&&c2==null){
  33. return0;
  34. }elseif(c1==null&&c2!=null){
  35. return-1;
  36. }elseif(c1!=null&&c2==null){
  37. return1;
  38. }else{
  39. intid1=c1.getId();
  40. intid2=c2.getId();
  41. returnid1==id2?0:(id1<id2?-1:1);
  42. }
  43. }
  44. }
  45. publicstaticclassFirstNameComparatorimplementsComparator<Contact>{
  46. publicintcompare(Contactc1,Contactc2){
  47. if(c1==null&&c2==null){
  48. return0;
  49. }elseif(c1==null&&c2!=null){
  50. return-1;
  51. }elseif(c1!=null&&c2==null){
  52. return1;
  53. }else{
  54. Strings1=c1.getFirstName();
  55. Strings2=c2.getFirstName();
  56. if(s1==null&&s2==null){
  57. return0;
  58. }elseif(s1==null&&s2!=null){
  59. return-1;
  60. }elseif(s1!=null&&s2==null){
  61. return1;
  62. }else{
  63. returncollator_Chinese.compare(s1,s2);
  64. }
  65. }
  66. }
  67. }
  68. publicstaticclassLastNameComparatorimplementsComparator<Contact>{
  69. publicintcompare(Contactc1,Contactc2){
  70. if(c1==null&&c2==null){
  71. return0;
  72. }elseif(c1==null&&c2!=null){
  73. return-1;
  74. }elseif(c1!=null&&c2==null){
  75. return1;
  76. }else{
  77. Strings1=c1.getLastName();
  78. Strings2=c2.getLastName();
  79. if(s1==null&&s2==null){
  80. return0;
  81. }elseif(s1==null&&s2!=null){
  82. return-1;
  83. }elseif(s1!=null&&s2==null){
  84. return1;
  85. }else{
  86. returncollator_Chinese.compare(s1,s2);
  87. }
  88. }
  89. }
  90. }
  91. publicstaticclassFullNameComparatorimplementsComparator<Contact>{
  92. publicintcompare(Contactc1,Contactc2){
  93. if(c1==null&&c2==null){
  94. return0;
  95. }elseif(c1==null&&c2!=null){
  96. return-1;
  97. }elseif(c1!=null&&c2==null){
  98. return1;
  99. }else{
  100. Strings1=c1.getFullName();
  101. Strings2=c2.getFullName();
  102. if(s1==null&&s2==null){
  103. return0;
  104. }elseif(s1==null&&s2!=null){
  105. return-1;
  106. }elseif(s1!=null&&s2==null){
  107. return1;
  108. }else{
  109. returncollator_Chinese.compare(s1,s2);
  110. }
  111. }
  112. }
  113. }
  114. publicstaticclassIdCardNoComparatorimplementsComparator<Contact>{
  115. publicintcompare(Contactc1,Contactc2){
  116. if(c1==null&&c2==null){
  117. return0;
  118. }elseif(c1==null&&c2!=null){
  119. return-1;
  120. }elseif(c1!=null&&c2==null){
  121. return1;
  122. }else{
  123. Strings1=c1.getIdCardNo();
  124. Strings2=c2.getIdCardNo();
  125. if(s1==null&&s2==null){
  126. return0;
  127. }elseif(s1==null&&s2!=null){
  128. return-1;
  129. }elseif(s1!=null&&s2==null){
  130. return1;
  131. }else{
  132. returns1.compareToIgnoreCase(s2);
  133. }
  134. }
  135. }
  136. }
  137. publicstaticclassNationalityComparatorimplementsComparator<Contact>{
  138. publicintcompare(Contactc1,Contactc2){
  139. if(c1==null&&c2==null){
  140. return0;
  141. }elseif(c1==null&&c2!=null){
  142. return-1;
  143. }elseif(c1!=null&&c2==null){
  144. return1;
  145. }else{
  146. Strings1=c1.getNationality();
  147. Strings2=c2.getNationality();
  148. if(s1==null&&s2==null){
  149. return0;
  150. }elseif(s1==null&&s2!=null){
  151. return-1;
  152. }elseif(s1!=null&&s2==null){
  153. return1;
  154. }else{
  155. returncollator_Chinese.compare(s1,s2);
  156. }
  157. }
  158. }
  159. }
  160. }


然后再来看JqGridBaseAction,其中添加了一个抽象方法,用来将数据结果进行排序。

  1. packagecn.gengv.struts2ex.jqGrid;
  2. //import...
  3. @SuppressWarnings("serial")
  4. publicabstractclassJqGridBaseAction<T>extendsActionSupport{
  5. ...
  6. //(1)添加排序方法
  7. publicabstractvoidsortResults(List<T>results,Stringfield,Stringorder);
  8. publicStringrefreshGridModel(){
  9. try{
  10. List<Criterion>criteria=Collections.emptyList();
  11. if(search==true){
  12. criteria=newArrayList<Criterion>();
  13. if(filters!=null&&filters.length()>0){
  14. criteria.addAll(this.generateSearchCriteriaFromFilters(filters));
  15. }
  16. Criterioncriterion=this.generateSearchCriterion(searchField,searchString,searchOper);
  17. if(criterion!=null){
  18. criteria.add(criterion);
  19. }
  20. }
  21. List<T>results=Collections.emptyList();
  22. intfrom=rows*(page-1);
  23. intlength=rows;
  24. if(loadonce){
  25. from=0;
  26. length=100;
  27. }
  28. if(!criteria.isEmpty()){
  29. record=this.getResultSize(criteria);
  30. results=this.listResults(criteria,from,length);
  31. }else{
  32. record=this.getResultSize();
  33. results=this.listResults(from,length);
  34. }
  35. //(2)将结果排序
  36. if(sidx!=null&&sord!=null){
  37. sortResults(results,sidx,sord);
  38. }
  39. this.setGridModel(results);
  40. total=(int)Math.ceil((double)record/(double)rows);
  41. returnSUCCESS;
  42. }catch(Exceptione){
  43. e.printStackTrace();
  44. this.addActionError(e.getMessage());
  45. returnERROR;
  46. }
  47. }
  48. ...
  49. }


而在ListContactsAction中提供了方法实现:

  1. packagecn.gengv.struts2ex.jqGrid;
  2. importjava.util.Collections;
  3. importjava.util.Comparator;
  4. importjava.util.List;
  5. importcom.byzl.hare.dao.impl.Criterion;
  6. importcom.byzl.hare.model.Contact;
  7. importcom.byzl.hare.service.ContactService;
  8. @SuppressWarnings("serial")
  9. publicclassListContactsActionextendsJqGridBaseAction<Contact>{
  10. ...
  11. @Override
  12. publicvoidsortResults(List<Contact>results,Stringfield,Stringorder){
  13. //(1)根据field获得对应的Comparator
  14. Comparator<Contact>comparator=ContactComparatorFactory.getComparator(field);
  15. if(comparator!=null){
  16. //(2)使用Comparator排序
  17. Collections.sort(results,comparator);
  18. //(3)如果需要的排序顺序为desc,则颠倒顺序
  19. if("desc".equals(order)){
  20. Collections.reverse(results);
  21. }
  22. }
  23. }
  24. ...
  25. }


不过这个例子存在一定的局限性,即只能将当前页中的数据根据某列进行排序;而不能跨页间进行数据排序。之所以存在这种局限,也是源于实际应用中的客观限制。还以这个例子来说,数据库里总共模拟了两万多条数据记录。如果每次要将这些记录进行排里的话,除非有数据库索引支持,否则所要消耗的时间也是相当客观的,对于用户体验来说,几乎就是灾难。如果数据量更多的话,结果可想而知。

因此,我们应该换一个角度来看这个问题,用户之所以使用排序,更多的目的还是在于查找数据方便,既然我们可以提供条件查询(尤其是复杂条件查询),那么用户对于排序的需求也就不会那么迫切了。同时也可以体会到,排序更多地应用在少量数据的场合下。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics