DataTables API及服务端处理模式介绍和后端分页案例

一.DataTables概述

Datatables是一款jquery表格插件.是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能.支持

  • 分页,即时搜索和排序
  • 支持数据源: DOM, JavaScript, Ajax 和服务器处理
  • 支持不同的主题: DataTables, jqueryUI, Bootstrap, Foundation
  • 支持国际化和多样的option选项

官方网址:

1.处理数据的三个核心概念

1.1 处理模式(processing modes)

DataTables 中有两种不同的方式处理数据(排序、搜索、分页等):

  • 客户端处理(Client)—— 所有的数据集预先加载(一次获取所有数据),数据处理都是在浏览器中完成的【逻辑分页】, 适用于数据量小。
  • 服务器端处理(ServerSide)—— 数据处理是在服务器上执行(页面只处理当前页的数据)【物理分页】,适用于数据量大。

注意:两种处理模式不能同时使用,但是可以动态更改从一个模式到另一个。

1.2 数据源类型(data source types)

DataTables 使用的数据源必须是一个数组,数组里的每一项将显示在你定义的行上面,DataTables 可以使用三种基本的 JavaScript 数据类型来作为数据源:

  • 数组(Array [])
  • 对象(object {}) -- 常使用
  • 实例(new myclass())
1.3 数据源(data sources)

DataTables 支持三种数据源显示:

  • DOM
  • Javascript
  • Ajax -- 常使用

2.安装datatables插件

将media文件下的内容全部放到工程下,html页面引入即可使用:

<!-- jQuery -->
<script type="text/javascript" src="media/js/jquery.js"></script>

<!-- DataTables -->
<link rel="stylesheet" type="text/css" href="media/css/jquery.dataTables.css">
<script type="text/javascript" src="media/js/jquery.dataTables.js"></script>

继续在html页面引入datatables的bootstrap样式:

<!-- CSS -->
<link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="media/css/dataTables.bootstrap4.css">
<!-- jQuery -->
<script type="text/javascript" src="media/js/jquery.js"></script>
<!-- dataTables.js -->
<script type="text/javascript" src="media/js/jquery.dataTables.js"></script>
<script type="text/javascript" src="media/js/dataTables.bootstrap4.js"></script>

3.Option API

文档: http://datatables.club/reference/option/

国际化zh_CN.json文件:

{
    "sProcessing": "处理中...",
    "sLengthMenu": "显示 _MENU_ 项结果",
     "sZeroRecords": "没有匹配结果",
     "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
     "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
     "sInfoFiltered": "(由 _MAX_ 项结果过滤)",
     "sInfoPostFix": "",
     "sSearch": "搜索:",
     "sUrl": "",
     "sEmptyTable": "表中数据为空",
     "sLoadingRecords": "载入中...",
     "sInfoThousands": ",",
     "oPaginate": {
        "sFirst": "首页",
        "sPrevious": "上页",
        "sNext": "下页",
        "sLast": "末页",
        "sJump": "跳转"
     },
     "oAria": {
         "sSortAscending": ": 以升序排列此列",
         "sSortDescending": ": 以降序排列此列"
     }
}

常用Option API介绍:

$(function() {
  $("#table_id").DataTable({
    language: {	//异步加载翻译,支持国际化
      url:"dist/zh_CN.json"	//在static资源文件夹下
    },
    info: true,	//显示页脚信息
    lengthChange: true, //显示更换记录数下拉选
    aLengthMenu : [6, 16, 32, 64], //更改显示记录数选项
    iDisplayLength : 6, //默认显示的记录数
    
    searching: false, //禁用原生搜索
    filter: false, //去掉搜索框方法,过滤功能
    
    ordering: true,	//开启排序
    orderMulti: false, //禁用多列排序
    order: [[ 3, "desc" ]], //取消默认排序查询,否则复选框一列会出现小箭头
    buttons:  ['copy', 'excel', 'pdf']	//开启下载数据为各种格式按钮
    
    renderer: "bootstrap", //渲染样式:Bootstrap和jquery-ui
    stripeClasses: ["odd", "even"], //为奇偶行加上样式,兼容不支持CSS伪类的场合
    
    paging: true,	//开启分页
    pageLength: 3, //每页显示3条数据,pagesize
    pagingType: "simple_numbers", //分页样式:simple,simple_numbers,full,full_numbers
    
    scrollX: true,  //启动水平滚动
    sScrollX : 820, //指定DataTables的宽    
    scrollY: true,	//启动垂直滚动
    sScrollY : 560, //指定DataTables的高
    autoWidth: false, //禁用自动调整列宽
    
    processing: true, //显示加载提示,自行处理
    serverSide: true, //开启服务器端分页
    ajax: {	//使用ajax异步请求的方式加载数据(包括处理分页,排序,搜索)
        url: '/data-source',	//请求的URL地址
        type: 'GET'	//使用GET请求的方式
    },
	columns: [	// 指定数据源,与服务器端响应的数据一一对应,使用对象数组
      { data: 'buildName', width: "60px", defaultContent: "<i></i>"},
      { data: 'totalCases', width: "120px", defaultContent: "<i></i>"},
      { data: 'failCases', width: "120px", defaultContent: "<i></i>"},
      { data: 'passRate', width: "120px", defaultContent: "<i></i>"},
      { data: 'detail', width: "120px", defaultContent: "<i></i>"},
      { data: 'loginfo', width: "120px", defaultContent: "<i></i>"}   
    ],
    columnDefs: [{
      "targets": 'nosort', //指定class为nosort的列
      "orderable": false, //包含上样式名‘nosort'的禁止排序
      "data": 'loginfo',	//指定引用loginfo的数据源
      render: function (data, type, row) {
        //可对数据进行处理,再显示
        var html = '<a  href="'+data+'" target="_blank" class="btn btn-success btn-sm">logInfo</a>';
        return html;
      }
    }],
    
  });
});

