Webapi+DataTables
webapi + datatables
前言
之前写过一个关于DataTables的记录,是之前做webform的时候从后台一次性生成html代码,有很多弊端,就不多说了。
这次把最近研究的DataTables结合webapi的成果记录一下。
DataTables 中文网
DataTables 官网
基本上所有问题都能在这俩网站找到答案
下面开始记录
1. 先准备一个实体
用于DataTables请求服务端之后返回的格式化数据
/// <summary>
/// DataTables返回实体
/// </summary>
public class BaseDataTables
{
/// <summary>
/// Datatables发送的draw是多少那么服务器就返回多少
/// </summary>
public int draw { get; set; }
/// <summary>
/// 即没有过滤的记录数(数据库里总共记录数)
/// </summary>
public int recordsTotal { get; set; }
/// <summary>
/// 过滤后的记录数(如果有接收到前台的过滤条件,则返回的是过滤后的记录数)
/// </summary>
public int recordsFiltered { get; set; }
/// <summary>
/// 对象数组
/// </summary>
public IEnumerable data { get; set; }
/// <summary>
/// 错误提示
/// </summary>
public string error { get; set; }
}
2. 再来几个实体类,用户接收 DataTables 的信息
后面加了四个扩展参数,用于接收除了DataTables固定的参数外,自己的业务参数。后面会有记录
/// <summary>
/// 接收DataTables回传数据model
/// </summary>
public class GetDataTablesMessage
{
/// <summary>
/// DataTables请求和返回都是固定的值
/// </summary>
public int draw { get; set; }
/// <summary>
/// 从哪行开始
/// </summary>
public int start { get; set; }
/// <summary>
/// 长度
/// </summary>
public int length { get; set; }
/// <summary>
/// 查询集合
/// </summary>
public search search { get; set; }
/// <summary>
/// 排序集合
/// </summary>
public List<order> order { get; set; }
/// <summary>
/// 列集合
/// </summary>
public List<columns> columns { get; set; }
/// <summary>
/// 参数1
/// </summary>
public int parameter1 { get; set; }
/// <summary>
/// 参数2
/// </summary>
public int parameter2 { get; set; }
/// <summary>
/// 参数3
/// </summary>
public int parameter3 { get; set; }
/// <summary>
/// 参数4
/// </summary>
public int parameter4 { get; set; }
}
/// <summary>
/// 列
/// </summary>
public class columns
{
/// <summary>
/// 列值
/// </summary>
public string data { get; set; }
/// <summary>
/// 列名
/// </summary>
public string name { get; set; }
/// <summary>
/// 是否单列查询
/// </summary>
public bool searchable { get; set; }
/// <summary>
/// 是否排序
/// </summary>
public bool orderable { get; set; }
/// <summary>
/// 查询实体
/// </summary>
public search search { get; set; }
}
/// <summary>
/// 排序
/// </summary>
public class order
{
/// <summary>
///
/// </summary>
public int column { get; set; }
/// <summary>
///
/// </summary>
public string dir { get; set; }
}
/// <summary>
/// DataTables 列查询值
/// </summary>
public class search
{
/// <summary>
/// 查询值
/// </summary>
public string value { get; set; }
/// <summary>
/// 正则
/// </summary>
public bool regex { get; set; }
}
3. 用户类(测试支持)
/// <summary>
/// 用户表
/// </summary>
[Table("SYS_User")]
public class SYS_User : SYS_Base_Entity
{
/// <summary>
/// 主键 用户ID
/// </summary>
[Key]
public int User_ID { get; set; }
/// <summary>
/// 用户名
/// </summary>
[StringLength(100)]
public string User_Name { get; set; }
/// <summary>
/// 手机号码
/// </summary>
[StringLength(11)]
public string Phone { get; set; }
/// <summary>
/// EMail
/// </summary>
[StringLength(100)]
public string Email { get; set; }
/// <summary>
/// Sex
/// </summary>
public int? Sex { get; set; }
/// <summary>
/// 出生年月
/// </summary>
[Column(TypeName = "DateTime")]
public System.DateTime? BirthDay { get; set; }
/// <summary>
/// 备注
/// </summary>
[StringLength(200)]
public string Comments { get; set; }
}
4. WEBAPI - UserController
结合 SqlSugar
[RoutePrefix("UserTypeGet")]
public class SYS_UserController : ApiController
{
ZEROContext db = new ZEROContext();
/// <summary>
/// DataTables数据支撑开场
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
[Route("GetAllData")]
[HttpPost]
public BaseDataTables<SYS_User> FenYe1([FromBody]GetDataTablesMessage obj)
{
BaseDataTables<SYS_User> Pagedata = new BaseDataTables<SYS_User>();
Pagedata.draw = obj.draw;
#region 动态拼接LINQ_WHERE
//动态WHERE
List<IConditionalModel> conModels = new List<IConditionalModel>();
#region all where 用到常用搜索条件
var allwhere = obj.search.value;
if (!string.IsNullOrEmpty(allwhere))
{
conModels.Add(new ConditionalModel()
{
ConditionalType = ConditionalType.Equal,
FieldName = "User_Name",
FieldValue = allwhere
});
}
conModels.Add(new ConditionalModel()
{
ConditionalType = ConditionalType.NoEqual,
FieldName = "State",
FieldValue = "2"
});
#endregion
#region col where
foreach (var item in obj.columns)
{
var col_data = item.data;
if (item.searchable)
{
if (!string.IsNullOrEmpty(item.search.value))
{
conModels.Add(new ConditionalModel()
{
ConditionalType = ConditionalType.Equal,
FieldName = col_data,
FieldValue = item.search.value
});
}
}
}
#endregion
#endregion
int rows = 0;
var list = db.SqlSugarDb.Queryable<SYS_User>()
.Where(conModels)
.ToPageList((obj.start / obj.length) + 1, obj.length, ref rows);
Pagedata.data = list;
Pagedata.recordsTotal = rows;
Pagedata.recordsFiltered = rows;
return Pagedata;
}
/// <summary>
/// 获取单个
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
public SYS_User Huo(int id)
{
return db.SYS_Users.Find(id);
}
/// <summary>
/// 添加
/// </summary>
/// <param name="u"></param>
/// <returns></returns>
[HttpPost]
public int Jia([FromBody]SYS_User u)
{
if (ModelState.IsValid)
{
u.Create_By = "Creater";
u.Create_Date = Convert.ToDateTime(DateTime.Now.ToString());
u.State = 1;
db.SYS_Users.Add(u);
return db.SaveChanges();
}
else
{
return 0;
}
}
/// <summary>
/// 修改
/// </summary>
/// <param name="u"></param>
/// <returns></returns>
[HttpPut]
public int Gai([FromBody]SYS_User u)
{
if (ModelState.IsValid)
{
#region 方法二
db.SYS_Users.Attach(u);
u.Update_By = "updater";
u.Update_Date = DateTime.Now;
var startEntity = ((IObjectContextAdapter)db).ObjectContext.ObjectStateManager.GetObjectStateEntry(u);
foreach (PropertyInfo p in u.GetType().GetProperties())
{
if (p.Name != "Create_By" && p.Name != "Create_Date")
{
startEntity.SetModifiedProperty(p.Name);
}
}
#endregion
return db.SaveChanges();
}
else
{
return 0;
}
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete]
public int Shan(int id)
{
return db.SqlSugarDb.Updateable<SYS_User>(new { State = 2, User_ID = id }).ExecuteCommand();
}
/// <summary>
/// 批量删除
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpDelete]
public int Shans([FromUri]dynamic ids)
{
string str = Convert.ToString(ids);
var result = 0;
if (!string.IsNullOrEmpty(str))
{
int[] array = Array.ConvertAll(str.Split(','), s => int.Parse(s));
var list = db.SqlSugarDb.Updateable<SYS_User>()
.UpdateColumns(it => new SYS_User() { State = 2 })
.Where(it => array.Contains(it.User_ID));
result = list.ExecuteCommand();
}
return result;
}
/// <summary>
/// 修改状态
/// </summary>
/// <param name="id"></param>
/// <param name="status"></param>
/// <returns></returns>
[HttpGet]
public int ChangeStatus(int id, int status)
{
ZEROContext dbz = new ZEROContext();
return dbz.SqlSugarDb.Updateable<SYS_User>(new { State = status == 0 ? 1 : 0, User_ID = id }).ExecuteCommand();
}
}
5. ZEROContext.cs
public class ZEROContext : DbContext
{
/// <summary>
/// 2019/01/06 加入SqlSugar 查询
/// </summary>
/// <returns></returns>
public SqlSugarClient SqlSugarDb;//用来处理事务多表查询和复杂的操作
public ZEROContext() : base("name=XLZF_write")
{
string sqlcontenxt = ConfigurationManager.ConnectionStrings["XLZF_Read"].ConnectionString;
SqlSugarDb = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = sqlcontenxt,
DbType = DbType.SqlServer,
IsAutoCloseConnection = true
});
}
}
正菜
前端结合了H+的UI
1. 引用
LibJS.js
document.write('<script src="../style/js/jquery.min.js?v=2.1.4"></script>');
document.write('<script src="../style/js/bootstrap.min.js?v=3.3.6"></script>');
document.write('<script src="../style/js/plugins/dataTables/jquery.dataTables.min.js"></script>');
document.write('<script src="../style/js/plugins/dataTables/dataTables.bootstrap4.min.js"></script>');
document.write('<script src="../style/js/content.min.js?v=1.0.0"></script>');
document.write('<script src="../style/js/plugins/dataTables/dataTables.buttons.min.js"></script>');
LibCSS.js
document.write('<link rel="shortcut icon" href="favicon.ico">');
document.write('<link href="../style/css/bootstrap.min14ed.css?v=3.3.6" rel="stylesheet">');
document.write('<link href="../style/css/font-awesome.min93e3.css?v=4.4.0" rel="stylesheet"> ');
document.write('<!-- <link href="http://apps.bdimg.com/libs/fontawesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" />-->');
document.write('<!-- Data Tables -->');
document.write('<!--<link href="../style/css/plugins/dataTables/bootstrap4alpha.css" rel="stylesheet">-->');
document.write('<link href="../style/css/plugins/dataTables/dataTables.bootstrap4.min.css" rel="stylesheet">');
document.write('<link href="../style/css/plugins/dataTables/buttons.bootstrap4.min.css" rel="stylesheet">');
document.write('<!--i-checkbox-->');
document.write('<!--<link href="../style/css/plugins/iCheck/custom.css" rel="stylesheet">-->');
document.write('<link href="../style/css/animate.min.css" rel="stylesheet">');
document.write('<link href="../style/css/style.min862f.css?v=4.1.0" rel="stylesheet">');
2. html
<!DOCTYPE html>
<html>
<!-- Mirrored from www.zi-han.net/theme/hplus/table_data_tables.html by HTTrack Website Copier/3.x [XR&CO'2014], Wed, 20 Jan 2016 14:20:01 GMT -->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>xlzf</title>
<meta name="keywords" content="">
<meta name="description" content="">
<script src="../style/LibCSS.js"></script>
<style>
/*对工具按钮列表整理一下*/
.dt-buttons {
width: 400px;
}
.dataTables_length {
width: 130px;
float: left;
}
/*.btn-group{
height: 25px;
}*/
</style>
</head>
<body class="gray-bg">
<div class="wrapper wrapper-content">
<!--animated fadeInRight-->
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户 <small>列表</small></h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table id="example" width="100%" class="table table-striped table-bordered table-hover dataTables-example">
<thead>
<tr>
<th style="text-align: center;">
<input type="checkbox" class="checkall" />
</th>
<th>行号</th>
<th>用户ID</th>
<th>用户名称</th>
<th>电话号码</th>
<th>邮箱</th>
<th>性别</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tfoot>
<tr>
<th></th>
<th>行号</th>
<th>用户ID</th>
<th>用户名称</th>
<th>电话号码</th>
<th>邮箱</th>
<th>性别</th>
<th>状态</th>
<th></th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="modal inmodal" id="myModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content animated bounceInRight">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span><span class="sr-only">关闭</span>
</button>
<i class="fa fa-laptop modal-icon"></i>
<h4 class="modal-title">用户维护</h4>
</div>
<div class="modal-body">
<form class="form-horizontal m-t" id="commentForm" novalidate="novalidate">
<div class="form-group">
<label class="col-sm-3 control-label">姓名:</label>
<div class="col-sm-8">
<input id="cname" name="name" minlength="2" type="text" class="form-control">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">手机:</label>
<div class="col-sm-8">
<input id="cphone" type="text" class="form-control" name="phone">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">E-mail:</label>
<div class="col-sm-8">
<input id="cemail" type="text" class="form-control" name="email">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">SEX:</label>
<div class="col-sm-8">
<input id="csex" type="text" class="form-control" name="sex">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Birthday:</label>
<div class="col-sm-8">
<input id="cbirthday" type="text" class="form-control" name="birthday">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">说明:</label>
<div class="col-sm-8">
<textarea id="ccomment" name="comment" class="form-control"></textarea>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="btn_save">保存</button>
</div>
</div>
</div>
</div>
<input type="hidden" id="hf_editid">
<script src="../style/LibJS.js"></script>
</body>
</html>
3. js
<script>
var rootUrl = "http://localhost:51120/";
var urlS = rootUrl + "api/SYS_User";
$(document).ready(function() {
//生成每列下的seachtext
$('#example tfoot th').each(function() {
var title = $('#example thead th').eq($(this).index()).text();
if(title != "操作" && title != "行号" && title != "状态" && $(this).index() != 0)
$(this).html('<input type="text" class="form-control input-sm" placeholder="Search ' + title + '" />');
});
//初始化 https://blog.csdn.net/u013380777/article/details/52067483 https://datatables.net/reference/option/
var table = $("#example").DataTable({
"processing": true,
"serverSide": true,
"autoWidth": true,
"searching": true,
"responsive": true,
"lengthChange": true,
"ajax": {
"url": rootUrl + "UserTypeGet/GetAllData",
"type": "post",
"dataType": "json",
"dataSrc": "data"
},
"columns": [{
"data": "User_ID",
"width": "100px",
"bSortable": false,
"render": function(data, type, full, meta) {
var checkHtml = '<input type="checkbox" class="checkchild" value="' + data + '" />';
return checkHtml;
},
"createdCell": function(td, cellData, rowData, row, col) {
$(td).css('text-align', 'center');
}
}, {
"data": null,
"width": "100px",
"bSortable": false
}, {
"data": "User_ID",
"bSortable": true
}, {
"data": "User_Name",
"bSortable": true,
"cellType": "th"
}, {
"data": "Phone",
"bSortable": true
}, {
"data": "Email",
"bSortable": true
}, {
"data": "Sex",
"width": "10%",
"bSortable": true,
//修饰性别
"render": function(data, type, full, meta) {
if(data == 1) {
return "<i class='fa fa-mars'></i>";
} else if(data == 0) {
return "<i class='fa fa-venus'></i>";
} else {
return "<i class='fa fa-venus-mars'></i>";
}
}
}, {
"data": null,
"bSortable": false
}, {
"data": null,
"width": "20%"
}],
"columnDefs": [{
"targets": 7,
"orderable": false,
"render": function(data, type, row) {
var id = data.User_ID;
var state = data.State;
var cHtml = "<div class='switch'>";
cHtml += "<div class='onoffswitch'>";
cHtml += "<input type= 'checkbox' " + (state == 1 ? "checked" : "") + " class='onoffswitch-checkbox' id='" + id + "' onclick='ChangUrlStatus(" + id + "," + state + ")'>";
cHtml += "<label class='onoffswitch-label' for='" + id + "'>";
cHtml += " <span class='onoffswitch-inner'></span>";
cHtml += " <span class='onoffswitch-switch'></span>";
cHtml += " </label>";
cHtml += "</div>";
cHtml += "</div>";
return cHtml;
}
}, {
"targets": 8, //操作按钮目标列
"orderable": false,
"render": function(data, type, row) {
var id = data.User_ID;
var html = "<div class='btn-group'>";
html += "<button class='btn btn-primary btn-xs' onclick='btn_row_seach(" + id + ")'><i class='fa fa-search'></i> 查看</button>";
html += "<button class='btn btn-warning btn-xs' onclick='btn_row_edit(" + id + ")'><i class='fa fa-pencil-square-o'></i> 编辑</button>";
html += "<button class='btn btn-danger btn-xs' onclick='btn_row_del(" + id + ")'><i class='fa fa-trash-o'></i> 删除</button>";
html += "</div>";
return html;
}
}],
"language": {
"lengthMenu": '<div class="input-group">' +
'<div class="input-group-addon">显示</div>' +
'<select class="form-control input-sm">' +
'<option value="5">5</option>' +
'<option value="10">10</option>' +
'<option value="20">20</option>' +
'</select>' +
'</div>',
"search": '<span class="label label-primary">搜索:</span>', //右上角的搜索文本,可以写html标签 <input type="search" class="form-control input-sm" placeholder="sss">
"paginate": { //分页的样式内容。
previous: "上一页",
next: "下一页",
first: "第一页",
last: "最后"
},
"zeroRecords": "没有内容", //table tbody内容为空时,tbody的内容。
//下面三者构成了总体的左下角的内容。
"info": "总共_PAGES_ 页,显示第_START_ 到第 _END_ ,筛选之后得到 _TOTAL_ 条,初始_MAX_ 条 ", //左下角的信息显示,大写的词为关键字。
"infoEmpty": "0条记录", //筛选为空时左下角的显示。
"infoFiltered": "" //筛选之后的左下角筛选提示,
},
"dom": "<'row'<'col-sm-8'l><'col-sm-4'f>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
"order": [2, "asc"]
});
var buttonHtml = "<button id='btn_add' class='btn btn-primary btn-sm'><i class='fa fa-plus'></i> 新增</button> ";
buttonHtml += "<button class='btn btn-primary btn-sm' id='btnAll'><i class='fa fa-trash'></i> 批量删除</button> ";
$("div.col-sm-8").eq(0).append(buttonHtml); //追加到length后面
//添加序号
//不管是排序,还是分页,还是搜索最后都会重画,这里监听draw事件即可
table.on('draw.dt', function() {
table.column(1, {
search: 'applied',
order: 'applied'
}).nodes().each(function(cell, i) {
//i 从0开始,所以这里先加1
i = i + 1;
//服务器模式下获取分页信息,使用 DT 提供的 API 直接获取分页信息
var page = table.page.info();
//当前第几页,从0开始
var pageno = page.page;
//每页数据
var length = page.length;
//行号等于 页数*每页数据长度+行号
var columnIndex = (i + pageno * length);
cell.innerHTML = columnIndex;
});
});
//监听seachtext
$('#example tfoot th').each(function(index) {
$(this).find('input').on('keyup change', function() {
table
.column(index)
.search(this.value)
.draw();
});
});
//全选
$(".checkall").click(function() {
var check = $(this).prop("checked");
$(".checkchild").prop("checked", check);
});
//新增
$("#btn_add").click(function() {
$("#hf_editid").val("");
$("#cname").val("");
$("#cphone").val("");
$("#cemail").val("");
$("#csex").val("");
$("#cbirthday").val("");
$("#ccomment").val("");
$("#myModal").modal('show');
});
//批量处理数据
$('#btnAll').on('click', function() {
var selectLoans = [];
$('.checkchild').each(function() {
if($(this).is(':checked')) {
selectLoans.push($(this).val());
}
});
if(selectLoans.length > 0) {
$.ajax({
url: urlS + "?ids=" + selectLoans,
type: "Delete",
dataType: "json",
success: function(data, status) {
window.location.reload();
}
});
} else {
alert('至少选择一项数据!');
}
});
//保存
$("#btn_save").click(function() {
var name = $("#cname").val();
var phone = $("#cphone").val();
var email = $("#cemail").val();
var sex = $("#csex").val();
var comments = $("#ccomment").val();
var birthday = $("#cbirthday").val();
if($("#hf_editid").val().length > 0) {
var u = {
User_ID: $("#hf_editid").val(),
User_Name: name,
Phone: phone,
Email: email,
Sex: sex,
BirthDay: birthday,
Comments: comments
};
$.ajax({
url: urlS,
type: "Put",
data: u,
dataType: "json",
success: function(data) {
window.location.reload();
}
});
} else {
var u = {
User_Name: name,
Phone: phone,
Email: email,
Sex: sex,
BirthDay: birthday,
Comments: comments
};
$.ajax({
url: urlS,
type: "Post",
data: u,
dataType: "json",
success: function(obj) {
window.location.reload();
}
});
}
});
});
//行查看按钮
function btn_row_seach(id) {
$.get(urlS, {
"id": id
}, function(data, status) {
$("#cname").val(data.User_Name);
$("#cphone").val(data.Phone);
$("#cemail").val(data.Email);
$("#csex").val(data.Sex);
$("#cbirthday").val(data.BirthDay.replace("T", " "));
$("#ccomment").val(data.Comments);
$("#btn_save").hide();
$("#myModal").modal('show');
});
}
//行编辑按钮
function btn_row_edit(id) {
$("#hf_editid").val(id);
$.get(urlS, {
"id": id
}, function(data, status) {
$("#cname").val(data.User_Name);
$("#cphone").val(data.Phone);
$("#cemail").val(data.Email);
$("#csex").val(data.Sex);
$("#cbirthday").val(data.BirthDay.replace("T", " "));
$("#ccomment").val(data.Comments);
$("#btn_save").show();
$("#myModal").modal('show');
});
}
//行删除按钮
function btn_row_del(id) {
$.ajax({
url: urlS + "?id=" + id,
type: "Delete",
dataType: "json",
success: function(data, status) {
window.location.reload();
}
});
}
//修改状态
function ChangUrlStatus(id, status) {
$.ajax({
url: urlS + "?id=" + id + "&status=" + status,
type: "Get",
dataType: "json",
success: function(data, status) {
console.log(status);
}
});
}
</script>
结果
直如弦,死道边;曲如钩,反封侯