记得仍是15年的时候,工做须要,独自写后台管理系统。。记得那时候,最让我头疼的不是后台逻辑,而是数据的列表展现。 列不少的时候,页面显示问题;分页样式问题;表格样式问题;数据加载...不少细节的问题,费时,并且老是达不到我想要的效果...也是那个时候,第一次接触了datatable.js插件,只须要简单的修改配置值,就能够改变表格的方方面面,真的是很是好的体验。。。javascript
不过,由于一些历史缘由,和时间问题,那时候对 ajax加载+服务端分页+页面刷新,仍然是一直很迷迷糊糊...恰好最近工做中须要作一个列表管理页,因此就很天然的选择了datatable.js,而且总算把 ajax加载数据+服务端分页+reload这套流程弄通。也许还有不少种方案能够达到效果,但至少这个是确定可行的.css
样式是基于bootstrap风格.html
<!-- datatables样式和bootstrap支持样式 --> <link rel="stylesheet" type="text/css" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/plug-ins/28e7751dbec/integration/bootstrap/3/dataTables.bootstrap.css"> <script type="text/javascript" language="javascript" src="https://code.jquery.com/jquery-1.10.2.min.js"></script> <script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js"></script> <script type="text/javascript" language="javascript" src="https://cdn.datatables.net/plug-ins/28e7751dbec/integration/bootstrap/3/dataTables.bootstrap.js"></script> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> <!--form ajax提交--> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.2.1/jquery.form.js"></script>
<!-- search 框start --> <div class="container"> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="用户姓名" name="userName" id="searchUserName"> </div> & <div class="form-group"> <input type="text" class="form-control" placeholder="律所名" name="officeName" id="searchOfficeName"> </div> & <div class="form-group"> <input type="number" class="form-control" placeholder="状态" name="be_valid" id="searchValid"> </div> <button type="button" class="btn btn-success" onclick="searchData()">搜索</button> </form> <form class="navbar-form navbar-right"> <button type="button" class="btn btn-primary btn-sm btn-warning" data-toggle="modal" data-target="#addModal"> 新增律所 </button> </form> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> </div> <!-- search 框end --> <div class="container"> <table id="mytable" class="table table-striped table-bordered table-hover" cellspacing="0" width="100%" style="white-space: nowrap;"> <thead> <tr> <th>用户名</th> <th>用户ID</th> <th>邮箱</th> <th>身份</th> <th>律所</th> <th>律所id</th> <th>律所简报</th> <th>律所建立时间</th> <th>限制人数</th> <th>验证码</th> <th>状态</th> <th>备注信息</th> <th>操做</th> </tr> </thead> <tbody></tbody> <tfoot> <tr> <th>用户名</th> <th>用户ID</th> <th>邮箱</th> <th>身份</th> <th>律所</th> <th>律所id</th> <th>律所简报</th> <th>律所建立时间</th> <th>限制人数</th> <th>验证码</th> <th>状态</th> <th>备注信息</th> <th>操做</th> </tr> </tfoot> </table> </div>
由于是服务端分页,因此我页面作了搜索框,进行自定义的参数搜索.前端
<script type="text/javascript"> var oTable; $(function(){ LoadData(); }); function searchData(){ oTable.draw(true); // oTable.ajax.reload(null,true); }function LoadData() { oTable = $('#mytable').DataTable({ //sDom: 'T<"clear">lfrtip', oLanguage: { sZeroRecords: "对不起,查询不到任何相关数据", sInfoEmpty: "记录数为0" }, sScrollX: "100%", sScrollXInner: "110%", bScrollCollapse: false, //可滚动 bDestory: true, //数据容许清空 bServerSide: true, //服务端处理分页 bLengthChange: false, //是否容许自定义每页显示条数. iDisplayLength: 20, //每页显示10条记录 bPaginate: true, //是否分页 //sPaginationType: "amaze", //分页样式 "full_numbers" //bJQueryUI: true,//是否将分页样式应用到表格 bProcessing: true, //当datatable获取数据时候是否显示正在处理提示信息。 bFilter: false, //是否启用条件查询 bSearchable: false, //bStorable: false,//是否启用列排序 //bInfo: true, //是否显示分页信息(页脚信息) order: [[7, "desc"]], //默认按照第几列排序,从1开始 bAutoWidth: false, //自动宽度 bStateSave: true, //状态保存,使用了翻页或者改变了每页显示数据数量,会保存在cookie中,下回访问时会显示上一次关闭页面时的内容 ajax:{ dataType:'json', type:'POST', url: '/adminUserList', headers: { 'token': window.localStorage.token //取localStorage中的token,用来作安全校验 }, dataSrc: "aaData", data:function(d){
//取搜索的参数值,在请求服务端时,附加到请求参数中 var userName=$('#searchUserName').val(); var officeName=$('#searchOfficeName').val(); var be_valid=$('#searchValid').val(); d.userName=userName; d.officeName=officeName; d.be_valid=be_valid; } }, columns: [ { data: "name", bSortable: false }, { data: "user_id", bSortable: false }, { data: "email", bSortable: false }, { data: "level_name", bSortable: false }, { data: "office_name", bSortable: false }, { data: "office_id", bSortable: false }, { data: "officeBriefing", bSortable: false }, { data: "office_create_time"}, { data: "limited_num", bSortable: false }, { data: "verify_code", bSortable: false }, { data: "be_valid", bSortable: false }, { data: "remark", bSortable: false }, { data: null, render: function (data, type, row) { return '<button type="button" class="btn btn-primary btn-sm" onclick="editShow(\''+data.user_id+'\')">编辑</button>'; }, bSortable: false } ] }); } </script>
@ResponseBody @RequestMapping(value = "/adminUserList",method = RequestMethod.POST) public AjaxListResponseDTO<AppUserShowDTO> getAdminUserList( @ApiParam(required = true, name = "start", value = "开始条数") @RequestParam Integer start, @ApiParam(required = true, name = "length", value = "取多少条") @RequestParam Integer length, @ApiParam(required = true, name = "userName", value = "用户名") @RequestParam String userName, @ApiParam(required = true, name = "officeName", value = "律所名") @RequestParam String officeName, @ApiParam(required = true, name = "be_valid", value = "状态") @RequestParam Integer be_valid, HttpServletRequest request) throws Exception{// Map<String,String[]> paramMap=request.getParameterMap(); String[] orderTypeArr=request.getParameterValues("order[0][dir]"); String lawOfficeOrderType=""; if(null!=orderTypeArr){ lawOfficeOrderType=orderTypeArr[0]; } AjaxListResponseDTO<AppUserShowDTO> responseDTO=new AjaxListResponseDTO<>(); //datatable.js 相关参数 String[] drawStrArr=request.getParameterValues("draw"); if(null!=drawStrArr){ responseDTO.setSEcho(Integer.parseInt(drawStrArr[0])); } Page<AppUserShowDTO> appUserShowDTOPage = authUserService.findAllUserAndLawOffice(userName,officeName,be_valid,null!=start?start:0,null!=length?length:20,lawOfficeOrderType,"超级管理员"); responseDTO.setITotalRecords((int) Math.ceil(appUserShowDTOPage.getTotal()));//实际须要传数据总数,此处值不对 responseDTO.setITotalDisplayRecords((int) Math.ceil(appUserShowDTOPage.getTotal())); responseDTO.setAaData(appUserShowDTOPage.getResult()); return responseDTO; }
start(起始条数,注意,是条数而不是页数 )和length(取多少条数据)为datatable默认会传到服务端的2个参数, userName/officeName/be_valid则为我前端自定义的附加参数。java
Page是List<T>泛型集合,是开源项目PageHelper-mybatis中的类。jquery
服务端返回给前端的json数据也有格式要求,具体见AjaxListResponseDTO类定义.ajax
/** * Created by xinhuiyang on 2017/6/9. */ @Data public class AjaxListResponseDTO<T>{ private Integer sEcho; private Integer iTotalRecords; private Integer iTotalDisplayRecords; private List<T> aaData; }
自此,就实现了带搜索功能的服务端分页效果.数据库
首先,在以前的基础上,须要添加一个js文件引用json
<!-- 固定列 插件js -->
<script src="https://cdn.datatables.net/fixedcolumns/3.2.2/js/dataTables.fixedColumns.min.js"></script>
其次,在配置项中添加一项:bootstrap
oTable = $('#mytable').DataTable({ //sDom: 'T<"clear">lfrtip', oLanguage: { sZeroRecords: "对不起,查询不到任何相关数据", sInfoEmpty: "记录数为0" }, sScrollX: "100%", sScrollXInner: "110%", bScrollCollapse: false, fixedColumns: { //固定列的配置项 leftColumns: 1, //固定左边第一列 rightColumns:1 //固定右边第一列 }, bDestory: true, bServerSide: true, .....省略......
而后,刷新页面...至此,固定列效果就ok了。
如今的页面效果,还有2个瑕疵:
其一是后台返回"总条数"不对,我是时间赶,来不及写查询了..你们实际使用时,本身查询一下就行,这个好解决;
其二是前端页面,下角显示页码总数和页脚信息显示有问题(见下图),不知道当后台"总条数"准确时,会不会就ok了。我后面还会找个时间,去修复一下的...当我有解决方案时,会补充在下面的,你们有知道缘由和解决方案的,也欢迎评论在下方。
1.左边数字没显示出来.
2.实际83条数据,每页20条,应该最多到5页的,但实际上,能够点任意页,只不过从第6页开始,数据都为空.
页面显示不对的问题已经找到缘由而且解决.
缘由是:后端分页时,须要返回给前端更多的信息,如总数多少,过滤后多少等,因此我代码中的AjaxListResponseDTO类就不符合后端分页时的需求了,须要改动.
修改后的类定义为:
/** * Created by xinhuiyang on 2017/6/9. */ @Data @ApiModel public class AjaxListResponseDTO<T>{ @ApiModelProperty("必要。上面提到了,Datatables发送的draw是多少那么服务器就返回多少。 这里注" + "意,做者出于安全的考虑,强烈要求把这个转换为整形,即数字后再" + "返回,而不是纯粹的接受而后返回,这是 为了防止跨站脚本(XSS)攻击。") private Integer draw; @ApiModelProperty("必要。即没有过滤的记录数(数据库里总共记录数)") private Integer recordsTotal; @ApiModelProperty("必要。过滤后的记录数(若是有接收到前台的过滤条件,则返回的是过滤后的记录数)") private Integer recordsFiltered; @ApiModelProperty("必要。表中中须要显示的数据。这是一个对象数组,也能够只是" + "数组,区别在于 纯数组前台就不须要用 columns绑定数据,会自动按照顺序" + "去显示 ,而对象数组则须要使用 columns绑定数据才能正常显示。") private List<T> aaData; @ApiModelProperty("可选。你能够定义一个错误来描述服务器出了问题后的友好提示") private String error; }
相应的,controller部分代码,也要给对应的属性附上正确的值,改动后代码以下:
@ResponseBody @RequestMapping(value = "/adminUserList",method = RequestMethod.POST) public AjaxListResponseDTO<AppUserShowDTO> getAdminUserList( @ApiParam(required = true, name = "start", value = "开始条数") @RequestParam Integer start, @ApiParam(required = true, name = "length", value = "取多少条") @RequestParam Integer length, @ApiParam(required = true, name = "userName", value = "用户名") @RequestParam String userName, @ApiParam(required = true, name = "officeName", value = "律所名") @RequestParam String officeName, @ApiParam(required = true, name = "be_valid", value = "状态") @RequestParam Integer be_valid, HttpServletRequest request) throws Exception{ // Map<String,String[]> paramMap=request.getParameterMap(); String[] orderTypeArr=request.getParameterValues("order[0][dir]"); String lawOfficeOrderType=""; if(null!=orderTypeArr){ lawOfficeOrderType=orderTypeArr[0]; } AjaxListResponseDTO<AppUserShowDTO> responseDTO=new AjaxListResponseDTO<>(); //datatable.js 相关参数 String[] drawStrArr=request.getParameterValues("draw"); if(null!=drawStrArr){ responseDTO.setDraw(Integer.parseInt(drawStrArr[0])); } int totalCountBeforeFilter=authUserService.countUserByLevel("超级管理员"); Page<AppUserShowDTO> appUserShowDTOPage = authUserService.findAllUserAndLawOffice(userName,officeName,be_valid,null!=start?start:0,null!=length?length:20,lawOfficeOrderType,"超级管理员"); responseDTO.setAaData(appUserShowDTOPage.getResult()); responseDTO.setRecordsTotal(totalCountBeforeFilter); responseDTO.setRecordsFiltered((int) appUserShowDTOPage.getTotal()); return responseDTO; }
而后,页面的页码显示就正确了(如图):
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利;
本文出自:博客园--别问是谁