- 浏览: 69464 次
文章分类
最新评论
jqGrid与Struts2的结合应用(七) —— 浅谈排序
终于讲到排序了,这一部分应该说还是比较好理解的。
jqGrid通过colModel选项中的sortable来控制是否可以以某列的值排序。sortable的默认值是true,当设为false时,即此列不能用于排序。
- $(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的代码:
- packagecn.gengv.struts2ex.jqGrid;
- importjava.text.Collator;
- importjava.util.Comparator;
- importcom.byzl.hare.model.Contact;
- publicclassContactComparatorFactory{
- privatestaticCollatorcollator_Chinese=Collator.getInstance(java.util.Locale.CHINA);
- privatefinalstaticComparator<Contact>idComparator=newIdComparator();
- privatefinalstaticComparator<Contact>firstNameComparator=newFirstNameComparator();
- privatefinalstaticComparator<Contact>lastNameComparator=newLastNameComparator();
- privatefinalstaticComparator<Contact>fullNameComparator=newFullNameComparator();
- privatefinalstaticComparator<Contact>idCardNoNoComparator=newIdCardNoComparator();
- privatefinalstaticComparator<Contact>nationalityComparator=newNationalityComparator();
- publicstaticComparator<Contact>getComparator(StringcompareType){
- if("id".equalsIgnoreCase(compareType)){
- returnidComparator;
- }elseif("firstName".equalsIgnoreCase(compareType)){
- returnfirstNameComparator;
- }elseif("lastName".equalsIgnoreCase(compareType)){
- returnlastNameComparator;
- }elseif("fullName".equalsIgnoreCase(compareType)){
- returnfullNameComparator;
- }elseif("idCardNoNo".equalsIgnoreCase(compareType)){
- returnidCardNoNoComparator;
- }elseif("nationality".equalsIgnoreCase(compareType)){
- returnnationalityComparator;
- }else{
- returnnull;
- }
- }
- publicstaticclassIdComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- intid1=c1.getId();
- intid2=c2.getId();
- returnid1==id2?0:(id1<id2?-1:1);
- }
- }
- }
- publicstaticclassFirstNameComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getFirstName();
- Strings2=c2.getFirstName();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- publicstaticclassLastNameComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getLastName();
- Strings2=c2.getLastName();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- publicstaticclassFullNameComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getFullName();
- Strings2=c2.getFullName();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- publicstaticclassIdCardNoComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getIdCardNo();
- Strings2=c2.getIdCardNo();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returns1.compareToIgnoreCase(s2);
- }
- }
- }
- }
- publicstaticclassNationalityComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getNationality();
- Strings2=c2.getNationality();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- }
然后再来看JqGridBaseAction,其中添加了一个抽象方法,用来将数据结果进行排序。
- packagecn.gengv.struts2ex.jqGrid;
- //import...
- @SuppressWarnings("serial")
- publicabstractclassJqGridBaseAction<T>extendsActionSupport{
- ...
- //(1)添加排序方法
- publicabstractvoidsortResults(List<T>results,Stringfield,Stringorder);
- publicStringrefreshGridModel(){
- try{
- List<Criterion>criteria=Collections.emptyList();
- if(search==true){
- criteria=newArrayList<Criterion>();
- if(filters!=null&&filters.length()>0){
- criteria.addAll(this.generateSearchCriteriaFromFilters(filters));
- }
- Criterioncriterion=this.generateSearchCriterion(searchField,searchString,searchOper);
- if(criterion!=null){
- criteria.add(criterion);
- }
- }
- List<T>results=Collections.emptyList();
- intfrom=rows*(page-1);
- intlength=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);
- returnSUCCESS;
- }catch(Exceptione){
- e.printStackTrace();
- this.addActionError(e.getMessage());
- returnERROR;
- }
- }
- ...
- }
而在ListContactsAction中提供了方法实现:
- packagecn.gengv.struts2ex.jqGrid;
- importjava.util.Collections;
- importjava.util.Comparator;
- importjava.util.List;
- importcom.byzl.hare.dao.impl.Criterion;
- importcom.byzl.hare.model.Contact;
- importcom.byzl.hare.service.ContactService;
- @SuppressWarnings("serial")
- publicclassListContactsActionextendsJqGridBaseAction<Contact>{
- ...
- @Override
- publicvoidsortResults(List<Contact>results,Stringfield,Stringorder){
- //(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);
- }
- }
- }
- ...
- }
不过这个例子存在一定的局限性,即只能将当前页中的数据根据某列进行排序;而不能跨页间进行数据排序。之所以存在这种局限,也是源于实际应用中的客观限制。还以这个例子来说,数据库里总共模拟了两万多条数据记录。如果每次要将这些记录进行排里的话,除非有数据库索引支持,否则所要消耗的时间也是相当客观的,对于用户体验来说,几乎就是灾难。如果数据量更多的话,结果可想而知。
因此,我们应该换一个角度来看这个问题,用户之所以使用排序,更多的目的还是在于查找数据方便,既然我们可以提供条件查询(尤其是复杂条件查询),那么用户对于排序的需求也就不会那么迫切了。同时也可以体会到,排序更多地应用在少量数据的场合下。
终于讲到排序了,这一部分应该说还是比较好理解的。
jqGrid通过colModel选项中的sortable来控制是否可以以某列的值排序。sortable的默认值是true,当设为false时,即此列不能用于排序。
- $(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的代码:
- packagecn.gengv.struts2ex.jqGrid;
- importjava.text.Collator;
- importjava.util.Comparator;
- importcom.byzl.hare.model.Contact;
- publicclassContactComparatorFactory{
- privatestaticCollatorcollator_Chinese=Collator.getInstance(java.util.Locale.CHINA);
- privatefinalstaticComparator<Contact>idComparator=newIdComparator();
- privatefinalstaticComparator<Contact>firstNameComparator=newFirstNameComparator();
- privatefinalstaticComparator<Contact>lastNameComparator=newLastNameComparator();
- privatefinalstaticComparator<Contact>fullNameComparator=newFullNameComparator();
- privatefinalstaticComparator<Contact>idCardNoNoComparator=newIdCardNoComparator();
- privatefinalstaticComparator<Contact>nationalityComparator=newNationalityComparator();
- publicstaticComparator<Contact>getComparator(StringcompareType){
- if("id".equalsIgnoreCase(compareType)){
- returnidComparator;
- }elseif("firstName".equalsIgnoreCase(compareType)){
- returnfirstNameComparator;
- }elseif("lastName".equalsIgnoreCase(compareType)){
- returnlastNameComparator;
- }elseif("fullName".equalsIgnoreCase(compareType)){
- returnfullNameComparator;
- }elseif("idCardNoNo".equalsIgnoreCase(compareType)){
- returnidCardNoNoComparator;
- }elseif("nationality".equalsIgnoreCase(compareType)){
- returnnationalityComparator;
- }else{
- returnnull;
- }
- }
- publicstaticclassIdComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- intid1=c1.getId();
- intid2=c2.getId();
- returnid1==id2?0:(id1<id2?-1:1);
- }
- }
- }
- publicstaticclassFirstNameComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getFirstName();
- Strings2=c2.getFirstName();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- publicstaticclassLastNameComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getLastName();
- Strings2=c2.getLastName();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- publicstaticclassFullNameComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getFullName();
- Strings2=c2.getFullName();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- publicstaticclassIdCardNoComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getIdCardNo();
- Strings2=c2.getIdCardNo();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returns1.compareToIgnoreCase(s2);
- }
- }
- }
- }
- publicstaticclassNationalityComparatorimplementsComparator<Contact>{
- publicintcompare(Contactc1,Contactc2){
- if(c1==null&&c2==null){
- return0;
- }elseif(c1==null&&c2!=null){
- return-1;
- }elseif(c1!=null&&c2==null){
- return1;
- }else{
- Strings1=c1.getNationality();
- Strings2=c2.getNationality();
- if(s1==null&&s2==null){
- return0;
- }elseif(s1==null&&s2!=null){
- return-1;
- }elseif(s1!=null&&s2==null){
- return1;
- }else{
- returncollator_Chinese.compare(s1,s2);
- }
- }
- }
- }
- }
然后再来看JqGridBaseAction,其中添加了一个抽象方法,用来将数据结果进行排序。
- packagecn.gengv.struts2ex.jqGrid;
- //import...
- @SuppressWarnings("serial")
- publicabstractclassJqGridBaseAction<T>extendsActionSupport{
- ...
- //(1)添加排序方法
- publicabstractvoidsortResults(List<T>results,Stringfield,Stringorder);
- publicStringrefreshGridModel(){
- try{
- List<Criterion>criteria=Collections.emptyList();
- if(search==true){
- criteria=newArrayList<Criterion>();
- if(filters!=null&&filters.length()>0){
- criteria.addAll(this.generateSearchCriteriaFromFilters(filters));
- }
- Criterioncriterion=this.generateSearchCriterion(searchField,searchString,searchOper);
- if(criterion!=null){
- criteria.add(criterion);
- }
- }
- List<T>results=Collections.emptyList();
- intfrom=rows*(page-1);
- intlength=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);
- returnSUCCESS;
- }catch(Exceptione){
- e.printStackTrace();
- this.addActionError(e.getMessage());
- returnERROR;
- }
- }
- ...
- }
而在ListContactsAction中提供了方法实现:
- packagecn.gengv.struts2ex.jqGrid;
- importjava.util.Collections;
- importjava.util.Comparator;
- importjava.util.List;
- importcom.byzl.hare.dao.impl.Criterion;
- importcom.byzl.hare.model.Contact;
- importcom.byzl.hare.service.ContactService;
- @SuppressWarnings("serial")
- publicclassListContactsActionextendsJqGridBaseAction<Contact>{
- ...
- @Override
- publicvoidsortResults(List<Contact>results,Stringfield,Stringorder){
- //(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);
- }
- }
- }
- ...
- }
不过这个例子存在一定的局限性,即只能将当前页中的数据根据某列进行排序;而不能跨页间进行数据排序。之所以存在这种局限,也是源于实际应用中的客观限制。还以这个例子来说,数据库里总共模拟了两万多条数据记录。如果每次要将这些记录进行排里的话,除非有数据库索引支持,否则所要消耗的时间也是相当客观的,对于用户体验来说,几乎就是灾难。如果数据量更多的话,结果可想而知。
因此,我们应该换一个角度来看这个问题,用户之所以使用排序,更多的目的还是在于查找数据方便,既然我们可以提供条件查询(尤其是复杂条件查询),那么用户对于排序的需求也就不会那么迫切了。同时也可以体会到,排序更多地应用在少量数据的场合下。
相关推荐
在jqGrid与Struts2的结合应用中,我们通常会经历以下几个步骤: 1. **配置Struts2**:首先,需要在项目的`struts.xml`配置文件中添加jqGrid相关的Action,这些Action负责处理来自jqGrid的AJAX请求,获取或更新...
总结来说,jqGrid 与 Struts2 的结合应用提供了高效的数据展示和管理能力。通过理解并熟练运用 jqGrid 的核心方法,开发者可以构建出功能丰富的数据网格,同时结合 Struts2 的灵活性,实现前后端的无缝协作,提高...
**三、jqGrid与Struts2结合应用** jqGrid与Struts2的结合使用可以实现数据的后台动态加载和前端的交互操作。具体步骤如下: 1. **配置Struts2 Action**:创建一个Action类,负责处理请求并返回数据。例如,可以创建...
在本项目中,jqGrid 与 Struts2 结合,实现了Web应用中的核心功能——增删改查。以下是关键步骤: 1. **配置 Struts2**:首先,需要在项目的 `struts.xml` 配置文件中设置Action类及其对应的URL映射,以及指定使用...
总的来说,jqGrid 与 Struts2 结合使用,可以构建出功能丰富的数据展示和管理界面。理解并熟练掌握 jqGrid 的选项配置和与服务器端的交互机制,对于提升 Web 应用的用户体验和数据管理能力至关重要。
将jqGrid与Struts2结合,可以创建高效的前端数据展示和交互界面,同时利用Struts2的强大后端处理能力。 在这个"jqGrid与Struts2的结合例子"中,我们将探讨如何将这两者集成,以实现动态加载、数据过滤、编辑和保存...
在IT领域,尤其是在Web开发中,"jqGrid+Struts2+iBatis+Oracle"是一种常见的技术组合,用于构建功能强大的数据管理应用。这里,jqGrid是一个强大的JavaScript表格插件,Struts2是一个Java Web应用程序框架,iBatis是...
在"jqGrid表格应用——新增与删除数据"这个主题中,我们可以探讨以下知识点: 1. **jqGrid的基本结构**:jqGrid的HTML结构通常包括一个`<table>`元素,以及必要的CSS和JavaScript引用。例如,`index.html`可能包含`...
jqGrid尤其在Web应用程序中,与后端如Struts2等框架结合使用时,能够提供高效的数据展示和管理。 在“jqGrid中文大全(1)”这个压缩包中,包含了一系列关于jqGrid的中文教程和文档,这些资料可以帮助开发者更深入地...
struts配置文件和hibernate的配置文件都在src目录下 4.这就是jqGrid最简单的演示,没有加入任何其它功能, Good Luck! 有人问到没有spring,由于主要是演示jqGrid和jQuery的AJAX功能,所以没有加上spring框架, 如有...
在jqGrid4.5.2版本中,一个备受期待的功能——多列排序终于被引入,极大地提升了用户交互体验和数据管理效率。在此之前,jqGrid只支持单列排序,而多列排序的加入使得用户可以根据多个字段进行复杂的数据筛选和排列...
Struts2JQGrid是一个基于Java的Web开发框架,它结合了Struts2和JQGrid两个强大的工具,用于创建动态、交互式的网格数据展示和管理界面。在本项目中,Struts2作为MVC(Model-View-Controller)框架负责处理业务逻辑和...
Struts2 和 hibernate 演示 jqGrid, 使用Action中的 代码可以容易的把jqGrid 用于servlet或纯jsp. Struts 2.16, jqGrid 3.5b, hibernate 3.2 annotation 由于我的上传权限为20M,而我上传上的包括所有的源代码和支持...
jqGrid demo in Struts2 & Hibernate war file part2
在本文中,我们将深入探讨jqGrid中的表头锁列和排序功能的实现细节。 一、jqGrid 添加列的大标题 jqGrid 提供了设置列组标题的功能,允许为多列设置一个共同的标题头部,提升表格的可读性。实现这一功能的代码如下...
这个"jqGrid增删改查例子"是一个实际应用示例,展示了如何结合Struts2框架和MySQL数据库实现一个完整的CRUD(创建、读取、更新、删除)功能的前端表格。 首先,让我们了解一下jqGrid的核心功能: 1. 数据展示:...
将 jqGrid 与 Bootstrap 4 结合使用,可以创建美观且功能丰富的数据网格,适用于各种设备。 标题 "jqgrid + bootstrap4.0 直接使用" 暗示这个压缩包提供了一个可以直接运行的 jqGrid 示例,集成了 Bootstrap 4 的...
jqGrid demo in Struts2 & Hibernate war file (SQL Script included in WEB-INF\classes)
2. 通过XML字符串数据获取:与XML数据类似,不过是将数据以字符串形式直接传递给jqGrid进行处理。 3. 通过JSON数据获取:后端返回JSON格式的数据,jqGrid通过配置jsonReader来解析。 4. 通过JSON字符串数据获取:...
将jqGrid与Struts结合,可以方便地在后台处理数据操作,例如通过Struts的Action来实现数据的增删改查,而前端则由jqGrid负责展示和交互,形成强大的前后端协作。 **核心功能** - **数据分页**:jqGrid允许用户对...