DataTables的伺服器端(SpringMVC)分頁模式
Datatables是一款jquery表格外掛。它是一個高度靈活的工具,可以將任何HTML表格新增高階的互動功能。
分頁,即時搜尋和排序
幾乎支援任何資料來源:DOM, javascript, Ajax 和 伺服器處理
支援不同主題 DataTables, jQuery UI, Bootstrap, Foundation
各式各樣的擴充套件: Editor, TableTools, FixedColumns ……
豐富多樣的option和強大的API
支援國際化
免費開源 ( MIT license )! 商業支援
因此這一款非常值得推薦的表格外掛。今天藉此機會我們來記錄一下使用伺服器端(SpringMVC)分頁的方法。
首先,來看客戶端的JavaScript程式碼:
var self_order_table = $("#self_order_table").DataTable({
"processing": true,
"serverSide": true,
"paging": true,
language : QINGE._set.table_language,
"ajax": {
"url": CONFIG.mec_datable.index + "otm/order/list?p=self" ,
"type": "POST",
"data": function (d) {
//刪除多餘請求引數
for(var key in d){
if(key.indexOf("columns")==0||key.indexOf("order")==0||key.indexOf("search")==0){ //以columns開頭的引數刪除
delete d[key];
}
}
var searchParams= {
page : d.start == 0 ? 1 : (d.start/d.length + 1),
rows : d.length,
};
//附加查詢引數
if(searchParams){
$.extend(d,searchParams); //給d擴充套件引數
}
},
"dataType" : "json",
"dataFilter": function (response) {//json是伺服器端返回的資料
var json = QINGE.jsonEval(response);
if (json[QINGE.keys.statusCode] == QINGE.statusCode.error) {
if (json[QINGE.keys.message])
$.showErr(json[QINGE.keys.message]);
} else {
var returnData = {};
returnData.draw = json.result.vo.mo.draw;
returnData.recordsTotal = json.result.count;//返回資料全部記錄
returnData.recordsFiltered = json.result.count;//後臺不實現過濾功能,每次查詢均視作全部結果
returnData.data = json.result.list;//返回的資料列表
return JSON.stringify(returnData);//這幾個引數都是datatable需要的,必須要
}
}
},
deferRender : true,
"scrollX" : true,
scrollCollapse : true,
fixedColumns : {
leftColumns : 1,
},
"columnDefs" : [
{
targets : 0,
data : "scode",
title : "商品",
render : function(data, type, row) {
return "</div><div style='color: #676b6e;font-size: 10px; '>" + row.scode + "</div>";
}
}, {
targets : 1,
"data" : "order_count",
title : "委託量",
}, {
targets : 2,
"data" : "chengjiao_count",
title : "成交量",
}, {
targets : 3,
"data" : "order_price",
title : "委託價",
} ],
"rowCallback" : function(row, data, index) {
},
});
需要注意的內容就是,如果使用伺服器端分頁,需要開啟:
"processing": true,
"serverSide": true,
"paging": true,
然後藉助ajax選項來定製發往伺服器端的分頁引數和伺服器端返回的分頁引數,先來看分頁請求引數:
"data": function (d) {
//刪除多餘請求引數
for(var key in d){
if(key.indexOf("columns")==0||key.indexOf("order")==0||key.indexOf("search")==0){ //以columns開頭的引數刪除
delete d[key];
}
}
var searchParams= {
page : d.start == 0 ? 1 : (d.start/d.length + 1),
rows : d.length,
};
//附加查詢引數
if(searchParams){
$.extend(d,searchParams); //給d擴充套件引數
}
},
其中page為第幾頁,rows為一頁顯示多少行,這兩個是必須引數。這個時候,發往伺服器端的引數都有哪一些呢?看下圖。
①、其中draw是DataTables一個必須引數,是記錄第幾次分頁的一個關鍵引數,伺服器端還需要返回。
②、通過start和length引數可以計算出當前請求是第幾頁,比如說上圖中的start為40,length為10,即page等於5(計算公式為:d.start == 0 ? 1 : (d.start/d.length + 1)
)
③、rows和length是相同的,只不過本次我們的SpringMVC端只認rows,不認length,所以需要轉換一下。
再來看伺服器端返回的資料處理,此時需要用到Ajax的dataFilter:
"dataFilter": function (response) {//json是伺服器端返回的資料
var json = QINGE.jsonEval(response);
if (json[QINGE.keys.statusCode] == QINGE.statusCode.error) {
if (json[QINGE.keys.message])
$.showErr(json[QINGE.keys.message]);
} else {
var returnData = {};
returnData.draw = json.result.vo.mo.draw;
returnData.recordsTotal = json.result.count;//返回資料全部記錄
returnData.recordsFiltered = json.result.count;//後臺不實現過濾功能,每次查詢均視作全部結果
returnData.data = json.result.list;//返回的資料列表
return JSON.stringify(returnData);//這幾個引數都是datatable需要的,必須要
}
}
伺服器端返回的是json字串,因此可以通過jsonEval函式來轉換成json物件。然後從中取出datatables需要的關鍵資料:
var returnData = {};
returnData.draw = json.result.vo.mo.draw;
returnData.recordsTotal = json.result.count;//返回資料全部記錄
returnData.recordsFiltered = json.result.count;//後臺不實現過濾功能,每次查詢均視作全部結果
returnData.data = json.result.list;//返回的資料列表
return JSON.stringify(returnData);//這幾個引數都是datatable需要的,必須要
QINGE.jsonEval(response)函式的具體內容如下:
jsonEval : function(data) {
try {
if ($.type(data) == 'string')
return eval('(' + data + ')');
else
return data;
} catch (e) {
return {};
}
},
這樣的話,針對客戶端傳遞到伺服器端的引數和接收伺服器端返回的資料就處理完成了,接下來我們來看Java端(也就是SpringMVC)來如何接收分頁請求和響應分頁資料。
首先來看controller:
@SuppressWarnings({ "rawtypes", "unchecked" })
@RequestMapping(value = "list")
public void list(HttpServletResponse response) {
Map result = new HashMap();
// 獲取列表引數
BaseConditionVO vo = getBaseConditionVOForTable();
vo.addParams("uid", InfoEL.getMemberUid());
String p = getPara("p", "trade");
if ("self".equals(p)) {
result.put("vo", vo);
result.put("count", selfOrderService.countTotal(vo));
result.put("list", selfOrderService.getList(vo, vo.createRowBounds()));
renderJsonDone(response, result);
}
}
其中BaseConditionVO 為分頁的請求引數,裡面包含如下屬性:
public static int PAGE_SHOW_COUNT = 50;// 預設一頁為50行
private int pageNum = 1;//第幾頁
private int numPerPage = 0;// 一頁顯示多少行資料
private long totalCount = 0;// 總頁數
private String orderField = "";// 排序欄位
private String orderDirection = "";// 排序方式
/**
* @Fields ps : 對引數型別進行封裝,同時方便儲存其他引數
*/
private Map<String, Object> mo = new HashMap<String, Object>();
其中renderJsonDone為返回json字串的方法:
private void renderJson(HttpServletResponse response, String jsonText) {
PrintWriter writer = null;
try {
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType(contentType);
writer = response.getWriter();
writer.write(jsonText);
writer.flush();
} catch (IOException e) {
throw new OrderException(e.getMessage());
} finally {
if (writer != null)
writer.close();
}
}
protected void renderJsonDone(HttpServletResponse response, final Object value) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("statusCode", 200);
map.put("result", value);
String jsonText = JSON.toJSONString(map);
renderJson(response, jsonText);
}
那麼,SpringMVC是怎麼分頁的呢?關鍵方法就在:
result.put("count", selfOrderService.countTotal(vo));// 計算總頁數
result.put("list", selfOrderService.getList(vo, vo.createRowBounds()));// 獲取分頁
對於SpringMVC來說,其強大的整合功能就在於此,我們只需要按照這種方式將RowBounds:vo.createRowBounds()
物件傳遞給Mybatis,Mybatis就會自己幫我們處理好分頁,我們並不需要關注分頁的具體細節。
先來來看Mybatis的處理:
<!--列 -->
<sql id="Base_Column_List">
so.*
</sql>
<sql id="queryJoins">
</sql>
<sql id="Base4List">
from otm_self_order so
<include refid="queryJoins"/>
where so.del_flag = 0
<if test="mo.status != null">
and so.status = #{mo.status}
</if>
<if test="mo.uid != null">
and so.uid = #{mo.uid}
</if>
<if test="mo.cancel != null">
and so.cancel = #{mo.cancel}
</if>
</sql>
<select id="getList" resultMap="BaseResultMap" parameterType="map">
select
<include refid="Base_Column_List" />
<include refid="Base4List" />
<choose>
<when test="orderField !=null and orderField !=''">
ORDER BY ${orderField}
<if test="orderDirection != null and orderDirection != ''">${orderDirection}</if>
</when>
<otherwise>
order by so.update_date DESC
</otherwise>
</choose>
</select>
<select id="countTotal" resultType="java.lang.Integer" parameterType="map">
select
count(0)
<include refid="Base4List" />
</select>
好了,說完了客戶端和伺服器端的處理細節,我們來看一下具體的伺服器端返回資料形式,通過Chrome瀏覽器的network面板就可以觀察到,如下圖:
另外,分頁的效果圖如下: