jqGrid <-- json --> spring,hibernate之服务器端分页,排序

最近做了一个以jqGrid实现的数据表格,与服务器端(spring + hibernate)以json格式交换数据,分页
和排序都在服务器端实现,现总结如下:

操作页面是这样的:

[img]http://dl.iteye.com/upload/attachment/494397/8c1239db-b1db-3946-a677-cd8f6e11b2bc.jpg[/img]

用户输入查询信息,按“检索”按钮,返回查询结果,表格可以翻页,排序。

当把jqGrid的属性datatype定义为function时,表格需要获取数据时(翻页,排序等),jqGrid就会调用
这个function,通过这种机制,就可以实现服务器端分页、排序。需要注意的是,这个function需要读取
数据并显式地调用addJSONData,addXMLData等去刷新表格,详情可以参看:
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#function

这个函数有一个参数,关于参数的定义我没有找到,但用firebug之类的工具可以看出包括如下的属性:
_search : (不清楚)
nd : (不清楚)
page : 当前页
rows : 每页记录数
sidx : sort index,排序字段名
sord : sort direction,排序方式:asc, desc

这样一来,我们就可以把这些数据发送到服务器端进行分页和排序。

以下是页面的html代码:
	<table width="95%">
<tr>
<td>
<table>
<tr>
<td>
<form id="frmSearchCustomer">
<table>
<tr>
<td>
名称:<input type="text" name="name" />
アドレス:<input type="text" name="addr" />
</td>
</tr>
<tr>
<td>
担当者:<input type="text" name="dandang" />
</td>
</tr>
</table>
</form>
</td>
</tr>
<tr>
<td>
<button id="search">检索</button>
<button id="clear">清除条件</button>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table id="list"></table>
<div id="pager"></div>
</td>
</tr>
</table>


以下是jqGrid初始化的代码:

	$("#list").jqGrid({
datatype : function(postdata) {
postdata = mergeObject(jsonCondition, postdata);

jQuery.ajax({
type : 'POST',
contentType : 'application/json',
url : ROOT_PATH + '/customer/search.do',
data : JSON.stringify(postdata),
dataType : 'json',
success : function(resp) {
if (resp.successed) {
var thegrid = jQuery("#list")[0];
thegrid.addJSONData(resp.returnObject);
} else {
alert(resp.errors[0].message);
}
},
error : ajaxFailed
});
},
height : '100%',
rowNum : '10',
jsonReader : {
repeatitems: false
},
colNames : ['顧客番号', '名称', 'アドレス', '担当者', '携帯', '電話①', '電話②'],
colModel : [
{name:'id', index:'id', width:80},
{name:'name', index:'name', width:256},
{name:'addr', index:'addr', width:256},
{name:'dandang', index:'dandang', width:64},
{name:'mobile', index:'mobile', width:128},
{name:'phone1', index:'phone1', width:128},
{name:'phone2', index:'phone2', width:128},
],
pager : '#pager'
});


其中关键就是datatype为一function,在这个function中通过jQuery.ajax发送一个请求,获取数据,然后通过
addJSONData刷新表格数据。发送的数据包括postdata和用户输入的查询条件,其中postdata是jqGrid传递过来
的包含分页、排序信息的对象,jsonCondition是“检索”按钮中生成的包含查询条件的对象。
检索按钮中的处理如下:

	var jsonCondition = {};

function search() {
jsonCondition = array2Json(jQuery("#frmSearchCustomer").serializeArray());
jQuery("#list").trigger("reloadGrid");
}

其中array2Json是从网上找来的把jQuery的serializeArray生成的数组转成json的函数,我以前的文章里有,这里
就不重复了。

mergeObject是一个我自己写的拷贝一个对象的属性到另一对象的函数:
	function mergeObject(src, dest) {
var i;
for(i in src) {
dest[i]=src[i];
}
return dest;
}


下面说下服务器端。
我用的spring的controller是直接接受json数据并以json格式返回数据的,这部分是延续以前的做法的,可以参见
我以前的文章:
jquery(1.3.2)<--json-->spring(3.0)
jquery<--json-->spring(3.0)之后台校验

我定义了一个对应jqGrid的postdata的类:
	public class JQGridRequest {
private String _search;
private String nd;
private int page;
private int rows;
private String sidx;
private String sord;

...
}


对于不同的查询页面,可以扩展这个类,定义包含该页面查询条件的类,本例中我定义了这样的类:
	public class CustomerSearchInfo extends JQGridRequest {
private String name;
private String addr;
private String dandang;

...
}


Controller的定义如下,其中接受的参数就是上面所说的CustomerSearchInfo这个类:
@Controller
@RequestMapping("/customer")
public class CustomerController extends JSONController {
private CustomerService customerService;

...

@RequestMapping(value = "/search", method = RequestMethod.POST)
@ResponseBody
public JSONResponse search(@RequestBody CustomerSearchInfo searchInfo) {
JQGridResponse data = customerService.search(searchInfo);
return this.successed(data);
}
}


jqGrid对于json数据是有格式要求的(这个格式可以自定义),详情可以参见
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data
当repeatitems为false时默认是这样的:
	{ 
"total": "xxx", //总页数
"page": "yyy", //当前页
"records": "zzz", //本次查询的记录数
"rows" : [
{"id" :"1", "name" : "xxxx", "addr" : "xxxx", ...},
{"id" :"2", "name" : "xxxx", "addr" : "xxxx", ...},
...
]
}


所以我还为服务器端的返回数据定义了一个类:
	public class JQGridResponse {
private int total; //total pages
private int page; //current page
private int records; //total records
private ArrayList<Object> rows;

...
}


customerService.search(searchInfo)返回的就是这样一个类。service的代码如下:
其中计算了总页数,当前页,记录数,同时通过相应的setter方法进行赋值。

	@Override
@Transactional
public JQGridResponse search(CustomerSearchInfo searchInfo) {
JQGridResponse response = new JQGridResponse();

int count = baseInfoDao.count(searchInfo);

double dCount = (double)count;
double dRows = (double)searchInfo.getRows();
int total = (int)Math.ceil(dCount / dRows); //total page
response.setTotal(total);
int curPage = Math.min(total, searchInfo.getPage()); //current page
response.setPage(curPage);
searchInfo.setPage(curPage); //这是为了在dao中查询用的

ArrayList<Object> customers = new ArrayList<Object>();
//检索符合条件的数据(略)
...

response.setRecords(customers.size());
response.setRows(customers);

return response;
}


在dao层,就是利用hibernate的setFirstResult和setMaxResults读取当前页的记录,需要注意
的是,对于符合条件的总记录数需要使用Projections.rowCount()获得,所以我做了两个方法
search和count,前者是取得本次查询当前页的数据,后者是本次查询的记录总数,这两者的
查询条件是一样的,但前者需要加上排序信息,并且指定仅返回当前页的记录数,后者仅获取
记录条数(其实就是select count(*)),代码片段如下:
public class CustomerBaseInfoDaoImpl implements CustomerBaseInfoDao {
private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

...

@Override
public List<CustomerBaseInfo> search(CustomerSearchInfo searchInfo) {
Session session = sessionFactory.getCurrentSession();
Criteria c = getSearchCriteria(session, searchInfo);

//排序
String sortIdx = searchInfo.getSidx();
if (sortIdx.length() > 0) {
if ("asc".equalsIgnoreCase(searchInfo.getSord())) {
c.addOrder(Order.asc(sortIdx));
} else {
c.addOrder(Order.desc(sortIdx));
}
}

c.setFirstResult((searchInfo.getPage() - 1) * searchInfo.getRows());
c.setMaxResults(searchInfo.getRows());

return (List<CustomerBaseInfo>)c.list();
}

@Override
public int count(CustomerSearchInfo searchInfo) {
Session session = sessionFactory.getCurrentSession();
Criteria c = getSearchCriteria(session, searchInfo);

c.setProjection(Projections.rowCount());

return ((Integer)c.list().get(0)).intValue();
}

private Criteria getSearchCriteria(Session session, CustomerSearchInfo searchInfo) {
Criteria c = session.createCriteria(CustomerBaseInfo.class);

//检索条件
String name = searchInfo.getName();
if (name != null && name.trim().length() > 0) {
c.add(Restrictions.ilike("name", "%" + name + "%"));
}

String addr = searchInfo.getAddr();
if (addr != null && addr.trim().length() > 0) {
c.add(Restrictions.ilike("addr", "%" + addr + "%"));
}

String dandang = searchInfo.getDandang();
if (dandang != null && dandang.trim().length() > 0) {
c.add(Restrictions.ilike("dandang", "%" + dandang + "%"));
}

return c;
}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值