没有从第一章开始看的童鞋我建议可以从第一章看起MVC+EF+SqlServer+Easyui简单企业项目(1)
上一章: MVC+EF+SqlServer+Easyui简单企业项目(3)
前几章我们把方法已经写好了,接下来的任务是通过Easyui+mvc的view视图实现列表展示了。话不多说,直接开始。
首先创建一个控制器,右击Controllers—>添加控制器,选择第一个
红色圈圈里边的东西不能删除,后果很严重的,前边的改成你需要的名字,我的是Drinks,这样我的控制器就创建完成,我的名字是“DrinksController”
因为很多地方会用到枚举类型,所以我们创建了一个枚举类型的集合,在Common公共层创建一个EnumHelper的枚举类集合,当然,这些都是小编从其他博主那里抢来的,如果你们可以找到当然可以,不行的话在Common层创建一个名称为EnumHelper的类,把下边的代码赋值到类中即可
/// <summary>
/// 枚举类型集合
/// </summary>
public class EnumHelper
{
/// <summary>
/// 枚举转字典集合
/// </summary>
/// <typeparam name="T">枚举类名称</typeparam>
/// <param name="keyDefault">默认key值</param>
/// <param name="valueDefault">默认value值</param>
/// <returns>返回生成的字典集合</returns>
public static Dictionary<string, object> EnumListDic<T>(string keyDefault, string valueDefault = "")
{
Dictionary<string, object> dicEnum = new Dictionary<string, object>();
Type enumType = typeof(T);
if (!enumType.IsEnum)
{
return dicEnum;
}
if (!string.IsNullOrEmpty(keyDefault)) //判断是否添加默认选项
{
dicEnum.Add(keyDefault, valueDefault);
}
string[] fieldstrs = Enum.GetNames(enumType); //获取枚举字段数组
foreach (var item in fieldstrs)
{
string description = string.Empty;
var field = enumType.GetField(item);
object[] arr = field.GetCustomAttributes(typeof(DescriptionAttribute), true); //获取属性字段数组
if (arr != null && arr.Length > 0)
{
description = ((DescriptionAttribute)arr[0]).Description; //属性描述
}
else
{
description = item; //描述不存在取字段名称
}
dicEnum.Add(description, (int)Enum.Parse(enumType, item)); //不用枚举的value值作为字典key值的原因从枚举例子能看出来,其实这边应该判断他的值不存在,默认取字段名称
}
return dicEnum;
}
}
接下来在Common公共层再创建一个EnumType类,里边用来写需要用到的枚举类型,我这里暂时写了一个是否删除
/// <summary>
/// 枚举类型(是否删除)
/// </summary>
public enum DeleteState
{
[Description("已删除")]
已删除=1,
[Description("未删除")]
未删除 =2
}
因为列表我们会有搜索,所以我们会有一个公司列表的下拉框,这里调用业务逻辑层的公司列表类进行访问,在BLL层创建一个公司列表类名字为CompanyServers并让该类继承BaseServers,接下来在控制器的Index方法里边写绑定数据,以下就是我们新建的控制器中的Index方法,我们上边调用完业务逻辑层,然后再Index里边开始写绑定数据,下边两个就是公司列表和是否删除的两个绑定
//业务逻辑层
private CompanyServers _CompanyServers = new CompanyServers(); //公司列表
/// <summary>
/// 加载饮料列表
/// </summary>
/// <returns></returns>
public ActionResult Index()
{
//获取公司列表信息
var company = _CompanyServers.GetList(e => true).Select(e => new SelectListItem() { Text = e.c_Name, Value = e.c_ID.ToString() }).ToList();
company.Insert(0,new SelectListItem() { Text="全部",Value="0"});
ViewBag.Company = company;
//获取状态信息
var drinksTypeList = EnumHelper.EnumListDic<DeleteState>("全部","0");
var drinksTypeSelectList = new SelectList(drinksTypeList, "value", "key");
ViewBag.DrinksTypeSelect = drinksTypeSelectList;
return View();
}
接下来开始添加视图,右击Index方法,选择添加视图
创建好的视图是一个空视图没有一个代码,下边就由我们自己来创造,我们定义一个table的id为“dg_Drinks”,里边包含用来显示饮料列表,div的id为“tb”里边包含我们来显示工具栏,最下边那个div我们用来显示要搜索的条件,[公司列表和状态] 就是我们控制器当中设置的列表信息,在此处通过ViewBag调用,
<table id="dg_Drinks" align="center"></table>
<div id="tb" style="padding:5px;height:auto">
<div style="margin-bottom:5px">
<a href="#" id="btn_Create" class="easyui-linkbutton" iconCls="icon-add">新增</a>
<a href="#" id="btn_Edit" class="easyui-linkbutton" iconCls="icon-edit">修改</a>
<a href="#" id="btn_Delete" class="easyui-linkbutton" iconCls="icon-remove">删除</a>
</div>
<div>
名称:<input id="txt_Name" type="text" class="easyui-textbox" />
价格:<input id="txt_Price" type="text" class="easyui-textbox" />
公司列表:@Html.DropDownList("Company", ViewBag.Company as IEnumerable<SelectListItem>)
状态:@Html.DropDownList("DrinksTypeSelect", ViewBag.DrinksTypeSelect as IEnumerable<SelectListItem>)
<a href="#" id="btn_Search" class="easyui-linkbutton Search" iconCls="icon-search">查询</a>
</div>
我们要显示列表并且添加Easyui的各个样式,这时候我们需要用到的js包和Easyui的样式包,最下边那个包是专门处理时间格式的,我把代码贴到下边,童鞋们可以自行到官网下载Easyui 的包,我这里 把样式包复制到Web层的Content的文件下了。js包是在Web上添加nuget的jquery的包,我的版本是1.11.1,
<link href="~/Content/easyui/themes/default/easyui.css" rel="stylesheet" />
<link href="~/Content/easyui/themes/icon.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.11.1.js"></script>
<script src="~/Scripts/jquery-1.11.1.min.js"></script>
<script src="~/Content/easyui/jquery.easyui.min.js"></script>
<script src="~/Content/easyui/locale/easyui-lang-zh_CN.js"></script>
<script src="~/Scripts/Toolkit.js"></script>
以下就是Tookit的代码包,专门转换时间格式,童鞋们可以直接拿来用,自行下载找不到的可以在Script文件下添加一个名称为Tookit的javascript的包,并把下边的代码搬过去就可以了
//格式化JSON时间
function FormatJsonTime(date) {
if (date != null) {
var de = new Date(parseInt(date.replace("/Date(", "").replace(")/", "").split("+")[0]));
var y = de.getFullYear();
var m = de.getMonth() + 1;
var d = de.getDate();
var h = de.getHours();
var mi = de.getMinutes();
var s = de.getSeconds();
return y + '-' + (m < 10 ? ('0' + m) : m) + '-' + (d < 10 ? ('0' + d) : d) + ' ' + (h < 10 ? ('0' + h) : h) + ':' + (mi < 10 ? ('0' + mi) : mi) + ':' + (s < 10 ? ('0' + s) : s);
}
else {
return "";
}
}
//格式化日期
function FormatJsonDate(date) {
if (date != null) {
var de = new Date(parseInt(date.replace("/Date(", "").replace(")/", "").split("+")[0]));
var y = de.getFullYear();
var m = de.getMonth() + 1;
var d = de.getDate();
return y + '-' + (m < 10 ? ('0' + m) : m) + '-' + (d < 10 ? ('0' + d) : d);
}
else {
return "";
}
}
我们要显示列表,就要写方法来处理数据,我们首先在控制器中创建一个新的方法
/// <summary>
/// 饮料列表展示方法接口
/// </summary>
/// <param name="viewmodel"></param>
/// <returns></returns>
public ActionResult GetPagedDrinksList(GetPagedDrinksListViewModel viewmodel)
{
}
GetPagedDrinksListViewModel 这个类是在Entity类中的ViewModel文件中创建的类,这个类中的数据是进行前台和后台交互的中间类该类中的数据基本上和数据库中字段相等,字段我们都用用到,最下边的两个数据就是分页查询用到的字段
/// <summary>
/// 饮料数据访问类
/// </summary>
public class GetPagedDrinksListViewModel
{
/// <summary>
/// 饮料主键
/// </summary>
public int d_ID { get; set; }
/// <summary>
/// 饮料名称
/// </summary>
public string d_Name { get; set; }
/// <summary>
/// 饮料价格
/// </summary>
public float d_Price { get; set; }
/// <summary>
/// 饮料产地
/// </summary>
public string d_Address { get; set; }
/// <summary>
/// 生产日期
/// </summary>
public DateTime d_Manufacture { get; set; }
/// <summary>
/// 保质期
/// </summary>
public string d_Expiration { get; set; }
/// <summary>
/// 公司id
/// </summary>
public int d_Company { get; set; }
/// <summary>
/// 是否删除
/// </summary>
public int d_IsDelete { get; set; }
/// <summary>
/// 当前页数
/// </summary>
public int page { get; set; }
/// <summary>
/// 页大小
/// </summary>
public int rows { get; set; }
}
交互类写完之后,我们在业务逻辑层开始写,这个就是分页显示方法,其中我又加了一些新的类文件,我依次贴给你们,请向下边看其中有这个几个
1,PredicateExtensions ——>进行查询业务处理的逻辑类,我也是抢过来的
2,DrinksListViewModel ——>展示给用户看的一个类
3,OperateResult ——>保存结果状态的类,例如查询成功,查询失败等结果
4,DataGridViewModel ——>分页查询的两个数据
这个贴的是drinksServers的业务逻辑类
/// <summary>
/// 分页查询及列表显示
/// </summary>
/// <param name="viewModel"></param>
/// <returns></returns>
public OperateResult GetPagedDrinksList(GetPagedDrinksListViewModel viewModel)
{
//总记录数
int rowCount = 0;
//1.当用户什么都没有输入的时候默认查询所有的
var query = PredicateExtensions.True<drinks>();
//2.根据用户输入的参数信息进行多条件查询
if (!string.IsNullOrWhiteSpace(viewModel.d_Name)) //根据饮料名称
query = query.And(e => e.d_Name.Contains(viewModel.d_Name));
if (viewModel.d_Price > 0) //根据饮料价格
query = query.And(e => e.d_Price == viewModel.d_Price);
if (viewModel.d_IsDelete >0) //是否删除
query = query.And(e => e.d_IsDelete == viewModel.d_IsDelete);
if (viewModel.d_Company > 0) //公司
query = query.And(e => e.d_Company == viewModel.d_Company);
var pagedData = GetPageList(viewModel.page, viewModel.rows, ref rowCount, query, e => e.d_ID, true)
.Select(e => new DrinksListViewModel()
{
d_ID = e.d_ID,
d_Name = e.d_Name,
d_Price = (float)e.d_Price,
d_Address = e.d_Address,
d_Manufacture = (DateTime)e.d_Manufacture,
d_Expiration = e.d_Expiration,
d_Company = (int)e.d_Company,
d_CompanyName = e.Company.c_Name,
d_IsDelete = ((DeleteState)e.d_IsDelete).ToString()
})
.ToList();
var dataGridViewModel = new DataGridViewModel() { total = rowCount, rows = pagedData };
return new OperateResult(ResultStatus.Success, "", dataGridViewModel);
}
PredicateExtensions这个类,小编的水平只知道怎么用,并不知道里边的逻辑,哪位博主知道的可以留言给小编,让小编也进一步学习
/// <summary>
/// ParameterExpression
/// </summary>
internal class ParameterReplacer : ExpressionVisitor
{
public ParameterReplacer(ParameterExpression paramExpr)
{
this.ParameterExpression = paramExpr;
}
public ParameterExpression ParameterExpression { get; private set; }
public Expression Replace(Expression expr)
{
return this.Visit(expr);
}
protected override Expression VisitParameter(ParameterExpression p)
{
return this.ParameterExpression;
}
}
public static class PredicateExtensions
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exp_left, Expression<Func<T, bool>> exp_right)
{
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
var parameterReplacer = new ParameterReplacer(candidateExpr);
var left = parameterReplacer.Replace(exp_left.Body);
var right = parameterReplacer.Replace(exp_right.Body);
var body = Expression.And(left, right);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exp_left, Expression<Func<T, bool>> exp_right)
{
var candidateExpr = Expression.Parameter(typeof(T), "candidate");
var parameterReplacer = new ParameterReplacer(candidateExpr);
var left = parameterReplacer.Replace(exp_left.Body);
var right = parameterReplacer.Replace(exp_right.Body);
var body = Expression.Or(left, right);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
}
DrinksListViewModel这个类文件跟上边那个非常相似,不过为了更好的区别,小编的这个类写的是用来显示给用户看的一个类
//饮料列表显示类
public class DrinksListViewModel
{
/// <summary>
/// 饮料主键
/// </summary>
public int d_ID { get; set; }
/// <summary>
/// 饮料名称
/// </summary>
public string d_Name { get; set; }
/// <summary>
/// 饮料价格
/// </summary>
public float d_Price { get; set; }
/// <summary>
/// 饮料产地
/// </summary>
public string d_Address { get; set; }
/// <summary>
/// 生产日期
/// </summary>
public DateTime d_Manufacture { get; set; }
/// <summary>
/// 保质期
/// </summary>
public string d_Expiration { get; set; }
/// <summary>
/// 公司id
/// </summary>
public int d_Company { get; set; }
/// <summary>
/// 公司名字
/// </summary>
public string d_CompanyName { get; set; }
/// <summary>
/// 是否删除
/// </summary>
public string d_IsDelete { get; set; }
}
OperateResult这个类是用来保存处理结果的状态信息
public enum ResultStatus
{
Error = -1,
Success = 1
}
/// <summary>
/// 保存处理结果及提示信息
/// </summary>
public class OperateResult
{
/// <summary>
/// 结果状态
/// </summary>
public ResultStatus ResultStatus { get; set; }
/// <summary>
/// 消息提示
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 数据
/// </summary>
public object Data { get; set; }
public OperateResult(ResultStatus resultStatus, string msg)
{
this.ResultStatus = resultStatus;
this.Msg = msg;
}
public OperateResult(ResultStatus resultStatus, string msg, object data)
{
this.ResultStatus = resultStatus;
this.Msg = msg;
this.Data = data;
}
}
DataGridViewModel这个类中保存的是分页需要的两个数据
/// <summary>
/// 分页查询需要的数据
/// </summary>
public class DataGridViewModel
{
public int total { get; set; }
public object rows { get; set; }
}
现在业务逻辑都处理完了,只剩下返回到控制器,然后到视图了,
/// <summary>
/// 饮料列表展示方法接口
/// </summary>
/// <param name="viewmodel"></param>
/// <returns></returns>
public ActionResult GetPagedDrinksList(GetPagedDrinksListViewModel viewmodel)
{
var result = _drinksServers.GetPagedDrinksList(viewmodel);
return Json(result.Data);
}
我们只需要在控制器中调用我们上边写的业务逻辑类回调的数据进行转换后可以显示到界面了
我们接下来开始在界面通过 Easyui和javascript来处理
<script type="text/javascript">
$(function () {
$("#dg_Drinks").datagrid({
fitColumns: true, //使列自动展开/收缩到合适的DataGrid宽度。
toolbar: "#tb", //toolbar:通过选择器指定的工具栏。
pagination: true, //pagination:如果为true,则在DataGrid控件底部显示分页工具栏。
fit: false, //fit:当设置为true的时候面板大小将自适应父容器。
singleSelect: true, //如果为true,则只允许选择一行。
rownumbers: true, //如果为true,则显示一个行号列。
url: "/Drinks/GetPagedDrinksList", //url:设置能够返回JSON数据的Action所对应的路径,控制器下的action方法,千万不要错,不然报404错误
columns: [[
{ field: 'd_ID', title: '饮料主键', width: 222, align: "center", },
{ field: 'd_Name', title: '饮料名称', width: 222, align: "center", },
{ field: 'd_Price', title: '饮料价格', width: 222, align: "center", },
{ field: 'd_Address', title: '饮料产地', width: 322, align: "center", },
{ field: 'd_Expiration', title: '保质期', width: 222, align: "center", },
{ field: 'd_CompanyName', title: '公司名称', width: 222, align: "center", },
{
field: 'd_Manufacture', title: '生产日期', width: 222, align: "center", formatter: function (value, row, index) {
return FormatJsonTime(row.d_Manufacture);
}
},
{ field: 'd_IsDelete', title: '是否删除', width: 222, align: "center", }
]]
});
//多条件搜索查询
$("#btn_Search").click(function () {
$("#dg_Drinks").datagrid("load", {
d_Name: $.trim($("#txt_Name").val()),
d_Price: $.trim($("#txt_Price").val()),
d_Company: $.trim($("#Company").val()),
d_IsDelete: $("#DrinksTypeSelect").val()
});
});
});
</script>
上边columns的属性中的field字段要跟饮料显示列表类中的字段保持一致这样数据就会过来,下边看一下我们列表和查询的最终结果
这时候你会发现列表并没有数据,这时候不要急不要慌,我们来慢慢一步一步解决问题,
首先按F12查看是否有错误,这里提示(datagrid is not a function)说明我们的easyui无效,我们先检查easyui的js是否正确引入,下一步打开网页源码,这时候你会发现最下边又出现了了一个Bootstrap的js,这时候就明白了,是js冲突的原因,只需要把下边生成的给干掉就行了
我们现在去把他给干掉,在Web层的Shared文件中的Layout的文件中,把这两行代码给注释掉,现在我们刷新界面再看一下
现在数据就全部出来完了,列表展示成功
测试查询,每页10条,为了方便查看,中间我又插入了一些数据,下边我们查询看一下结果如果、
这是查询公司列表为开心公司的数据。我们的列表分页显示和查询已经完成了
今天我们就到这里了,今天你又进步了一点点没