二.服务器处理模式

表格数据量如果很大,超过5000行的话,建议使用后台分页功能。关于这个功能的一些参数:

  • 开关:表格初始化时的选项,字段为serverSide,true表示使用后台分页功能

  • datatables发送的数据:使用ajax自定义的方法时, data字段增加了下面三个属性, start和length其实对应的是sql语句limit之后的两个参数

    描述 字段
    draw 绘制计数器。这个是用来确保Ajax从服务器返回的是对应的(Ajax是异步的,因此返回的顺序是不确定的)。 要求在服务器接收到此参数后再返回
    start 第一条数据的起始位置,比如0代表第一条数据
    length 告诉服务器每页显示的条数,这个数字会等于返回的 data集合的记录数,可能会大于因为服务器可能没有那么多数据。这个也可能是-1,代表需要返回全部数据(尽管这个和服务器处理的理念有点违背)
    其它 还有一些字段指定了哪些列需要排序 和 搜索条件等
  • datatables接受的数据:要求4个参数,分别是:

    • draw请求时的标记字段 ,直接返回
    • recordsTotal,表格总长度,总记录数
    • recordsFiltered,根据返送的过滤条件 过滤后的数据数,通常可以直接和recordsFiltered相同
    • data,表中中需要显示的数据。这是一个对象数组,也可以只是数组,区别在于 纯数组前台就不需要用 columns绑定数据,会自动按照顺序去显示 ,而对象数组则需要使用 columns绑定数据才能正常显示。

需要注意的是,对于后台返回空时,需要将表格长度置为0,否则表格下面的分页按钮不会变化,延续上次结果

1.html页面中table

<!-- 冒烟 -->
<div class="row" id="pre_alpha_smoke">
  <div class="col-md-12">
    <h4 class="text-center bg-secondary" style="margin: 24px 0px;">冒烟</h4>

    <table id="pre_alpha_smoke_table" class="table table-bordered table-striped" style="width: 100%;">
      <thead align='center' valign="middle">
        <tr>
          <th>版本名称</th>
          <th>总用例数</th>
          <th>失败用例数</th>
          <th>脚本通过率</th>
          <th>测试结果</th>
          <th>日志信息</th>
        </tr>
      </thead>
      <tbody align='center' valign="middle">
        <tr>
          <td>1902v52</td>
          <td>188</td>
          <td>16</td>
          <td><span class="badge bg-success">100%</span></td>
          <td>ok</td>
          <td><a href="http://10.150.99.10:8080/jenkins/job/SMOKE_TEST_5/926/consoleText" target="_blank">logLink</a></td>
        </tr>
      </tbody>
    </table>
  </div>
  <!-- /.col -->
</div>
<!-- /.row -->

2.table的js文件

