ABP之展现层(Datatables分页)
在前面的随笔中,已经介绍了ABP的增删改查的操作,但是对于查询的数据并没有进行分页,只是进行粗糙的展示,今天的随笔中将摸索进行分页展示。这里打算使用的分页插件是DataTables,这是一款比较强大的表格插件。
在以前我们后台手动分页的时候,需要前台传入两个重要的分页参数:PageIndex和PageSize(显示第几页的数据和每页显示的数量),这是必须的量的参数。分页作为一个页面展示的基础功能,ABP框架已经对分页功能进行了一些方便性的操作,为我们提供了一些有助于分页的接口和Dto,Dto是什么?这个在前面的随笔中已经研究过了,这里就不再重复。
一 .ABP中的分页接口
在ABP中总共为我们提供了三个分页的接口:IPagedResultRequest、ISortedResultRequest、ILimitedResultRequest三个接口
从上面的三个接口中我们看到了三个重要的变量,这就是我们分页和排序中经常用到的量。
二. 实现分页的Dto
在我们免费的ABP中模板中,也就是只能找到这么三个接口,对我们分页来说确实并没有提供了多大的方便,但是在ABP Zero中已经对三个接口进行了相应的实现,只是zero是收费的。在这里我们可以模仿zero在我们ABP模板中添加上分页的Dto,并且为DataTables这个插件定制分页Dto。
详细的代码
1 1.PagedInputDto 2 public class PagedInputDto : IPagedResultRequest 3 { 4 /// <summary> 5 /// 每页显示的行数 6 /// </summary> 7 [Range(1, AppConsts.MaxPageSize)] 8 public int MaxResultCount { get; set; } 9 /// <summary> 10 /// 跳过数量=MaxResultCount*页数 11 /// </summary> 12 [Range(0, int.MaxValue)] 13 public int SkipCount { get; set; } 14 15 public PagedInputDto() 16 { 17 MaxResultCount = AppConsts.DefaultPageSize; 18 } 19 } 20 2. PagedAndFilteredInputDto 21 public class PagedAndFilteredInputDto : IPagedResultRequest 22 { 23 [Range(1, AppConsts.MaxPageSize)] 24 public int MaxResultCount { get; set; } 25 26 [Range(0, int.MaxValue)] 27 public int SkipCount { get; set; } 28 29 public string Filter { get; set; } 30 31 public PagedAndFilteredInputDto() 32 { 33 MaxResultCount = AppConsts.DefaultPageSize; 34 } 35 } 36 3. PageAndSortedInputDto 37 public class PagedAndSortedInputDto : PagedInputDto, ISortedResultRequest 38 { 39 public string Sorting { get; set; } 40 41 public PagedAndSortedInputDto() 42 { 43 MaxResultCount = AppConsts.DefaultPageSize; 44 } 45 } 46 4.PagedSortedAndFilteredInputDto 47 public class PagedSortedAndFilteredInputDto : PagedAndSortedInputDto 48 { 49 public string Filter { get; set; } 50 //接收DataTables的参数 51 public int Draw { get; set; } 52 public int Length 53 { 54 get 55 { 56 return this.MaxResultCount; 57 } 58 59 set 60 { 61 this.MaxResultCount = value; 62 } 63 } 64 public int Start 65 { 66 get 67 { 68 return this.SkipCount; 69 } 70 71 set 72 { 73 this.SkipCount = value; 74 } 75 } 76 } 77 5.DataTablesPageOutPutDto 78 [Serializable] 79 public class DataTablesPagedOutputDto<T>:PagedResultDto<T> 80 { 81 public int Draw { get; set; } 82 83 /// <summary> 84 /// 过滤后的记录数(没有就是全部),这个是必须的参数 85 /// </summary> 86 public int RecordsFiltered { get; set; } 87 88 public int RecordsTotal { get { return this.TotalCount; } } 89 90 public DataTablesPagedOutputDto(int totalCount, IReadOnlyList<T> items) 91 : base(totalCount, items) 92 { 93 this.RecordsFiltered = totalCount; 94 } 95 }
其中PagedSortedAndFilteredInputDto和DataTablesPageOutPutDto分别是为了适应DataTables的需求定制的两个类,Input的类中Start、Length、Draw、Filter都是为了接收DataTables传递过来的参数,在OutPut类中定义了RecordsFiltered和recordsTotal和Draw这些都是DataTables需要的参数。说了这么多,还是先看一下DataTables这插件再说。
三.DataTables分页
在这里我们使用的服务端分页,详细的内容可查看官网的具体介绍:http://www.datatables.club/manual/server-side.html
(1)Dto的请求参数
当然参数还有许多,但是主要的参数也就是上面的那几个,尤其是已经圈出来的这三个,就可以完成分页功能了,如果需要进行排序或者添加按照字段的搜索的功能,那么就需要用到下面的字段了,我们这里只是使用分页功能。
(2)Dto的返回参数
通过了上面DataTables官网的介绍,我们已经清楚了我们Dto中定义的参数的作用了,不知道大家有没有一点困惑,就是Draw参数到底是干什么的???哈哈哈,我们在DataTables中已经找到了答案,他是防止跨站脚本攻击的,关于他的赋值,只要给他赋值一个整数就可以了。
三.在ABP中使用DataTables实现分页
View
Index的具体代码
@using Abp.Authorization.Users @using StudyABPProject.Web.Startup @model IList<StudyABPProject.Movie.Dto.MovieTicketDto> @{ViewBag.CurrentPageName = PageNames.Movies; // The menu item will be active for this page. } @section scripts{<script src="~/lib/jquery-daterangepicker/daterangepicker.js" asp-append-version="true"></script><script src="~/view-resources/Views/Movie/Index.js" asp-append-version="true"></script><link href="~/lib/jquery-daterangepicker/daterangepicker.css" rel="stylesheet" /><link href="~/lib/datatables/jquery.dataTables.min.css" rel="stylesheet" /><script src="~/lib/datatables/jquery.dataTables.min.js"></script> }<div class="row clearfix"><div class="col-lg-12 col-md-12 col-sm-12 col-xs-12"><div class="card"><div class="header"><h2>@L("Movie")</h2><ul class="header-dropdown m-r--5"><li class="dropdown"><a href="javascript:void(0);" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><i class="material-icons">more_vert</i></a><ul class="dropdown-menu pull-right"><li><a id="RefreshButton" href="javascript:void(0);" class="waves-effect waves-block"><i class="material-icons">refresh</i>Refresh</a></li></ul></li></ul></div><div class="body table-responsive"><button type="button" class="btn btn-primary waves-effect waves-float pull-right" data-toggle="modal" data-target="#MovieTicketCreateModal"><i class="material-icons">添加</i></button><table id="MovieTable" name="MovieTable"></table></div></div></div> </div><div class="modal fade" id="MovieTicketCreateModal" tabindex="-1" role="dialog" aria-labelledby="UserCreateModalLabel" data-backdrop="static"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><h4 class="modal-title"><span>@L("CreateMovieTicket")</span></h4></div><div class="modal-body"><form name="movieCreateForm" role="form" novalidate class="form-validation"><div class="tab-content"><div role="tabpanel" class="tab-pane animated fadeIn active" id="create-user-details"><div class="row clearfix" style="margin-top:10px;"><div class="col-sm-12"><div class="form-group form-float"><div class="form-line"><input class="form-control" type="text" name="MovieName" required maxlength="256" minlength="2"><label class="form-label">@L("MovieName")</label></div></div></div></div><div class="row clearfix"><div class="col-sm-12"><div class="form-group form-float"><div class="form-line"><input type="text" name="MovieActor" class="form-control" required maxlength="256"><label class="form-label">@L("MovieActor")</label></div></div></div></div><div class="row clearfix"><div class="col-sm-12"><div class="form-group form-float"><div class="form-line"><input type="datetime" name="StartTime" class="form-control" required>@*<label class="form-label">@L("StartTime")</label>*@</div></div></div></div><div class="row clearfix"><div class="col-sm-12"><div class="form-group form-float"><div class="form-line"><input type="datetime" id="EndTime" name="EndTime" class="form-control">@*<label class="form-label">@L("EndTime")</label>*@</div></div></div></div><div class="row clearfix"><div class="col-sm-12"><div class="form-group form-float"><div class="form-line"><input type="number" id="Money" name="Money" class="form-control"><label class="form-label">@L("Money")</label></div></div></div></div></div></div><div class="modal-footer"><button type="button" class="btn btn-default waves-effect" data-dismiss="modal">取消</button><button type="submit" id="btnSave" class="btn btn-primary waves-effect">保存</button></div></form></div></div></div> </div> <div class="modal fade" id="MovieTicketEditModal" tabindex="-1" role="dialog" data-backdrop="static"><div class="modal-dialog" role="document"><div class="modal-content"></div></div> </div>
Js
关于js代码的位置我也按照框架中的位置放在了view-resources,话说Js代码离View有点远~~~
Index.Js中的主要代码
(function () {$(function () {var _movieService = abp.services.app.movieTicket;var _$modal = $('#MovieTicketCreateModal');var _$form = _$modal.find('form[name="movieCreateForm"]');_$form.validate({rules: {MovieName:{required:true},StartTime: "required",EndtTime:{required: true},MovieActor: "required",Money:"required"},messages: {MovieName: {required:"电影名称不能为空"},MovieActor: {required: "演员名称不能为空"},StartTime: {required: "开始时间不能为空"},EndTime: {required: "结束时间不能为空"},Money: {required: "票价不能为空"}}});var dateOption = {locale: {format: 'YYYY-MM-DD HH:mm:ss',applyLabel: '确认',cancelLabel: '取消'},singleDatePicker: true,startDate: moment().format("YYYY-MM-DD HH:mm:ss"),timePicker24Hour: true,timePicker: true,autoApply: true,autoUpdateInput: true};$('input[name=StartTime]').daterangepicker(dateOption);$('input[name=EndTime]').daterangepicker(dateOption);$('#RefreshButton').click(function () {refreshUserList();});$('.delete-movie').click(function () {var movieId = $(this).attr("data-movie-id");var movieName = $(this).attr("data-movie-name");abp.message.confirm("删除电影 '" + movieName + "'?",function (isConfirmed) {if (isConfirmed) {_movieService.deleteMovie({"id": movieId, "movieName": movieName,}).done(function () {refreshMovieList();});}});});$('.edit-movie').click(function (e) {var movieId = $(this).attr("data-movie-id");e.preventDefault();$.ajax({url: abp.appPath + 'MovieTicket/EditMovieTicketModal?movieId=' + movieId,type: 'POST',contentType: 'application/html',success: function (content) {$('#MovieTicketEditModal div.modal-content').html(content);},error: function (e) { }});});_$form.find('button[type="submit"]').click(function (e) {e.preventDefault();if (!_$form.valid()) {return;}var movie = _$form.serializeFormToObject(); abp.ui.setBusy(_$modal);_movieService.createMovie(movie).done(function (response) {if (response == "No") {abp.message.error("创建失败");}else {_$modal.modal('hide');location.reload(true); }}).always(function () {abp.ui.clearBusy(_$modal);});});_$modal.on('shown.bs.modal', function () {_$modal.find('input:not([type=hidden]):first').focus();});function refreshMovieList() {location.reload(true); //reload page to see new user! }function deleteUser(userId, userName) {}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": ": 以降序排列此列"}},autoWidth: false, //禁用自动调整列宽 stripeClasses: ["odd", "even"],//为奇偶行加上样式,兼容不支持CSS伪类的场合 order: [], //取消默认排序查询,否则复选框一列会出现小箭头 processing: false, //隐藏加载提示,自行处理 serverSide: true, //启用服务器端分页 searching: false //禁用原生搜索 },COLUMN: {CHECKBOX: { //复选框单元格 className: "td-checkbox",orderable: false,width: "30px",data: null,render: function (data, type, row, meta) {return '<input type="checkbox" class="iCheck">';}}},RENDER: { //常用render可以抽取出来,如日期时间、头像等 ELLIPSIS: function (data, type, row, meta) {data = data || "";return '<span title="' + data + '">' + data + '</span>';}}}}; var getQueryCondition=function(data) { var param = {}; //组装排序参数 if(data.order&&data.order.length && data.order[0]) {//组装分页参数 param.start = data.start;param.length = data.length; param.draw = data.draw; return param; }var page = {$table: $("#MovieTable"),$dataTable: null,initDataPicker: function () {var dataOption = {startDate: moment().startOf("month"),"maxDate": null,singleDatePicker: true};var dataOption1 = {startDate: moment().endOf("month"),"maxDate": null,singleDatePicker: true};$("#StartTime").WIMIDaterangepicker(dataOption);$("#EndTime").WIMIDaterangepicker(dataOption1);},initTable: function () {if (!$.fn.DataTable.isDataTable("#MovieTable")) {page.$datatable = page.$table.DataTable($.extend(true, {}, CONSTANT.DATA_TABLES.DEFAULT_OPTION, {ajax: function (data, callback, settings) {//封装请求参数 var param = getQueryCondition(data);$.ajax({type: "GET",url: "/api/services/app/" + "movieTicket/getAllMovieTicketPage",cache: false, //禁用缓存 data: param, //传入已封装的参数 dataType: "json",success: function (response) {//封装返回数据 var returnData = {};returnData.draw = response.result.draw;//这里直接自行返回了draw计数器,应该由后台返回 returnData.recordsTotal = response.result.recordsFiltered;//总记录数 returnData.recordsFiltered = response.result.recordsFiltered;//后台不实现过滤功能,每次查询均视作全部结果 returnData.data = response.result.items;//调用DataTables提供的callback方法,代表数据已封装完成并传回DataTables进行渲染 //此时的数据需确保正确无误,异常判断应在执行此回调前自行处理完毕 callback(returnData);},error: function (XMLHttpRequest, textStatus, errorThrown) {alert("查询失败");}});},"paging": true,//绑定数据 "columns": [{"defaultContent": "","title": "操作","orderable": false,"width": "150px","className": "text-center not-mobile","createdCell": function (td, cellData, rowData, row, col) {var $actionContent = $("<div class='action-content'>");$('<button class="btn btn-xs">修改</button>').appendTo($actionContent).click(function () {alert(rowData.startTime);console.log(rowData);});$('<button class="btn btn-xs"> 删除 </button>').appendTo($actionContent).click(function () {alert(rowData.id);});$(td).append($actionContent);} }, { "data": "movieName", "title": "电影名称" }, { "data": "movieActor", "title": "演员名称", "width": "120px", }, { "data": "startTime", "title": "开始时间", "render": function (data, type, full, meta) { return moment(data).format("YYYY-MM-DD HH:mm:ss"); } }, { "data": "endTime", "title": "结束时间", "render": function (data, type, full, meta) { return moment(data).format("YYYY-MM-DD HH:mm:ss"); } }, { "data": "money", "title": "票价", } ], }));//此处需调用api()方法,否则返回的是JQuery对象而不是DataTables的API对象 } else {page.$datatable.ajax.reload();}},init: function () {page.initTable();}}page.init();}); })();
在这里需要感谢https://blog.csdn.net/u011072139/article/details/54312414?locationnum=10&fps=1,从这篇博客类借鉴了一些Jscript代码。
注意的问题:
(1)在使用DataTables的时候,经常出现一个错误,错误的提示:没有“length”,其实出现这个错误的原因是没有为Data赋值,DataTables需要返回Data,然后它会自动计算length,所以只要将Data赋值并返回即可。
(2)returnData.data = response.result.items;从这行代码中可以看出,我们返回的数据并不是一个简单的对象,不能直接访问我们在后台传出的属性,多封装了一层。
上面的代码中只是实现了分页的功能,关于删除和修改并没有重新实现。需要注意的是在DataTables尽心后台访问的时候的请求路径url,url: "/api/services/app/" + "movieTicket/getAllMovieTicketPage",这的路径并不是具体的控制器中的方法,而是直接访问的Application层的服务方法,这里就涉及了ABP中动态的Js代理,还一个需要重点关注的是type必须是Get类型,否则是无法找到访问路径的,这是因为在ABP中动态Js代理默认的请求方式是get。关于动态的Js代理在ABP中的应用这个将会在后面的随笔去研究。
后台主要的代码
public async Task<PagedResultDto<MovieTicketDto>> GetAllMovieTicketPage(MovieInputDto input){var query = movieTicketRepository.GetAll() ;var totalCount =await query.CountAsync();var models =await query.OrderBy(input.Sorting).AsNoTracking().PageBy(input).ToListAsync();if (models.Count()==0){return new DataTablesPagedOutputDto<MovieTicketDto>(0, new List<MovieTicketDto>());}var items = models.MapTo<List<MovieTicketDto>>();return new DataTablesPagedOutputDto<MovieTicketDto>(totalCount,items); }
到此为止,基本的分页功能已经实现,下面看一下运行的效果吧
请求的数据:
返回的数据:
转载于:https://www.cnblogs.com/XZhao/p/8647535.html
ABP之展现层(Datatables分页)相关推荐
- ABP入门系列(5)——展现层实现增删改查
ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 这一章节将通过完善Controller.View.ViewModel,来实现展现层的增删改查.最终 ...
- mondrain多维分析引擎+saiku web展现层的演示环境搭建
为什么80%的码农都做不了架构师?>>> mondrain多维分析引擎+saiku web展现层的演示环境搭建 找了很久,官网git提供的源码下载搭建起来很麻烦,buildal ...
- sell02 展现层编写
# API###商品列表``` GET /sell/buyer/product/list ```参数``` 无 ```返回``` {"code": 0,"msg" ...
- 《Spring 3.0就这么简单》——1.6 展现层
本节书摘来自异步社区<Spring 3.0就这么简单>一书中的第1章,第1.6节,作者: 陈雄华 , 林开雄著,更多章节内容可以访问云栖社区"异步社区"公众号查看 1. ...
- java 展现层框架_spring快速入门例子教程:06展现层
Spring的业务层和Spring的持久层都已经开始完成了,该是为程序提供界面的时候了.Struts2框架由于抢尽天时地利,成为当下最流行的展现层框架.但Spring MVC相对于Struts2更加简 ...
- dataTables分页组合查询 springMVC Hibernate
组合查询的字段:昵称,性别,年龄,和类型.dataTable列显示字段:编号,名称,性别,年龄,类型. 1 <body> 2 <form> 3 <span>昵称:& ...
- EFCore+Mysql仓储层建设(分页、多字段排序、部分字段更新)
前沿 园子里已有挺多博文介绍了EFCore+Mysql/MSSql如何进行使用,但实际开发不会把EF层放在Web层混合起来,需要多个项目配合结构清晰的进行分层工作,本文根据个人实践经验总结将各个项目进 ...
- 使用 ASP.NET Core, Entity Framework Core 和 ABP 创建N层Web应用 第二篇
介绍 这是"使用 ASP.NET Core ,Entity Framework Core 和 ASP.NET Boilerplate 创建N层 Web 应用"系列文章的第二篇.以下 ...
- datatables分页下一页不能点击_干货,删不掉Word文末最后一页?学会5个方法,再也不愁啦...
在处理Word文档时,经常会在文档最后出现一页空白,非常讨厌,更可恶的是总是删不掉,按退格键或者delete键都无济于事. 你是不是也正在为删除Word文末空白页发愁呢? 有没有好的方法解决这一问题呢 ...
最新文章
- 区块链应用 | 不知道什么时候起,满世界都在谈区块链的事情
- 语言中如何在main函数开始前执行函数
- 距离度量:闵氏、欧式、马氏、余弦、汉明等
- 如何当好PM?请求大家积极讨论
- mysql怎么实现事务序列化_一文快速搞懂MySQL InnoDB事务ACID实现原理(转)
- graph driver-device mapper-04libdevmapper基本操作
- 检查vCenter Server上STS证书的过期日期(79248)(STS证书过期,导致 vCenter 报503无法登陆VC)
- horizontal center and vertical middle in CSS
- win64 Python下安装PIL出错解决2.7版本 (3.6版本可以使用)
- webstorm破解码
- MicroMsg.SDK.WXMsgImplComm: ignore wechat app signature validation
- slam和orbslam3环境配置
- c#窗体编辑个人简历_C#个人简历完整代码
- Java 合并、拆分PDF文档
- USB-HID游戏手柄的数据通信
- draw.io二次开发改造过程
- Centos7 压缩文件
- English语法_人称代词 - It
- 做phodal的御用编辑,其实我是拒绝的
- jquery遍历对象list拼接
热门文章
- 埃博拉病毒和微生物现代战争
- leetcode:Excel Sheet Column Number
- 使用Linux自定义自动补全命令完善自己的shell脚本
- 在 CentOS 上安装和配置 Xen 虚拟化
- “富豪相亲大会”究竟迷失了什么?
- 用HTML,CSS和JavaScript创建iPhone/iPad应用程序
- 错误:The project was not built due to Unparsed aapt error(s)
- 利用UTL_FILE包实现文件I/O操作
- WPF Unleashed Chapter 2:XAML Demystified 翻译(第二部分)
- linux系统上手工建库步骤,Linux下Oracle手工建库过程