一、场景
公司新开发的一个web项目,项目中一个功能是从失败交易流水表中按日期查询失败的交易,以列表的形式展示出来。前端列表使用了DataTable,DataTable自带前端分页和后端分页。所谓前端分页就是一次性从数据库中查出所有数据返回给前端,前端自动进行分页。这种处理方式在数据量较小的情况下还可以,当数据量较大(具体数据量没有测试)会导致前端加载数据缓慢卡顿,同时因为后端一次性从数据库查出大量数据放在内存中,会导致内存资源消耗过大而卡顿甚至宕机。为了解决这个瓶颈问题,采用后端分页的形式。后端分页即前端传递当前页码以及当前页显示的数据量给后端,后端只查询当前页要进行展示的数据。从而避开了由于数据量过大而导致的卡顿问题。
二、基础代码
DataTable默认的分页机制为前端分页,此处不过多陈述,通过查找资料了解到,后端分页需要将原来的
1 | bServerSide:false |
修改为:
1 | bServerSide:true |
后端分页对返回的JSON数据格式有要求,具体格式如下:
1 | {"sEcho":"1","iTotalRecords":"0","iTotalDisplayRecords":"0","aaData":[]} |
其中sEcho是前端传递的,只需获取然后原数返回即可,iTotalRecords字面理解意思是当前数据表中总的记录数,iTotalDisplayRecords是当前页面要展示的记录数,aaData为返回列表的数据。
这里先展示一版基础代码,也就是我从网上查找资料写的代码,通过基础代码,后边一步一步的发现问题解决问题。
HTML部分:
1 | </div> |
JS部分:
1 | function dataTableDraw(){ |
后端Controller层:
1 | "/page/getTrafficMonitorFailedList",method=RequestMethod.POST) (value= |
第一版的基础代码如上,其中有一些如数据Model的代码,不同业务场景Model不同,此处不做列举。
三、问题描述/解决
Q1.Cannot read property ‘length’ of undefined
上述代码运行之后,页面加载之后一直显示加载中,F12到调试模式可以看到控制台报错“Cannot read property ‘length of undefined’”,而且这个是jquery报的错,可以说是非常恼火了。经过分析,可能是返回的数据格式不对,因此在js的回调函数中进行了修改,将JSON字符串转换成JSON数据的格式,修改后如下:
1 | $.ajax({ |
修改之后运行,此问题解决
Q2.DataTables warning (table id = ‘trafficMonitorFailed’):Requested unknown parameter ‘0’ from the data source for row 0
上述代码运行之后,页面弹窗报错“DataTables warning (table id =’trafficMonitorFailed’):Requested unknown parameter ‘0’ from the data source for row 0”这个问题诈一看也是一脸蒙蔽,后来发现应该是dataTable版本的问题,需要将数据表中的mData修改为mDataProp,修改之后如下:
1 | { "mDataProp": "tranDate","fnRender":function(data,val){ |
修改之后运行,问题解决。
Q3.数据明明很多,DataTable仅显示了一页的数据,并且没有显示其它页的按钮,不可以翻页。
这个问题的意思是,我数据库中有很多数据,F12调试也能看到返回了一页10条数据,并且iTotalRecords为32,按道理应该显示一页数据之后,可以进行翻页,总共显示4页,但是实际的页面却只显示了一页数据,列表下方的翻页处也仅仅有“1”的页签,没有其它的页签,上一页下一页都不能点击。这个问题困扰了我许久,后来私信网上一位大神给出了解决方案。原因是iTotalRecords和iTotalDisplayRecords数据放反了。这个我到现在也没有理解,按照字面意思itotalRecords确实是应该放总查询数据量,iTotalDisplayRecords为当前页要展示的数据量。而实际的使用过程中,这两个数据应该是反了过来。不知道其它人有没有遇到这种情况。
修改代码如下:
1 | getObj.put("iTotalRecords",trafficMonitorFailed.size()); |
即将原来两个放置数据统计个数的值互换。运行之后,问题解决,心心念念的后端分页终于实现了。
Q4.后端分页实现之后,检索筛选、排序功能失效。
实现了基本的后端分页,点击了几页试了一下,分页效果没问题,但是检索跟排序的功能都没有反应。于是F12开启调试模式,发现点击排序和在检索框输入文字之后,都发起了后台请求,因此可以判定,后端分页的检索跟排序功能需要后端代码实现。实现原理,在前端传递的aoData中,会储存要排序的列、排序的方式以及检索的内容。因此可以通过后端修改SQL的形式完成。
修改之后的Controller代码为:
1 | "/page/getTrafficMonitorFailedList",method=RequestMethod.POST) (value= |
这里前端传递的orderColumn是int类型,标记的是列的序号,SQL语句中可以判断序号然后ORDER BY指定的列,orderDir传递的是排序方式有两种一种是ASC另一种是DESC。sSearch传递的是检索框的内容,这里为了避免没有检索的情况还使用like语句模糊查找而影响效率,没有想到其它办法,单单的使用了判断sSearch如果为空则不使用like语句查找。多说一句,分页查询使用的sql语句我这里使用了limit a,b的形式,从a+1位置查,查b条数据。这里忘了贴SQL语句,大概的形式就是select xxx from xxx where xxx order by xxx asc/desc limit a,b 这种,如果后期数据量大了出现瓶颈再继续优化。
Q5.给DataTable增加横向滚动条
为了美观,我想保证每一条数据都在一行上显示,不进行换行。然后就会出现数据过长,一页显示不下的情况,因此需要增加滚动条。网上查到不同版本使用的形式不同,我这里是使用如下形式
1 | sScrollX:"100%" |
还有另一种方式是将“100%”改为true的形式。增加滚动条还需要设置文本框的数据处于一行显示而不是自动换行。
修改html代码如下:
1 | </div> |
即增加了样式:
1 | style="white-space:nowrap" |
至此,后端分页的功能全部实现。如有不足,还望指正。