http://www.javaeye.com/topic/666942#
本文是jquery<--json-->spring(3.0)系列的第三篇。
jquery与yui相比,感觉写法很简洁,但也有个问题是配套的jquery ui中的页面控件
不是很全,很多要借助plugin,而这些plugin良莠不齐,选用时要自己好好挑一挑。
列表是一个常用的页面控件,我选了半天发现DataTables这款用的人比较多,就试了
试服务器端翻页功能,现总结如下。
DataTables的主页是http://www.datatables.net/
先上个这个demo的截图,设想的操作是输入客户名称,按检索后进行模糊检索进行分
页显示,每页显示8条记录。
1 页面部分
使用DataTables时,html需要如下书写,其中tfoot部分是表表格的下部标题,可以不
要。
- <table class="display" id="customerInfo">
- <thead>
- <tr>
- <th>ID</th>
- 略
- <th>身高</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td colspan="8"></td>
- </tr>
- </tbody>
- <tfoot>
- <tr>
- <th>ID</th>
- 略
- <th>身高</th>
- </tr>
- </tfoot>
- </table>
<table class="display" id="customerInfo">
<thead>
<tr>
<th>ID</th>
略
<th>身高</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="8"></td>
</tr>
</tbody>
<tfoot>
<tr>
<th>ID</th>
略
<th>身高</th>
</tr>
</tfoot>
</table>
js部分这样写:
- $('#customerInfo').dataTable();
$('#customerInfo').dataTable();
对于从服务器端取数据,还要指定几个参数:
bServerSide:true
sAjaxSource:获取数据的url
这样,在DataTables需要数据时会调用jquery的getJSON获取数据,其中url就是sAjaxSource,
同时传递一堆自定义的参数,包括需要显示的起始记录数,需要显示的记录数,列数,排序
列等等,具体可以参看这里http://www.datatables.net/usage/server-side。其中一个比较
特殊的是sEcho,这个参数需要以后原封不动地返回给页面。
由于默认是以$.getJSON发送请求,所以http命令是GET,参数是以url参数的方式传递的,我
希望以POST命令,以json方式发送请求,而且要加上客户名称这个参数,所以这里需要做些修
改。
DataTables通过fnServerData提供了这样一个接口,fnServerData是与服务器端交换数据时被
调用的函数,默认实现是如上所说的通过getJSON发送请求,然后接收特定格式的json数据(这
个在服务器端处理部分再说)。fnServerData会接到3个参数:
sSource: 接收数据的url,就是sAjaxSource中指定的地址
aoData:DataTables定义的参数,是一个数组,其中每个元素是一个name-value对,我需要
把客户名称这个参数加进去
fnCallback:服务器返回数据后的处理函数,我需要按DataTables期望的格式传入返回数据
最后自定义的fnServerData如下所示:
- function retrieveData( sSource, aoData, fnCallback ) {
- //将客户名称加入参数数组
- aoData.push( { "name": "customerName", "value": $("#customerName").val() } );
- $.ajax( {
- "type": "POST",
- "contentType": "application/json",
- "url": sSource,
- "dataType": "json",
- "data": JSON.stringify(aoData), //以json格式传递
- "success": function(resp) {
- fnCallback(resp.returnObject); //服务器端返回的对象的returnObject部分是要求的格式
- }
- });
- }
function retrieveData( sSource, aoData, fnCallback ) {
//将客户名称加入参数数组
aoData.push( { "name": "customerName", "value": $("#customerName").val() } );
$.ajax( {
"type": "POST",
"contentType": "application/json",
"url": sSource,
"dataType": "json",
"data": JSON.stringify(aoData), //以json格式传递
"success": function(resp) {
fnCallback(resp.returnObject); //服务器端返回的对象的returnObject部分是要求的格式
}
});
}
页面的初始化及查询按钮的处理函数如下所示:
- var oTable = null;
- $(function() {
- $("#customerInfo").hide();
- } );
- //“检索”按钮的处理函数
- function search() {
- if (oTable == null) { //仅第一次检索时初始化Datatable
- $("#customerInfo").show();
- oTable = $('#customerInfo').dataTable( {
- "bAutoWidth": false, //不自动计算列宽度
- "aoColumns": [ //设定各列宽度
- {"sWidth": "15px"},
- {"sWidth": "80px"},
- {"sWidth": "160px"},
- {"sWidth": "110px"},
- {"sWidth": "120px"},
- {"sWidth": "140px"},
- {"sWidth": "140px"},
- {"sWidth": "*"}
- ],
- "bProcessing": true, //加载数据时显示正在加载信息
- "bServerSide": true, //指定从服务器端获取数据
- "bFilter": false, //不使用过滤功能
- "bLengthChange": false, //用户不可改变每页显示数量
- "iDisplayLength": 8, //每页显示8条数据
- "sAjaxSource": "customerInfo/search.do",//获取数据的url
- "fnServerData": retrieveData, //获取数据的处理函数
- "sPaginationType": "full_numbers", //翻页界面类型
- "oLanguage": { //汉化
- "sLengthMenu": "每页显示 _MENU_ 条记录",
- "sZeroRecords": "没有检索到数据",
- "sInfo": "当前数据为从第 _START_ 到第 _END_ 条数据;总共有 _TOTAL_ 条记录",
- "sInfoEmtpy": "没有数据",
- "sProcessing": "正在加载数据...",
- "oPaginate": {
- "sFirst": "首页",
- "sPrevious": "前页",
- "sNext": "后页",
- "sLast": "尾页"
- }
- }
- });
- }
- //刷新Datatable,会自动激发retrieveData
- oTable.fnDraw();
- }
var oTable = null;
$(function() {
$("#customerInfo").hide();
} );
//“检索”按钮的处理函数
function search() {
if (oTable == null) { //仅第一次检索时初始化Datatable
$("#customerInfo").show();
oTable = $('#customerInfo').dataTable( {
"bAutoWidth": false, //不自动计算列宽度
"aoColumns": [ //设定各列宽度
{"sWidth": "15px"},
{"sWidth": "80px"},
{"sWidth": "160px"},
{"sWidth": "110px"},
{"sWidth": "120px"},
{"sWidth": "140px"},
{"sWidth": "140px"},
{"sWidth": "*"}
],
"bProcessing": true, //加载数据时显示正在加载信息
"bServerSide": true, //指定从服务器端获取数据
"bFilter": false, //不使用过滤功能
"bLengthChange": false, //用户不可改变每页显示数量
"iDisplayLength": 8, //每页显示8条数据
"sAjaxSource": "customerInfo/search.do",//获取数据的url
"fnServerData": retrieveData, //获取数据的处理函数
"sPaginationType": "full_numbers", //翻页界面类型
"oLanguage": { //汉化
"sLengthMenu": "每页显示 _MENU_ 条记录",
"sZeroRecords": "没有检索到数据",
"sInfo": "当前数据为从第 _START_ 到第 _END_ 条数据;总共有 _TOTAL_ 条记录",
"sInfoEmtpy": "没有数据",
"sProcessing": "正在加载数据...",
"oPaginate": {
"sFirst": "首页",
"sPrevious": "前页",
"sNext": "后页",
"sLast": "尾页"
}
}
});
}
//刷新Datatable,会自动激发retrieveData
oTable.fnDraw();
}
2 服务器端
页面请求的参数是一个数组,其中每个元素是一个name-value对,我如下定义
- public class JSONParam {
- private String name;
- private String value;
- //略
- }
public class JSONParam {
private String name;
private String value;
//略
}
对应的处理函数如下定义:
- @RequestMapping(value = "/search", method = RequestMethod.POST)
- @ResponseBody
- public JSONResponse search(@RequestBody JSONParam[] params){
- //略
- }
@RequestMapping(value = "/search", method = RequestMethod.POST)
@ResponseBody
public JSONResponse search(@RequestBody JSONParam[] params){
//略
}
在这个函数里大致的处理是先取出所需的参数,然后检索数据,最后将DataTables期望的
格式的数据放入返回对象JSONResponse的returnObject部分。
DataTables期望的数据格式如下:
{
"sEcho": 页面发来的参数,原样返回,
"iTotalRecords": 过滤前总记录数,
"iTotalDisplayRecords": 过滤后总记录数,我没有使用过滤,不太清楚和iTotalRecords的区别,
"aaData": 包含数据的2维数组
}
对应的java定义如下:
- public class DataTableReturnObject {
- private long iTotalRecords;
- private long iTotalDisplayRecords;
- private String sEcho;
- private String[][] aaData;
- public DataTableReturnObject(long totalRecords, long totalDisplayRecords, String echo, String[][] d) {
- //略
- }
- //略
- }
public class DataTableReturnObject {
private long iTotalRecords;
private long iTotalDisplayRecords;
private String sEcho;
private String[][] aaData;
public DataTableReturnObject(long totalRecords, long totalDisplayRecords, String echo, String[][] d) {
//略
}
//略
}
完整的服务器端处理函数如下:
- @RequestMapping(value = "/search", method = RequestMethod.POST)
- @ResponseBody
- public JSONResponse search(@RequestBody JSONParam[] params) throws IllegalAccessException, InvocationTargetException
- //convertToMap定义于父类,将参数数组中的所有元素加入一个HashMap
- HashMap<String, String> paramMap = convertToMap(params);
- String sEcho = paramMap.get("sEcho");
- String customerName = paramMap.get("customerName");
- int start = Integer.parseInt(paramMap.get("iDisplayStart"));
- int length = Integer.parseInt(paramMap.get("iDisplayLength"));
- //customerService.search返回的第一个元素是满足查询条件的记录总数,后面的是
- //页面当前页需要显示的记录数据
- List<Object> customerList = customerService.search(customerName, start, length);
- Long count = (Long)customerList.get(0);
- //将查询结果转换为一个二维数组
- int record = customerList.size() - 1;
- String[][] data = new String[record][];
- for(int i=0; i<record; i++) {
- Customer customer = (Customer)customerList.get(i+1);
- JSONCustomer jsonCustomer = new JSONCustomer();
- BeanUtils.copyProperties(jsonCustomer, customer);
- data[i] = jsonCustomer.toArray();
- }
- return successed(new DataTableReturnObject(count.longValue(), count.longValue(), sEcho, data));
- }
@RequestMapping(value = "/search", method = RequestMethod.POST)
@ResponseBody
public JSONResponse search(@RequestBody JSONParam[] params) throws IllegalAccessException, InvocationTargetException
//convertToMap定义于父类,将参数数组中的所有元素加入一个HashMap
HashMap<String, String> paramMap = convertToMap(params);
String sEcho = paramMap.get("sEcho");
String customerName = paramMap.get("customerName");
int start = Integer.parseInt(paramMap.get("iDisplayStart"));
int length = Integer.parseInt(paramMap.get("iDisplayLength"));
//customerService.search返回的第一个元素是满足查询条件的记录总数,后面的是
//页面当前页需要显示的记录数据
List<Object> customerList = customerService.search(customerName, start, length);
Long count = (Long)customerList.get(0);
//将查询结果转换为一个二维数组
int record = customerList.size() - 1;
String[][] data = new String[record][];
for(int i=0; i<record; i++) {
Customer customer = (Customer)customerList.get(i+1);
JSONCustomer jsonCustomer = new JSONCustomer();
BeanUtils.copyProperties(jsonCustomer, customer);
data[i] = jsonCustomer.toArray();
}
return successed(new DataTableReturnObject(count.longValue(), count.longValue(), sEcho, data));
}
数据返回到页面后,如上所述,取出response中的returnObject交给DataTables的函数进行处理
就可以了
DataTables还有很多功能,例如排序,过滤等等,关于这些可以参看它的主页。