jQuery学习之:jqGrid表格插件——从Struts2获得数据


 


版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。 http://polaris.blog.51cto.com/1146394/264465


之前谈到了jqGrid与Serlvet/JSP集成,实际上就是Servlet按jqGrid对数据的要求返回相应的数据,Servlet中是通过PrintWriter输出数据的,那时,我们用到了json-lib来构建Json数据。现在来谈谈jqGrid如何与Struts2集成。



对于Struts2,同样需要按jqGrid的要求返回相应的json数据格式。当然,我们可以在Struts2的Action中通过返回null来干Servlet一样的事情,这样也能够同Servlet一样实现与jqGrid集成。然而,此时Struts2实际上相当于没有。既然用到了Struts2,我们就应该用Struts2为我们提供的方法。而且,在Struts的Action中应该尽量避免使用request之类的Servlet对象,用Struts2更是如此。在struts1.x中,request直接就有的,因而在开发中总会有人“打着struts的旗帜,干着Servlet的勾当”。我们知道,request等是依赖于Servlet容器的,Struts2把这些屏蔽了,Struts2的Action可以直接是POJO,因而我们更不应该违反Struts2的设计原则,硬是去“干Servlet的勾当”。闲话不说,开始咱们的正题。



在Struts2的jar包中,有一个struts2-json-plugin.jar,它就是用于处理json数据的(Struts2提供了很多插件),我们就是应用它来实现struts2与jqGrid的集成。



1、效果图:



jQuery学习之:jqGrid表格插件——从Struts2获得数据_jQuery

 




2、代码与解释:



HTML代码:


<          body          >          
                  <          table          id          ="gridTable"          >          </table>          
                  <          div          id          ="gridPager"          >          </div>          
</body>



JavaScript代码:


