spring mvc +bootstrap+datatable实现分页

文章介绍大致分以下几步:
1. 后台数据分页查询实现;
2. 前台bootstrap样式+datatable插件 数据渲染;

一、后台真分页实现:
主要涉及以下内容:
1、数据库分页插件类PagePlugin.java;
2、分页参数类Page.java;
3、排序类SortCond.java;
4、用来返回datatables格式数据的DataTables.java(不使用datatables时不需要);
5、mybatis-config.xml配置插件;
6、相关mapper.xml文件SQL;
7、controller层参数传递;
直接上代码:
1、PagePlugin.java

package com.bi.dao.base.plugin;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

import javax.xml.bind.PropertyException;

import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

import com.bi.common.base.entity.Page;
import com.bi.common.util.ReflectHelper;
import com.bi.common.util.Tools;

/**
 * 
 * 

功能描述:

*

Company:

* @author Jeff * @version 1.0 2015年12月9日 */
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})}) public class PagePlugin implements Interceptor { private static String dialect = ""; //数据库方言 private static String pageSqlId = ""; //mapper.xml中需要拦截的ID(正则匹配) public Object intercept(Invocation ivk) throws Throwable { // TODO Auto-generated method stub if(ivk.getTarget() instanceof RoutingStatementHandler){ RoutingStatementHandler statementHandler = (RoutingStatementHandler)ivk.getTarget(); BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate"); MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement"); if(mappedStatement.getId().matches(pageSqlId)){ //拦截需要分页的SQL BoundSql boundSql = delegate.getBoundSql(); Object parameterObject = boundSql.getParameterObject();//分页SQL\n"); sb.append("
  • 跳转
  • \n"
    ); sb.append("
  • 首页
  • \n"
    ); sb.append("
  • 上页
  • \n"
    ); } else { sb.append("
  • " + totalResult + "
  • \n"
    ); sb.append("
  • \n"
    ); sb.append("
  • 跳转
  • \n"
    ); sb.append("
  • 首页
  • \n"
    ); sb.append("
  • + (currentPage - 1) + ")\">上页
  • \n"
    ); } int showTag = 5;// 分页标签显示数量 int startTag = 1; if (currentPage > showTag) { startTag = currentPage - 1; } int endTag = startTag + showTag - 1; for (int i = startTag; i <= totalPage && i <= endTag; i++) { if (currentPage == i) sb.append("
  • " + i + "
  • \n"
    ); else sb.append("
  • + i + ")\">" + i + "
  • \n"
    ); } if (currentPage == totalPage) { sb.append("
  • 下页
  • \n"
    ); sb.append("
  • 尾页
  • \n"
    ); } else { sb.append("
  • + (currentPage + 1) + ")\">下页
  • \n"
    ); sb.append("
  • + totalPage + ")\">尾页
  • \n"
    ); } sb.append("
  • 第" + currentPage + "页
  • \n"
    ); sb.append("
  • 共" + totalPage + "页
  • \n"
    ); sb.append("
  • \n"); sb.append("
  • \n"
    ); sb.append("\n"); sb.append("\n"); } pageStr = sb.toString(); return pageStr; } public void setPageStr(String pageStr) { this.pageStr = pageStr; } public int getShowCount() { return showCount; } public void setShowCount(int showCount) { this.showCount = showCount; } public int getCurrentResult() { currentResult = (getCurrentPage() - 1) * getShowCount(); if (currentResult < 0) currentResult = 0; return currentResult; } public void setCurrentResult(int currentResult) { this.currentResult = currentResult; this.currentPage = (currentResult / showCount) + 1; } public boolean isEntityOrField() { return entityOrField; } public void setEntityOrField(boolean entityOrField) { this.entityOrField = entityOrField; } public PageData getPd() { return pd; } public void setPd(PageData pd) { this.pd = pd; } }

    3、SortCond.java

    package com.bi.common.base.entity;
    
    /**
     * 

    功能描述:排序类

    *

    Company:

    * @author Jeff * @version 1.0 2015年12月11日 */
    public class SortCond { /** * 排序类型枚举 */ public enum Order { ASC, DESC } /** * 排序类型 */ private String column; /** * 排序类型 */ private Order order; public SortCond(String column) { this(column, Order.DESC); } public SortCond(String column, Order order) { this.column = column; this.order = order; } public String getColumn() { return column; } public Order getOrder() { return order; } }

    4、DataTables.java

    /**
     * 文件名: DataTables.java
     * 版    权: Copyright © 2013 - 2015 ThinkJF, Inc. All Rights Reserved
     * 描    述: <描述>
     * 创建人: Jeff
     * 创建时间: 2015年12月10日
     */
    package com.bi.common.base.entity;
    
    import java.io.Serializable;
    import java.util.List;
    
    import org.apache.poi.ss.formula.functions.T;
    
    /**
     * 

    功能描述:datatables数据返回实体类

    *

    Company: 上海丞风智能科技有限公司

    * @author Jeff * @version 1.0 2015年12月10日 */
    public class DataTables implements Serializable{ private static final long serialVersionUID = 8172262630982712326L; //与datatales 加载的“dataSrc"对应 private List data; //过滤后的记录数 private int recordsFiltered; //数据库里总共记录数 private int recordsTotal; //请求次数计数器 private int draw; private Boolean success; public List getData() { return data; } public void setData(List data) { this.data = data; } public int getRecordsFiltered() { return recordsFiltered; } public void setRecordsFiltered(int recordsFiltered) { this.recordsFiltered = recordsFiltered; } public int getRecordsTotal() { return recordsTotal; } public void setRecordsTotal(int recordsTotal) { this.recordsTotal = recordsTotal; } public int getDraw() { return draw; } public void setDraw(int draw) { this.draw = draw; } }

    5、mybatis-config.xml配置插件
    指定方言为mysql,且配置sqlid以_page结尾的都走分页查询

        <plugins>
            <plugin interceptor="com.bi.dao.base.plugin.PagePlugin">
                <property name="dialect" value="mysql"/>
                <property name="pageSqlId" value=".*_page"/>
            plugin>
        plugins>

    6、相关mapper.xml文件SQL
    拿查询用户列表来举例:

        <sql id="userSort">
             <if test="pd.sortCond != null and pd.sortCond.size() != 0">
                    order by
                    <foreach collection="pd.sortCond" item="sortCond" separator=",">
                        ${sortCond.column} ${sortCond.order}
                    foreach>
             if>  
        sql>
        <select id="listAllUser_page" parameterType="Page" resultMap="userResultMap" useCache="false">
            select  u.USER_ID,
                    u.USER_NAME,
                    u.USER_PWD,
                    u.USER_SEX,
                    u.USER_ADDRESS,
                    u.E_MAIL,
                    u.USER_PHOTO,
                    u.USER_PHONE,
                    u.DEPT_ID,
                    u.USER_STATUS,
                    u.CREATE_BY,
                    u.CREATE_TIME,
                    u.LAST_LOGIN_TIME,
                    u.SKIN 
            from BI_SYS_USER u
            where u.USER_NAME != 'admin'
            <if test="pd.userName != null and pd.userName != ''">
                and u.USER_NAME LIKE CONCAT(CONCAT('%', #{pd.userName}),'%')
            if>
            <if test="pd.userPhone != null and pd.userPhone != ''">
                and u.USER_PHONE=#{pd.userPhone} 
            if>
            <if test="pd.deptId!=null and pd.deptId!=''">
                and u.DEPT_ID = #{pd.deptId} 
            if>
            <if test="pd.userStatus!=null and pd.userStatus!=''">
                and u.USER_STATUS = #{pd.userStatus} 
            if>
            <include refid="userSort">include>
        select>

    7、controller类部分代码:

        @RequestMapping(value="/userSearch")
        @ResponseBody
        public Object userSearch(Page page){
            PageData pd = new PageData();
            pd = this.getPageData();
            page.setPd(pd);
    
            //调用封装方法,构造page参数
            page = DataTablesUtil.constructPd(page);
            //构造分页查询param------end------------
            //分页查询(查询SQL id必须以"_page"结尾)
            List  userList = userService.listAllUser_page(page);
    
            //设置datatables要求返回的数据-----start-------
            /**
             * draw:请求次数计数器 要求原样返回
             * Data:查询结果List
             * recordsTotal:查询结果总数
             * recordsFiltered:过滤条件后的结果总数(一般与查询结果总数一致)
             */
            DataTables dts = new DataTables();
            dts.setDraw(Integer.parseInt(pd.get("draw").toString()));
            dts.setData(userList);
            dts.setRecordsTotal(page.getTotalResult());
            dts.setRecordsFiltered(page.getTotalResult());
            //设置datatables要求返回的数据-----end-------
    
            return dts;
        }

    8、补充一个DataTablesUtil.java
    主要实现将前端传过来的参数处理后构造好Page类供查询service方法使用。

    /**
     * 文件名: DataTablesUtil.java
     * 版    权: Copyright © 2013 - 2015 ThinkJF, Inc. All Rights Reserved
     * 描    述: <描述>
     * 创建人: Jeff
     * 创建时间: 2015年12月11日
     */
    package com.bi.common.util;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.bi.common.base.entity.Page;
    import com.bi.common.base.entity.SortCond;
    
    /**
     * 

    * 功能描述:dataTables工具类 *

    *

    * Company: *

    * * @author Jeff * @version 1.0 2015年12月11日 */
    public class DataTablesUtil { /** * 构造Page类,包括设置startIndex,pageSize以及pd对象的查询参数及排序参数 * @author Jeff * @version 1.0 2015年12月11日 * @param page * @return */ public static Page constructPd(Page page) { PageData pd = new PageData(); pd = page.getPd(); // 获取前端datatables参数---------start-------------- // desc:draw,start,length // 计数器 int draw = Integer.parseInt(pd.get("draw").toString()); // 数据起始位置 int startIndex = Integer.parseInt(pd.get("startIndex").toString()); // 数据长度 int pageSize = Integer.parseInt(pd.get("pageSize").toString()); // 根据列索引获取该列列名 String ColumnName = pd.getString("sortName"); // 是降序还是升序 String sortDir = pd.getString("sortDir"); // 获取前端参数---------end-------------- // 构造分页查询param------start------------ // desc:pageSize,currentResult,sortCond page.setShowCount(pageSize); page.setCurrentResult(startIndex); // 排序设置 if (ColumnName != null && !"".equals(ColumnName)) { List lsc = new ArrayList(); SortCond sc = new SortCond(ColumnName, "asc".equals(sortDir) ? SortCond.Order.ASC : SortCond.Order.DESC); lsc.add(sc); pd.put("sortCond", lsc); } //将设置覆盖原pd page.setPd(pd); return page; } }

    二、前台bootstrap样式+datatable插件 数据渲染;
    涉及到以下内容:
    1、bootstrap与datatables相关css与js;
    2、构造dataTables相关对象,设置相关参数;
    3、html代码

    1、css与js,可以直接上官网扒
    dataTables.bootstrap.min.css
    buttons.bootstrap.min.css
    select.bootstrap.min.css
    editor.bootstrap.min.css

    jquery.dataTables.min.js
    dataTables.bootstrap.min.js
    dataTables.buttons.min.js
    buttons.bootstrap.min.js
    dataTables.select.min.js
    dataTables.editor.min.js
    editor.bootstrap.min.js

    2、构造dataTables相关对象,设置相关参数

    <script type="text/javascript">
    //声明biUserManage对象
    var biUserManage = {
        userTable : null,
        getQueryCondition : function(data) {
            var param = {};
            //处理datatables排序参数
            if (data.order&&data.order.length&&data.order[0]) {
                var indexColumn = data.order[0].column;
                param.sortName = data.columns[indexColumn].name;
                param.sortDir = data.order[0].dir;
            }
            //处理查询参数
            param.userName = $("#searchUserName").val();
            param.userPhone = $("#searchPhone").val();
            param.deptId = $("#searchDeptId").val();
            param.userStatus = $("#searchStatus").val();
            //处理分页参数
            param.startIndex = data.start;
            param.pageSize = data.length;
            param.draw = data.draw;
            return param;
        }
    };
    
    //初始化datatables 
    $(function(){
        biUserManage.userTable =  $('#usertable').dataTable($.extend({
        //设置ajax数据源请求
        ajax: function(data, callback){
            //封装请求参数
            var param = biUserManage.getQueryCondition(data);
            $.ajax({
                    type: "POST",
                    url: "${rc.contextPath}/user/userSearch?systime=" + new Date().getTime(),
                    data: param,
                    dataType: "json",
                    success: function(result) {                 
                        callback(result);                   
                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        alert("查询失败");
                        //$('#div-table-container').spinModal(false);
                    }
                });
        },
        //默认按哪列排序
        order: [ 9, 'desc' ],
        //设置列相关信息
        columns: [//列定义参数
            CONSTANT.DATA_TABLES.CELL_CHECKBOX,
                {
                    "data": "userId",
                    "name": "USER_ID"
                },
                {
                    "data": "userName",
                    "name": "USER_NAME"
                },
                {
                    "data" : "userSex",
                    "name": "USER_SEX",
                    "width" : "80px",
                    "render" : function(data,type, row, meta) {
                        if(data==1){
                            return ' 男';
                        }else{
                            return ' 女';
                        }
                    },
                    "orderable" : false
                },
                {
                    "data":"email",
                    "name": "E_MAIL",
                    "orderable" : false
                },
                {
                    "data":"userPhone",
                    "name": "USER_PHONE",
                    "orderable" : false
                },
                {
                    "data":"dept.deptName",
                    "name": "DEPT_ID"
                },
                {
                    "data": "userAddress",
                    "name": "USER_ADDRESS",
                    "orderable" : false
                },
                {
                    "data" : "userStatus",
                    "name": "USER_STATUS",
                    "width" : "80px",
                    "render" : function(data,type, row, meta) {
                        if(data==0){
                            return "注销";
                        }else if(data==1){
                            return "正常";
                        }else if(data==2){
                            return "暂停";
                        }
                    }
                },
                {
                    "data": "lastLoginTime",
                    "name": "LAST_LOGIN_TIME",
                    "width" : "120px"
                },
                {
                    "data": null,
                    "width" : "80px",
                    "defaultContent":"",
                    "orderable" : false
                }
        ],  
        //在最后一列增加编辑删除按钮             
        "createdRow": function ( row, data, index ) {
                            //行渲染回调,在这里可以对该行dom元素进行任何操作
                            $('td', row).eq(10).addClass("taC");
                            var btnEdit = $('
    '
    ); $('td', row).eq(10).append(btnEdit); } },CONSTANT.DATA_TABLES.DEFAULT_OPTION)).api(); }); //初始化其它 $(function(){ //加载搜索按钮点击事件 $("#btnSearch").click(function(){ biUserManage.isSearch = true; biUserManage.userTable.ajax.reload(); }); }); /*常量*/ var CONSTANT = { DATA_TABLES : { DEFAULT_OPTION : { //DataTables初始化选项 "language": { "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": ": 以降序排列此列" } }, "processing" : false, //隐藏加载提示,自行处理 "serverSide" : true, "searching" : false,//禁用表格内搜索 "lengthMenu" :[10,20,50,100]//定义页面长度组件里面的选项 }, CELL_CHECKBOX : { //复选框单元格 "className" : "cell-chechbox", "orderable" : false, "data": null, "width" : "40px", "render" : function(data, type, row, meta) { return ''; } } } };
    script>

    3、html代码

    <table class="table table-bordered table-hover " id="usertable">
                    <thead>
                        <tr>
                            <th class="taC resource-content-check"><input type="checkbox"
                                class="check" id="allcheck" />th>
                            <th class="taC cp" width="5%">编号th>
                            <th class="taC cp" width="10%">姓名th>
                            <th class="taC cp" width="5%">性别th>
                            <th class="taC cp" width="10%">邮箱th>
                            <th class="taC cp" width="10%">联系电话th>
                            <th class="taC cp" width="10%">所属部门th>
                            <th class="taC cp" width="15%">地址th>
                            <th class="taC" width="5%">状态th>
                            <th class="taC" width="18%">最后登录时间th>
                            <th class="taC" width="10%">操作th>
                        tr>
                    thead>
    
                table>

    截止到这里,基本上整个代码都差不多贴完了,大家可以根据自己的项目实际情况进行修改;
    这里可能还涉及一个前端与后台用json格式传递数据的问题,可以参照我关于这个问题的文章处理。
    贴两个有关dataTables网站地址:
    dataTables中文网:http://datatables.club/example/
    dataTables参数说明:http://www.suchso.com/UIweb/jquery-DataTables-use-opertions-zhongwen-shuoming.html

    你可能感兴趣的:(系统框架架构,spring-mvc,分页,bootstrap,dataTables)