之前谈到了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、效果图:
2、代码与解释:
HTML代码:
JavaScript代码:
$(function() { $("#gridTable").jqGrid({ url:'json/jqgrid.action', datatype: "json", height: 250, colNames:['编号','用户名', '性别', '邮箱', 'QQ','手机号','出生日期'], colModel:[ {name:'id',index:'id', width:60, sorttype:"int"}, {name:'userName',index:'userName', width:90}, {name:'gender',index:'gender', width:90}, {name:'email',index:'email', width:125,sorttype:"string"}, {name:'QQ',index:'QQ', width:100}, {name:'mobilePhone',index:'mobilePhone', width:120}, {name:'birthday',index:'birthday', width:100, 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; /** * * 该类是所有需要返回json数据的Action的抽象基类。在展示数据时,使用了jQuery的插件jqGrid, * 它对返回的json数据格式有一定的要求。该基类就处理了这些统一的格式要求。 * 需要返回json格式数据被jqGrid使用的,应该继承该类。 * 注意:所有子类应该实现以下get方法,并只简单的返回相应的属性值。 * * * {@link JsoBaseAction#getTotalPages()} * * {@link JsoBaseAction#getCurPage()} * * {@link JsoBaseAction#getTotalRecords()} * * {@link JsoBaseAction#getDataRows()} * * 之所以将这些get方法定义为抽象的,是因为struts2的json插件只会序列化Action类,而不会序列化其父类。 * * * * 继承该类的Action方法,除了搜索(它需要返回JSON数据,因此可以返回SUCCESS),其他操作都应该返回null而不是SUCCESS之类的。 * 这意味着struts配置中,result什么也不用配,即没有相应的视图资源——这是AJAX请求。 * * * * 该类定义了以下几个字段:totalPages、curPage、totalRecords和dataRows。 * 这几个字段是jqGrid格式的要求,而此处是自定义的。因此,在配置jqGrid接收服务器 * 返回的数据格式时,应该配置成这几个名字。(因为默认名字不是这样的,默认名字为:page,total,records,rows) * 当然,也可以通过@JSON注解来指定与默认一样的名字 * * * * 另外一个字段page,则是一个分页类。因为jqGrid会向服务器端传递分页参数, * 用一个分页类接收这些参数。同样,为使Struts能够为page赋值,需要修改jqGrid默认的分页参数名。 * jqGrid默认分页名为:(默认定义在options参数中的prmNames数组中) * * * page->显示第几页 * * rows->每页显示几条记录 * * sidx->排序字段 * * sord->排序方式(asc/desc) * * 应用中应该根据{@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} * * * @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> dataRows = new ArrayList>(); 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中的。 * 因而,子类在action方法如:execute中,应该构建一个 * Map对象,将数据放入其中,并把该对象放入 * List中。 * @return */ public abstract List> getDataRows(); public void setDataRows(List> 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","男","[email protected]","772618379","18329382732","1985-10-2"]}, * {id:"2",cell:["2","张三","女","[email protected]","272618382","15329382732","1986-10-12"]}, * {id:"3",cell:["3","王五","女","[email protected]","172635372","13329389832","1987-12-21"]}, * {id:"4",cell:["4","赵六","男","[email protected]","372618332","18929343731","1988-09-22"]} * ] * } * 当然,在js中,可以通过jqGrid的jsonReader属性来修改默认格式 * 因为默认的格式,rows的数据要求顺序不能变,且每个字段都得有值(空也得有"")。因而, * 在jsonReader中定义repeatitems : false。这样,rows就变成了: * "rows":[ * {id:"1",userName:"polaris",gender:" 男",email:"[email protected]",QQ:"772618379",mobilePhone:"18329382732",birthday:"1985-10-2"]}, * {id:"2",userName:"徐新华",gender:" 男",email:"[email protected]",QQ:"272618382",mobilePhone:"15329382732",birthday:"1986-10-12"]}, * {id:"3",userName:"王五",gender:" 女",email:"[email protected]",QQ:"172635372",mobilePhone:"13329389832",birthday:"1987-12-21"]}, * {id:"4",userName:"赵六",gender:" 女",email:"[email protected]",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存放一行行数据。(跟从Servlet获得数据类似,只不过此处不需要用json-lib) Map row = new HashMap(); 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", "[email protected]"); 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> getDataRows() { return this.dataRows; } @Override public int getTotalPages() { return this.totalPages; } @Override public int getTotalRecords() { return this.totalRecords; } }
注意看注释。
struts.xml的配置:
说明:1)设置字符编码,否则会乱码;2)package要继承自json-default,json-default在struts2-json-plugin中有定义;3)result的type必须为json,表示返回数据类型为json,然而视图映射留空(即result不能对应一个视图)
web.xml的struts2核心过滤器的配置:
你可能会发现,此处配置的过滤器类名和网上很多地方说的不一样。的确,我用的struts2是2.1.8。自从2.1.3开始,原来的过滤器FilterDispatcher被标注为:Deprecated
结语:
至此jqGrid告一段落,不好之处请指正。如有什么问题,可以联系我,我们一起讨论。