$(function () {
    var catalog = 'smoke';
    var project = 'X653C-H6114GH-PGo';
    var starttime = '2019-08-30 00:00:01';
    var endtime = '2020-01-16 23:59:59';

    //封装相应的请求参数,这里获取页大小和当前页码
    // var param = {};
    // param.pagesize = data.length;//页面显示记录条数,在页面显示每页显示多少项的时候,页大小
    // param.start = data.start;//开始的记录序号
  	// param.draw = data.draw;//标记字段
    // param.currentPage = (data.start) / data.length + 1;//当前页码

    $("#pre_alpha_smoke_table").DataTable({
        // 语言国际化
        language: {
            url:"dist/zh_CN.json"
        },
        info : true,
        paging: true,
        aLengthMenu : [6, 16, 32, 64], //更改显示记录数选项
        iDisplayLength : 6, //默认显示的记录数
        // pageLength: 3, //每页显示3条数据
        processing: false,   //显示加载提示,自行处理
        searching: true,    //显示原生搜索
        stripeClasses: ["odd", "even"], //为奇偶行加上样式,兼容不支持CSS伪类的场合
        pagingType: "full_numbers", //分页样式:simple,simple_numbers,full,full_numbers
        serverSide: true,   //开启服务器模式
        //数据来源(包括处理分页,排序,过滤) ,即url,action,接口,等等
        ajax: function (data, callback, setting) {
            var flag = data.draw;//标记字段
            var pagesize = data.length;//当前页大小
            var currentPage = (data.start) / data.length + 1;//当前页码
            $.ajax({
                type: "GET",
                url: "http://localhost:8081/api/testresult/"+catalog+"/"+project+"/"+starttime+"/"+endtime+"/"+currentPage+"/"+pagesize,
                cache: false, //禁用缓存
                data: {}, //传入组装的参数
                dataType: "json",
                success: function (result) {
                    console.log(result);
                    var returnData = {};
                    // returnData.draw = result.pageInfo.draw;//这里直接自行返回了draw计数器,应该由后台返回,没什么卵用!
                    returnData.recordsTotal = result.pageInfo.recordsTotal;//返回数据全部记录
                    returnData.recordsFiltered = result.pageInfo.recordsFiltered;//后台不实现过滤功能,每次查询均视作全部结果
                    returnData.data = result.pageInfo.data;//返回的数据列表
                    //此时的数据需确保正确无误,异常判断应在执行此回调前自行处理完毕
                    callback(returnData);
                }
            });
        },
        //使用对象数组,一定要配置columns,告诉 DataTables 每列对应的属性
        //data 这里是固定不变的,name,position,salary,office 为你数据里对应的属性
        columns: [
            { data: 'buildName' },
            { data: 'totalCases' },
            { data: 'failCases' },
            { data: 'passRate' },
            { data: 'detail' },
            {
                data: 'loginfo'
                /*render: function (data, type, full) {
                    //可对数据进行处理,再显示
                    var html = '<a  href="'+data+'" target="_blank" class="btn btn-success btn-sm">logInfo</a>';
                    return html;
                }*/
            }
        ],
        "columnDefs" : [{
            "targets" : 5,  //索引从0开始,将索引值所在的列重新定义
            "data" : 'loginfo',
            render: function (data, type, full) {
                //可对数据进行处理,再显示
                var html = '<a  href="'+data+'" target="_blank" class="btn btn-success btn-sm">logInfo</a>';
                return html;
            }
        }],
        //列样式处理
        "fnRowCallback": function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
        },
        // 切换下一页更新复选框的状态为不选中:重绘的回调函数,更新状态
        "fnDrawCallback" : function() {
        },
    });

})

3.后端Controller类

@RestController
@RequestMapping("/api")
public class SmokeResultController {
  
  private final Logger log =  LoggerFactory.getLogger(SmokeResultController.class);

  @Autowired
  private SmokeResultService smokeResultService;
  
  // 获采用datatables前端插件的服务器端处理模式  -- 后端分页(需要传入currentPage和pageSize)
  @GetMapping("/testresult/{catalog}/{project}/{starttime}/{endtime}/{currentPage}/{pagesize}")
  public ResponseEntity<TestResultResponse> getPhaseSmokeResult(@PathVariable("catalog")String catalog,@PathVariable("project")String project,@PathVariable("starttime")String starttime,@PathVariable("endtime")String endtime,
@PathVariable("currentPage")Integer currentPage,@PathVariable("pagesize")Integer pagesize){
    log.debug("REST request to get {} phase smoke result from {} to {} ", project, starttime, endtime);
    TestResultResponse response = smokeResultService.getPhaseSmokeResult(catalog,project,starttime,endtime,currentPage,pagesize);
    return new ResponseEntity<>(response, HttpStatus.OK);
  }
  
}

serviceImpl类:

@Service
public class SmokeResultServiceImpl implements SmokeResultService{
  
  @Autowired
  private SmokeResultMapper smokeResultMapper;
  
