DataTables的服务器端(SpringMVC)分页模式

简介: 版权声明:欢迎转载,请注明沉默王二原创。 https://blog.csdn.net/qing_gee/article/details/82285030 Datatables是一款jquery表格插件。
版权声明:欢迎转载,请注明沉默王二原创。 https://blog.csdn.net/qing_gee/article/details/82285030

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面板就可以观察到,如下图:

这里写图片描述

另外,分页的效果图如下:

这里写图片描述

相关文章
|
29天前
|
存储 SQL 安全
什么是传统的客户端服务器模式架构
什么是传统的客户端服务器模式架构
41 0
|
29天前
|
存储 弹性计算 编解码
ecs实例规格工作负载模式
阿里云ECS实例有多种工作负载模式:计算密集型(适合高性能计算)、内存密集型(适用于内存数据库)、通用型(平衡资源,多场景适用)、大数据型(优化大数据分析)、共享型(低成本,轻负载)和企业级实例(高稳定性和隔离性)。用户依据业务需求选择实例规格,结合SLB和ESS服务可优化架构,应对动态负载。
30 4
|
29天前
|
存储 设计模式
用反应器模式和epoll构建百万并发服务器
用反应器模式和epoll构建百万并发服务器
43 0
|
29天前
|
移动开发 前端开发 JavaScript
VSCode设置类似Webstorm那样可以用本地局域网IP地址访问自己开发的测试项目,vs code 前端如何以服务器模式打开?
VSCode设置类似Webstorm那样可以用本地局域网IP地址访问自己开发的测试项目,vs code 前端如何以服务器模式打开?
VSCode设置类似Webstorm那样可以用本地局域网IP地址访问自己开发的测试项目,vs code 前端如何以服务器模式打开?
|
29天前
|
弹性计算 供应链
阿里云服务器付费模式包年包月、按量付费、抢占式实例选择说明
阿里云ECS提供包年包月、按量付费和抢占式实例三种计费方式。选择建议:稳定需求选包年包月,动态需求选按量付费,无状态应用选抢占式实例以降低成本。可结合使用按量付费、预留实例券和节省计划以平衡灵活性和成本。需要资源保障则组合按量付费和资源保障。具体详情和规定可参考阿里云ECS官方文档
277 7
|
29天前
|
监控 安全 持续交付
【专栏】Webhook是服务器主动发送事件通知的机制,打破传统客户端轮询模式,实现数据实时高效传递。
【4月更文挑战第29天】Webhook是服务器主动发送事件通知的机制,打破传统客户端轮询模式,实现数据实时高效传递。常用于持续集成部署、第三方服务集成、实时数据同步和监控告警。具有实时性、高效性和灵活性优势,但也面临安全风险和调试挑战。理解并善用Webhook能提升系统性能,广泛应用于现代软件开发和集成。
|
29天前
|
网络协议 网络架构 Windows
解锁远程联机模式:使用MCSM面板搭建我的世界服务器,并实现内网穿透公网访问
解锁远程联机模式:使用MCSM面板搭建我的世界服务器,并实现内网穿透公网访问
115 0
|
8月前
|
设计模式 网络协议 Java
Reactor 模式网络服务器【I/O多路复用】(C++实现)
Reactor 模式网络服务器【I/O多路复用】(C++实现)
309 0
|
29天前
|
弹性计算
阿里云服务器“带宽计费模式”详细说明_2024固定带宽和流量详解
阿里云服务器“带宽计费模式”详细说明_2024固定带宽和流量详解,按固定带宽是指直接购买多少M带宽,比如1M、5M、10M、100M等,阿里云直接分配用户所购买的带宽值,根据带宽大小先付费再使用;按使用流量是先设置一个带宽峰值,然后根据实际公网产生的出流量来计算费用,先使用后付费
166 1
|
29天前
|
弹性计算
阿里云服务器的带宽计费模式是什么意思?咋收费的?
阿里云服务器带宽计费模式分为“按固定带宽”和“按使用流量”,有什么区别?按固定带宽是指直接购买多少M带宽,比如1M、5M、10M、100M等,阿里云直接分配用户所购买的带宽值,根据带宽大小先付费再使用;按使用流量是先设置一个带宽峰值,然后根据实际公网产生的出流量来计算费用,先使用后付费。阿里云百科分享阿里云服务器“带宽计费模式”详细区别、计费及注意事项