終於講到排序了,這一部分應該說還是比較好理解的。
jqGrid通過colModel選項中的sortable來控制是否可以以某列的值排序。sortable的預設值是true,當設為false時,即此列不能用於排序。
$(function(){<br />$("#gridTable").jqGrid({</p><p>...</p><p>colModel: [<br /> {name:"id",index:"id",label:"編碼",width:40},<br /> {name:"lastName",index:"lastName",label:"姓",width:80},<br /> {name:"firstName",index:"firstName",label:"名",width:80},<br /> {name:"email",index:"email",label:"電子郵箱",width:160,sortable:false},<br /> {name:"telNo",index:"telNo",label:"電話",width:120,sortable:false}<br />],</p><p>...</p><p>});<br />});
當點擊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的代碼:
package cn.gengv.struts2ex.jqGrid;<br />import java.text.Collator;<br />import java.util.Comparator;<br />import com.byzl.hare.model.Contact;<br />public class ContactComparatorFactory {<br />private static Collator collator_Chinese = Collator.getInstance(java.util.Locale.CHINA);<br />private final static Comparator<Contact> idComparator = new IdComparator();<br />private final static Comparator<Contact> firstNameComparator = new FirstNameComparator();<br />private final static Comparator<Contact> lastNameComparator = new LastNameComparator();<br />private final static Comparator<Contact> fullNameComparator = new FullNameComparator();<br />private final static Comparator<Contact> idCardNoNoComparator = new IdCardNoComparator();<br />private final static Comparator<Contact> nationalityComparator = new NationalityComparator();</p><p>public static Comparator<Contact> getComparator(String compareType) {<br />if ("id".equalsIgnoreCase(compareType)) {<br />return idComparator;<br />} else if ("firstName".equalsIgnoreCase(compareType)) {<br />return firstNameComparator;<br />} else if ("lastName".equalsIgnoreCase(compareType)) {<br />return lastNameComparator;<br />} else if ("fullName".equalsIgnoreCase(compareType)) {<br />return fullNameComparator;<br />} else if ("idCardNoNo".equalsIgnoreCase(compareType)) {<br />return idCardNoNoComparator;<br />} else if ("nationality".equalsIgnoreCase(compareType)) {<br />return nationalityComparator;<br />} else {<br />return null;<br />}<br />}</p><p>public static class IdComparator implements Comparator<Contact> {<br />public int compare(Contact c1, Contact c2) {<br />if (c1 == null && c2 == null) {<br />return 0;<br />} else if (c1 == null && c2 != null) {<br />return -1;<br />} else if (c1 != null && c2 == null) {<br />return 1;<br />} else {<br />int id1 = c1.getId();<br />int id2 = c2.getId();<br />return id1 == id2 ? 0 : (id1 < id2 ? -1 : 1);<br />}<br />}<br />}</p><p>public static class FirstNameComparator implements Comparator<Contact> {<br />public int compare(Contact c1, Contact c2) {<br />if (c1 == null && c2 == null) {<br />return 0;<br />} else if (c1 == null && c2 != null) {<br />return -1;<br />} else if (c1 != null && c2 == null) {<br />return 1;<br />} else {<br />String s1 = c1.getFirstName();<br />String s2 = c2.getFirstName();</p><p>if (s1 == null && s2 == null) {<br />return 0;<br />} else if (s1 == null && s2 != null) {<br />return -1;<br />} else if (s1 != null && s2 == null) {<br />return 1;<br />} else {<br />return collator_Chinese.compare(s1, s2);<br />}<br />}<br />}<br />}</p><p>public static class LastNameComparator implements Comparator<Contact> {<br />public int compare(Contact c1, Contact c2) {<br />if (c1 == null && c2 == null) {<br />return 0;<br />} else if (c1 == null && c2 != null) {<br />return -1;<br />} else if (c1 != null && c2 == null) {<br />return 1;<br />} else {<br />String s1 = c1.getLastName();<br />String s2 = c2.getLastName();</p><p>if (s1 == null && s2 == null) {<br />return 0;<br />} else if (s1 == null && s2 != null) {<br />return -1;<br />} else if (s1 != null && s2 == null) {<br />return 1;<br />} else {<br />return collator_Chinese.compare(s1, s2);<br />}<br />}<br />}<br />}</p><p>public static class FullNameComparator implements Comparator<Contact> {<br />public int compare(Contact c1, Contact c2) {<br />if (c1 == null && c2 == null) {<br />return 0;<br />} else if (c1 == null && c2 != null) {<br />return -1;<br />} else if (c1 != null && c2 == null) {<br />return 1;<br />} else {<br />String s1 = c1.getFullName();<br />String s2 = c2.getFullName();</p><p>if (s1 == null && s2 == null) {<br />return 0;<br />} else if (s1 == null && s2 != null) {<br />return -1;<br />} else if (s1 != null && s2 == null) {<br />return 1;<br />} else {<br />return collator_Chinese.compare(s1, s2);<br />}<br />}<br />}<br />}</p><p>public static class IdCardNoComparator implements Comparator<Contact> {<br />public int compare(Contact c1, Contact c2) {<br />if (c1 == null && c2 == null) {<br />return 0;<br />} else if (c1 == null && c2 != null) {<br />return -1;<br />} else if (c1 != null && c2 == null) {<br />return 1;<br />} else {<br />String s1 = c1.getIdCardNo();<br />String s2 = c2.getIdCardNo();</p><p>if (s1 == null && s2 == null) {<br />return 0;<br />} else if (s1 == null && s2 != null) {<br />return -1;<br />} else if (s1 != null && s2 == null) {<br />return 1;<br />} else {<br />return s1.compareToIgnoreCase(s2);<br />}<br />}<br />}<br />}</p><p>public static class NationalityComparator implements Comparator<Contact> {<br />public int compare(Contact c1, Contact c2) {<br />if (c1 == null && c2 == null) {<br />return 0;<br />} else if (c1 == null && c2 != null) {<br />return -1;<br />} else if (c1 != null && c2 == null) {<br />return 1;<br />} else {<br />String s1 = c1.getNationality();<br />String s2 = c2.getNationality();</p><p>if (s1 == null && s2 == null) {<br />return 0;<br />} else if (s1 == null && s2 != null) {<br />return -1;<br />} else if (s1 != null && s2 == null) {<br />return 1;<br />} else {<br />return collator_Chinese.compare(s1, s2);<br />}<br />}<br />}<br />}</p><p>}
然後再來看JqGridBaseAction,其中添加了一個抽象方法,用來將資料結果進行排序。
package cn.gengv.struts2ex.jqGrid;</p><p>// import ...</p><p>@SuppressWarnings("serial")<br />public abstract class JqGridBaseAction<T> extends ActionSupport {<br />...</p><p>// (1)添加排序方法<br />public abstract void sortResults(List<T> results, String field, String order);</p><p>public String refreshGridModel() {<br />try {<br />List<Criterion> criteria = Collections.emptyList();</p><p>if(search == true) {<br />criteria = new ArrayList<Criterion>();</p><p>if(filters != null && filters.length()>0) {<br />criteria.addAll(this.generateSearchCriteriaFromFilters(filters));<br />}</p><p>Criterion criterion = this.generateSearchCriterion(searchField, searchString, searchOper);<br />if(criterion != null) {<br />criteria.add(criterion);<br />}<br />}</p><p>List<T> results = Collections.emptyList();</p><p>int from = rows * (page - 1);<br />int length = rows; </p><p>if(loadonce) {<br />from = 0;<br />length = 100;<br />}</p><p>if(!criteria.isEmpty()) {<br />record = this.getResultSize(criteria);<br />results = this.listResults(criteria, from, length);</p><p>} else {<br />record = this.getResultSize();<br />results = this.listResults(from, length);</p><p>}</p><p>// (2)將結果排序<br />if(sidx != null && sord != null) {<br />sortResults(results, sidx, sord);<br />}</p><p>this.setGridModel(results);<br />total = (int) Math.ceil((double) record / (double) rows);<br />return SUCCESS;<br />} catch (Exception e) {<br />e.printStackTrace();<br />this.addActionError(e.getMessage());<br />return ERROR;<br />}<br />}</p><p>...<br />}
而在ListContactsAction中提供了方法實現:
package cn.gengv.struts2ex.jqGrid;</p><p>import java.util.Collections;<br />import java.util.Comparator;<br />import java.util.List;<br />import com.byzl.hare.dao.impl.Criterion;<br />import com.byzl.hare.model.Contact;<br />import com.byzl.hare.service.ContactService;</p><p>@SuppressWarnings("serial")<br />public class ListContactsAction extends JqGridBaseAction<Contact> {</p><p>...</p><p>@Override<br />public void sortResults(List<Contact> results, String field, String order) {<br />// (1)根據field獲得對應的Comparator<br />Comparator<Contact> comparator = ContactComparatorFactory.getComparator(field);</p><p>if(comparator != null) {<br />// (2)使用Comparator排序<br />Collections.sort(results, comparator);</p><p>// (3)如果需要的排序次序為desc,則顛倒順序<br />if("desc".equals(order)) {<br />Collections.reverse(results);<br />}<br />}</p><p>}</p><p>...<br />}
不過這個例子存在一定的局限性,即只能將當前頁中的資料根據某列進行排序;而不能跨頁間進行資料排序。之所以存在這種局限,也是源於實際應用中的客觀限制。還以這個例子來說,資料庫裡總共類比了兩萬多條資料記錄。如果每次要將這些記錄進行排裡的話,除非有資料庫索引支援,否則所要消耗的時間也是相當客觀的,對於使用者體驗來說,幾乎就是災難。如果資料量更多的話,結果可想而知。
因此,我們應該換一個角度來看這個問題,使用者之所以使用排序,更多的目的還是在於尋找資料方便,既然我們可以提供條件查詢(尤其是複雜條件查詢),那麼使用者對於排序的需求也就不會那麼迫切了。同時也可以體會到,排序更多地應用在少量資料的場合下。