  @Override
    public TestResultResponse getPhaseSmokeResult(String catalog, String project, String starttime, String endtime, Integer currentPage, Integer pagesize) {
        PageHelper.startPage(currentPage, pagesize);//pageHelper分页插件,只对后续一条语句起作用
        List<SmokeResult> smokeResultList = smokeResultMapper.getPhaseSmokeResult(project,starttime,endtime);
        PageInfo<SmokeResult> pageInfo = new PageInfo<>(smokeResultList);
        TestResultResponse response = new TestResultResponse();
        response.setCatalog(catalog).setProject(project).setStarttime(starttime).setEndtime(endtime).setPageInfo(pageInfo);
        return response;
    }
  
}

entity类:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class TestResultResponse {

	private String project;
	private String version;
	private String starttime;
	private String endtime;
	private String pass;
	private String fail;
	private String total;
    private String catalog;
	private PageInfo pageInfo;

}

4.PageInfo类

public class PageInfo<T> {

    private Integer draw;//绘制计数器
    private Integer start;//每页第一条数据的起始位置
    private Integer length;//每页显示的条数
    private Long recordsTotal;//总记录数
    private Long recordsFiltered;//过滤后的数据数
    private List<T> data;//表中需要显示的数据
    
}

5.效果图

在这里插入图片描述

三.客服端处理模式

当数据量比较小时,可以采用datatables自动分页,一次将数据全部获取,分页交给浏览器处理,逻辑分页.这里就不需要开启serverSide和使用自带的ajax请求了.

$(function() {
    $("#pre_alpha_smoke_table").dataTable({	// 客户端模式这样初始化配置就可以
        language: {
          url:"dist/zh_CN.json"
        },
        "aLengthMenu" : [3, 16, 32, 64], //更改显示记录数选项
        "iDisplayLength" : 3, //默认显示的记录数
        "lengthChange": false,	//禁用更换记录数的下拉选
        "searching": false,	//禁用搜搜框
    });
  
  	var starttime = '2020-03-02 01:51:20';
    var endtime = '2020-03-02 12:51:20';
  
    ajax({
      type: 'get',
      dataType: 'json',
      url: 'http://localhost:8081/api/testresult/smoke/HIOS6.0-Q-MP-KB8-P70/all',
      data: {
        'starttime': starttime,
        'endtime': endtime
      },
      cache: false,
      async: true,
      success: function (data) {
        console.log(data);
        // 获取项目名称
        $("#projectname").html(data.project);

        // 获取pre-alpha的monkey上海数据
        var monkey_sh = data.detail.results[0];
        console.log(monkey_sh);

        // 动态生成monkey_sh table中的数据
        $("#pre_alpha_monkey_sh_table").dataTable().fnClearTable();     //清空一下table
        $("#pre_alpha_monkey_sh_table").dataTable().fnDestroy();        //还原初始化了的datatable
        $("#pre_alpha_monkeysh_tbody").empty();

        //for(var i=0;i<monkey_sh.length;i++){
        var $tr = $("<tr></tr>");
        $tr.append("<td>"+monkey_sh.round+"</td>");
        $tr.append("<td>"+monkey_sh.version+"</td>");
        $tr.append("<td>"+monkey_sh.dppm+"</td>");
        $tr.append("<td>"+monkey_sh.samples+"</td>");
        $tr.append("<td>"+monkey_sh.HWT+"</td>");
        $tr.append("<td>"+monkey_sh.SWT+"</td>");
        $tr.append("<td>"+monkey_sh.FatalJE+"</td>");
        $tr.append("<td>"+monkey_sh.FatalNE+"</td>");
        $tr.append("<td>"+monkey_sh.KE+"</td>");
        $tr.append("<td>"+monkey_sh.JE+"</td>");
        $tr.append("<td>"+monkey_sh.NE+"</td>");
        $tr.append("<td>"+monkey_sh.ANR+"</td>");
        $("#pre_alpha_monkeysh_tbody").append($tr);
		//}

      	//dataTable重新渲染
      	$("#pre_alpha_monkey_sh_table").dataTable({
            language: {
              url:"dist/zh_CN.json"
            },
             "aLengthMenu" : [3, 16, 32, 64], //更改显示记录数选项
             "iDisplayLength" : 3, //默认显示的记录数
             "lengthChange": false,
             "searching": false,
         });
      },
      error: function (msg) {
        alert("网络延迟,请待会加载......");
      }
  });
})
posted @ 2020-03-07 18:19  zlgSmile  阅读(788)  评论(0编辑  收藏  举报