function()          
{          
        $(          "#gridTable").jqGrid({          
                url:'json/jqgrid.action',          
                datatype:          "json",          
                height: 250,          
                colNames:['编号','用户名', '性别', '邮箱', 'QQ','手机号','出生日期'],          
                colModel:[          
                        {name:'id',index:'id', sorttype:          "int"},          
                        {name:'userName',index:'userName',          
                        {name:'gender',index:'gender',          
                        {name:'email',index:'email', ;string"},          
                        {name:'QQ',index:'QQ', ;                      
                        {name:'mobilePhone',index:'mobilePhone', ;                      
                        {name:'birthday',index:'birthday', sorttype:          "date"}          
                ],          
                sortname:'id',          
                sortorder:'asc',          
                viewrecords:          true,          
                rowNum:10,          
                rowList:[10,20,30],          
                jsonReader: {          
                        root:          "dataRows",                          // 数据行(默认为:rows)          
                        page:          "curPage",                      // 当前页          
                        total:          "totalPages",              // 总页数          
                        records:          "totalRecords",              // 总记录数          
                        repeatitems :          false                          // 设置成false,在后台设置值的时候,可以乱序。且并非每个值都得设          
                },          
                prmNames:{rows:          "page.pageSize",page:          "page.curPageNo",sort:          "page.orderBy",order:          "page.order"},          
                pager:          "#gridPager",          
                caption:          "jqGrid与Struts2集成"          
}).navGrid('#gridPager',{edit:          false,add:          false,del:          false});          
})


注意,JavaScript代码与Servlet例子中的有点不一样,主要是:jsonReader参数,另外增加了prmNames参数。每一项的是什么意思下面Java代码的注释中有详细说明。






Java代码:

package com.polaris.jqgrid.struts2;         

import java.util.ArrayList;         
import java.util.List;         
import java.util.Map;         

import com.opensymphony.xwork2.ActionSupport;         
import com.polaris.jqgrid.util.Page;         

/**
* <p>
* 该类是所有需要返回json数据的Action的<b>抽象基类</b>。在展示数据时,使用了jQuery的插件jqGrid,
* 它对返回的json数据格式有一定的要求。该基类就处理了这些统一的格式要求。
* 需要返回json格式数据被jqGrid使用的,应该继承该类。<br/>
* <b><font color='red'>注意:所有子类应该实现以下get方法,并只简单的返回相应的属性值。</font></b>
* <ul>
*         <li>{@link JsoBaseAction#getTotalPages()}</li>
*         <li>{@link JsoBaseAction#getCurPage()}</li>
*         <li>{@link JsoBaseAction#getTotalRecords()}</li>
*         <li>{@link JsoBaseAction#getDataRows()}</li>
* </ul>
* 之所以将这些get方法定义为抽象的,是因为struts2的json插件只会序列化Action类,而不会序列化其父类。
* </p>
*
* <p><font color='red'>
* 继承该类的Action方法,除了搜索(它需要返回JSON数据,因此可以返回SUCCESS),其他操作都应该返回null而不是SUCCESS之类的。
* 这意味着struts配置中,result什么也不用配,即没有相应的视图资源——这是AJAX请求。
* </font></p>
*
* <p>
* 该类定义了以下几个字段:totalPages、curPage、totalRecords和dataRows。
* 这几个字段是jqGrid格式的要求,而此处是自定义的。因此,在配置jqGrid接收服务器
* 返回的数据格式时,应该配置成这几个名字。(因为默认名字不是这样的,默认名字为:page,total,records,rows)
* 当然,也可以通过@JSON注解来指定与默认一样的名字
* </p>
*
* <p>
* 另外一个字段page,则是一个分页类。因为jqGrid会向服务器端传递分页参数,
* 用一个分页类接收这些参数。同样,为使Struts能够为page赋值,需要修改jqGrid默认的分页参数名。
* jqGrid默认分页名为:(默认定义在options参数中的prmNames数组中)
* <ul>
*         <li>page->显示第几页</li>
*         <li>rows->每页显示几条记录</li>
*         <li>sidx->排序字段</li>
*         <li>sord->排序方式(asc/desc)</li>
* </ul>
* 应用中应该根据{@link com.polaris.jqgrid.util.Page}类中的定义设置。设置为:
* prmNames:{rows:"page.pageSize",page:"page.curPageNo",sort:"page.orderBy",order:"page.order"}
*
* prmNames数组的默认值为:
* prmNames: {page:"page",rows:"rows", sort: "sidx",order: "sord", search:"_search", nd:"nd", npage:null}
* </p>
*
* @author xuxinhua
* @version 1.0
*/         
@SuppressWarnings(         "unchecked")         
public         abstract         class JsonBaseAction         extends ActionSupport         
{         
                 private         static         final         long serialVersionUID = 1L;         
                 /**
         * 该属性专门用于接收删除的数据的ID(主键)。注意,当支持一次删除多记录时,id的值是通过','号分隔的多个
         */         
                 protected String id;         
                 /**
         * 分页类
         */         
                 protected Page page =         new Page();         
                 /**
         * 以下属性用于序列化成json格式的数据。名称不能改。如果要改,客户端页面对应的地方也要改;
         * 或通过@JSON来指定序列化的名字
         */         
                 /**
         * 总页数
         */         
                 protected         int totalPages;         
                 /**
         * 显示第几页
         */         
                 protected         int curPage;         
                 /**
         * 总记录数
         */         
                 protected         int totalRecords;         
                 /**
         * 保存实际的数据
         */         
                 protected List<Map<String,Object>> dataRows =         new ArrayList<Map<String,Object>>();         

                 public JsonBaseAction() {         
                         super();         
        }         

                 public Page getPage() {         
                         return page;         
        }         

                 public         void setPage(Page page) {         
                         this.page = page;         
        }         
                 public         void setId(String id) {         
                         this.id = id;         
        }         
                 public String getId() {         
                         return id;         
        }         

                 public         abstract         int getTotalPages();         

                 public         void setTotalPages(         int totalPages) {         
                         this.totalPages = totalPages;         
        }         
                 public         abstract         int getCurPage();         

                 public         void setCurPage(         int curPage) {         
                         this.curPage = curPage;         
        }         
                 public         abstract         int getTotalRecords();         

                 public         void setTotalRecords(         int totalRecords) {         
                         this.totalRecords = totalRecords;         
        }         
                 /**
         * 注意该方法的返回值:List。实际上包含了实际的数据,
         * 而这些数据是放在Map<String, Object>中的。
         * 因而,子类在action方法如:execute中,应该构建一个
         * Map<String, Object>对象,将数据放入其中,并把该对象放入
         * List中。
         * @return
         */         
                 public         abstract List<Map<String, Object>> getDataRows();         

                 public         void setDataRows(List<Map<String, Object>> dataRows) {         
                         this.dataRows = dataRows;         
        }         

}

这个类是一个抽象基类,为了方便扩展而设计的。需要返回json数据(使用jqGrid插件)的Action应该继承该类。这个类是我为公司写的一个类,拿出来与大家分享。



实际处理JSON数据的Action类代码:

package com.polaris.jqgrid.struts2;         

import java.util.HashMap;         
import java.util.List;         
import java.util.Map;         
/**
* 该Struts2向客户端返回一个json对象。为了简便,数据不是从数据库获得的。
* jqGrid默认期望返回的json对象格式要求如下:
* {"page":"1","total":"2","records":"13",
* "rows":[
*                 {id:"1",cell:["1","polaris","男","polaris@gmail.com","772618379","18329382732","1985-10-2"]},
*                 {id:"2",cell:["2","张三","女","zhangsan@163.com","272618382","15329382732","1986-10-12"]},
*                 {id:"3",cell:["3","王五","女","wangwu@yahoo.com","172635372","13329389832","1987-12-21"]},
*                 {id:"4",cell:["4","赵六","男","zhaoliu@sina.com","372618332","18929343731","1988-09-22"]}
*         ]
* }
* 当然,在js中,可以通过jqGrid的jsonReader属性来修改默认格式
* 因为默认的格式,rows的数据要求顺序不能变,且每个字段都得有值(空也得有"")。因而,
* 在jsonReader中定义repeatitems : false。这样,rows就变成了:
* "rows":[
*                 {id:"1",userName:"polaris",gender:" 男",email:"polaris@gmail.com",QQ:"772618379",mobilePhone:"18329382732",birthday:"1985-10-2"]},
*                 {id:"2",userName:"徐新华",gender:" 男",email:"xh.xu@163.com",QQ:"272618382",mobilePhone:"15329382732",birthday:"1986-10-12"]},
*                 {id:"3",userName:"王五",gender:" 女",email:"wangwu@yahoo.com",QQ:"172635372",mobilePhone:"13329389832",birthday:"1987-12-21"]},
*                 {id:"4",userName:"赵六",gender:" 女",email:"zhaoliu@sina.com",QQ:"372618332",mobilePhone:"18929343731",birthday:"1988-09-22"]}
*         ]
* @author xuxinhua
*
*/         
public         class JqGridForJSONAction         extends JsonBaseAction         
{         
                 private         static         final         long serialVersionUID = 132383828833L;         
                 /**
         * 该方法得到数据并构造json对象以便返回给客户端
         * @return
         * @throws Exception
         */         
                 public String execute()         throws Exception         
        {         
                         // 构建几条数据         
                         int i = 0;         
                         for(i=0;i<4;++i)         
                {         
                                 // 定义一个Map<String,Object>存放一行行数据。(跟从Servlet获得数据类似,只不过此处不需要用json-lib)         
                        Map<String, Object> row =         new HashMap<String, Object>();         
                        row.put(         "id", i);         
                                 if(i%2==0)         
                        {         
                                row.put(         "userName",         "polaris");         
                                row.put(         "gender",         "女");         
                        }         
                                 else         
                        {         
                                row.put(         "userName",         "徐新华");         
                                row.put(         "gender",         "男");         
                        }         
                        row.put(         "email",         "polaris@gmail.com");         
                        row.put(         "QQ",         "772"+i+         "1837"+i);         
                        row.put(         "mobilePhone",         "132"+i+         "1837"+i+         "3"+i);         
                        row.put(         "birthday",         "198"+i+         "-10-"+         "1"+i);         
                        dataRows.add(row);         
                }         
                         // 给另外三个返回参数设值         
                setTotalPages(1);                         // 总页数         
                setCurPage(1);                                 // 当前页         
                setTotalRecords(i);                         // 总记录数         
                         return SUCCESS;         
        }         
                 /*
         * 以下getter方法必须实现,struts2-json插件会将这些getter方法序列化,以便输出json对象。
         * 这些getter方法只需返回相应的属性即可。如getCurPage应该返回curPage
         * (curPage在JsonBaseAction中有定义)
         */         
        @Override         
                 public         int getCurPage()         
        {         
                         return         this.curPage;         
        }         

        @Override         
                 public List<Map<String, Object>> getDataRows()         
        {         
                         return         this.dataRows;         
        }         

        @Override         
                 public         int getTotalPages()         
        {         
                         return         this.totalPages;         
        }         

        @Override         
                 public         int getTotalRecords()         
        {         
                         return         this.totalRecords;         
        }         
}


注意看注释。



struts.xml的配置:



<         constant         name         ="struts.i18n.encoding"         value         ="utf-8"         >         </         constant         >         

<         package         name         ="json"         namespace         ="/json"         extends         ="json-default"         >         
                 <         action         name         ="jqgrid"         class         ="com.polaris.jqgrid.struts2.JqGridForJSONAction"         >         
                         <         result         type         ="json"         >         </         result         >         
                 </         action         >         
</         package         >


说明:1)设置字符编码,否则会乱码;2)package要继承自json-default,json-default在struts2-json-plugin中有定义;3)result的type必须为json,表示返回数据类型为json,然而视图映射留空(即result不能对应一个视图)



web.xml的struts2核心过滤器的配置:


<         filter         >         
                 <         filter-name         >struts2         </         filter-name         >         
                 <         filter-class         >         
                org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter         
                 </         filter-class         >         
</         filter         >         

<         filter-mapping         >         
                 <         filter-name         >struts2         </         filter-name         >         
                 <         url-pattern         >/*         </         url-pattern         >         
</         filter-mapping         >


你可能会发现,此处配置的过滤器类名和网上很多地方说的不一样。的确,我用的struts2是2.1.8。自从2.1.3开始,原来的过滤器FilterDispatcher被标注为:

Deprecated


结语:



至此jqGrid告一段落,不好之处请指正。如有什么问题,可以联系我,我们一起讨论。



本文出自 “徐新华polaris” 博客,请务必保留此出处http://polaris.blog.51cto.com/1146394/264465


本文出自 51CTO.COM技术博客




 

 

由于很多人需要com.polaris.jqgrid.util.Page这个类,在此贴出该类代码:

package com.polaris.jqgrid.util;

import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.StringUtils;

/**
* 与具体ORM实现无关的分页参数及查询结果封装.
* 
* @param <T> Page中记录的类型.
* @author xuxinhua
*/
public final class Page<T> {

     // 公共变量
     public static final String ASC = "asc";
     public static final String DESC = "desc";

     public static final int MIN_PAGESIZE = 1;                  // 每页显示的最少记录数
     public static final int MAX_PAGESIZE = 200;                  // 每页显示的最大记录数

     // 分页参数
     protected int curPageNo = 1;                                    // 当前所在页码(在第几页)
     protected int pageSize = MIN_PAGESIZE;                        // 当前每页显示的记录数
     protected String orderBy = null;                              // 排序字段
     protected String order = null;                                    // 排序方式(升序或降序)
     protected boolean autoCount = false;                        // 查询对象时是否自动另外执行count查询获取总记录数

     // 返回结果
     protected List<T> result = Collections.emptyList();      // 当前页的实际记录数
     protected int totalCount = -1;                                    // 记录总数

     /**
      * 默认构造函数
      */
     public Page() {
           super();
     }
     /**
      * 通过设置每页显示多少条记录来构造对象
      * @param pageSize
      */
     public Page(final int pageSize) {
           setPageSize(pageSize);
     }
     /**
      * 
      * @param pageSize
      * @param autoCount
      */
     public Page(final int pageSize, final boolean autoCount) {
           setPageSize(pageSize);
           this.autoCount = autoCount;
     }

     // 查询参数函数

     /**
      * 获得当前页的页号,序号从1开始,默认为1.
      */
     public int getCurPageNo() {
           return curPageNo;
     }

     /**
      * 设置当前页的页号,序号从1开始,低于1时自动调整为1.
      * @param curPageNo
      */
     public void setCurPageNo(final int curPageNo) {
           this.curPageNo = curPageNo;

           if (curPageNo < 1) {
                 this.curPageNo = 1;
           }
     }

     /**
      * 获得每页的记录数量,默认为10.
      */
     public int getPageSize() {
           return pageSize;
     }

     /**
      * 设置每页的记录数量,超出MIN_PAGESIZE与MAX_PAGESIZE范围时会自动调整.
      * @param pageSize
      */
     public void setPageSize(final int pageSize) {

           this.pageSize = pageSize;
           
           if (pageSize < MIN_PAGESIZE) {
                 this.pageSize = MIN_PAGESIZE;
           }
           else if (pageSize > MAX_PAGESIZE) {
                 this.pageSize = MAX_PAGESIZE;
           }
     }

     /**
      * 根据curPageNo和pageSize(每页显示记录数)计算当前页第一条记录在总结果集中的位置,序号从0开始.
      */
     public int getFirst() {
           return ((curPageNo - 1) * pageSize);
     }

     /**
      * 获得排序字段,无默认值。多个排序字段时用','分隔,仅在Criterion查询时有效.
      */
     public String getOrderBy() {
           return this.orderBy;
     }

     /**
      * 设置排序字段。多个排序字段时用','分隔.仅在Criterion查询时有效.
      * @param orderBy 要排序的字段
      */
     public void setOrderBy(final String orderBy) {
           this.orderBy = orderBy;
     }

     /**
      * 是否已设置排序字段,仅在Criterion查询时有效.
      */
     public boolean isOrderBySetted() {
           return StringUtils.isNotBlank(orderBy);      // isNotBlank判断:当orderBy不等于null、""或" "时返回true
     }

     /**
      * 获得排序方向,默认为asc,仅在Criterion查询时有效.
      */
     public String getOrder() {
           return this.order;
     }

     /**
      * 设置排序方式向,仅在Criterion查询时有效.
      * @param order 可选值为desc或asc,多个排序字段时用','分隔.
      */
     public void setOrder(final String order) {
           // 检查order字符串的合法值
           String[] orders = StringUtils.split(StringUtils.lowerCase(order), ',');
           for (String orderStr : orders) {
                 if (!StringUtils.equals(DESC, orderStr)
                             && !StringUtils.equals(ASC, orderStr))
                       throw new IllegalArgumentException("排序方向" + orderStr + "不是合法值");
           }

           this.order = StringUtils.lowerCase(order);
     }

     /**
      * 查询对象时是否自动另外执行count查询获取总记录数,默认为false,仅在Criterion查询时有效.
      */
     public boolean isAutoCount() {
           return autoCount;
     }

     /**
      * 查询对象时是否自动另外执行count查询获取总记录数,仅在Criterion查询时有效.
      * @param autoCount
      */
     public void setAutoCount(final boolean autoCount) {
           this.autoCount = autoCount;
     }

     // 查询结果函数

     /**
      * 取得页内的记录列表.
      */
     public List<T> getResult() {
           return result;
     }
     
     /**
      * 设置页内的记录列表.
      * @param result
      */
     public void setResult(final List<T> result) {
           this.result = result;
     }

     /**
      * 取得总记录数,默认值为-1.
      */
     public int getTotalCount() {
           return totalCount;
     }
     
     /**
      * 设置总记录数
      * @param totalCount
      */
     public void setTotalCount(final int totalCount) {
           this.totalCount = totalCount;
     }

     /**
      * 根据pageSize与totalCount计算总页数,默认值为-1.
      */
     public int getTotalPages() {
           if (totalCount < 0)
                 return -1;

           int count = totalCount / pageSize;
           if (totalCount % pageSize > 0) {
                 count++;
           }
           return count;
     }

     /**
      * 是否还有下一页.
      */
     public boolean isHasNext() {
           return (curPageNo + 1 <= getTotalPages());
     }

     /**
      * 取得下页的页号,序号从1开始.
      */
     public int getNextPage() {
           if (isHasNext())
                 return curPageNo + 1;
           else
                 return curPageNo;
     }

     /**
      * 是否还有上一页.
      */
     public boolean isHasPre() {
           return (curPageNo - 1 >= 1);
     }

     /**
      * 取得上页的页号,序号从1开始.
      */
     public int getPrePage() {
           if (isHasPre())
                 return curPageNo - 1;
           else
                 return curPageNo;
     }
}