• 反射实体自动生成EasyUi DataGrid模板


    用EasyUi Datagrid展示数据的时候总是要一下这样一段代码 

    <table id="dt" class="easyui-datagrid">
        <thead>
            <tr>
                <th data-options="field:'Id',150,align:'center'">Id</th>
                <th data-options="field:'Name',150,align:'center'">Name</th>
                <th data-options="field:'Category',150,align:'center'">Category</th>
                <th data-options="field:'Price',150,align:'center'">Price</th>
                <th data-options="field:'Binary',150,align:'center'">Binary</th>
                <th data-options="field:'操作',80,align:'center',formatter:formatOperate" >操作</th>
            </tr>
        </thead>
    </table>

     其实就是对应后台的一个实体类,具体展示就是对于的属性名。我是一个比较懒的人,总是不喜欢做重复性的工作。刚好最近我又量用到EasyUi Datagrid,拷贝了两次这个代码我就烦了,于是想想怎么直接通过实体(ViewModel)来生成对应的easyui datagrid HTML代码。就像MVC带的验证一样,在类上打上自定义的属性,最后在客户端就能实现对应的验证功能。其实就是根据自定义的属性在客户端生成对应的js代码。为了避免反复写html代码这个繁琐的工作,于是我开发了一个简版的datagrid模板生成器。每次只要你想偷懒的时候总是能找到方法。

    于是我花了点时间来实现这个想法,并投入到项目中使用。开始没有考虑太多,只是临时满足我现在的需求,以下是主要代码。就是通过反射取出实体的所有字段,然后遍历每个字段,拿到字段上自定义的属性,并挨个处理。根据easyui datagrid模板要求,我们主要是设置table的表头,column每个字段

    namespace WebSeat.Web.Core.EasyUi
    {
    #pragma warning disable 693
        public class GenerateDataGrid<T> where T : new()
    #pragma warning restore 693
        {
    
            #region Tools Methods
    
            public static IEnumerable<PropertyInfo> GetPropertyInfoList(T entity)
            {
                return
                    entity.GetType()
                        .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase)
                        .Where(propertyInfo => propertyInfo.Name.ToLower() != "id"); //Id为主键,不能插入。写死了,这个可以做相应修改,主要在字段删改时用到
            }
    
            public static IEnumerable<PropertyInfo> GetAllPropertyInfoList(T entity)
            {
                return
                    entity.GetType()
                        .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            }
    
    
            #endregion
    
            public static string GetDataGridTemplate()
            {
                return GetDataGridTemplate(new T());
            }
    
            /// <summary>
            ///     生成Datagrid的模板
            /// </summary>
            /// <param name="entity"></param>
            /// <returns></returns>
            public static string GetDataGridTemplate(T entity)
            {
                var sb = new StringBuilder();
                //先获取类的Attribute
                CustomAttributeData entityType =
                    typeof(T).CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(DataOptionsAttribute));
    
                #region 对实体的Attibute属性进行处理
    
                //类的这个自定义属性不为空
                bool isShowNotAttr = true;
                string options = string.Empty;
                if (entityType != null)
                {
                    if (entityType.NamedArguments != null)
                    {
                        foreach (CustomAttributeNamedArgument v in entityType.NamedArguments)
                        {
                            if ((String.CompareOrdinal(v.MemberName, "IsShowNotAttr")) == 0)
                            {
                                isShowNotAttr = v.TypedValue.Value is bool && (bool)v.TypedValue.Value;
                                continue;
                            }
                            if ((String.CompareOrdinal(v.MemberName, "Options")) == 0)
                            {
                                options = v.TypedValue.Value as string;
                            }
                        }
                    }
                }
                options = string.IsNullOrWhiteSpace(options) ? "" : options;
    
                #endregion
    
                //获取所有类的Property
                IEnumerable<PropertyInfo> properties = GetAllPropertyInfoList(entity);
    
                //如果设置有不显示没有dataoptions标记的,如果有些字段不显示出来,这个就有作用了。
                if (!isShowNotAttr)
                {
                    properties = properties.Where(n => n.CustomAttributes.Any(a => a.AttributeType == typeof(DataOptionsAttribute)));
                }
                //没有打标记的也要取出来,转换成key-value集合,key是字段名,value是它的GetCustomAttributes。DataOptionsAttribute 自定义属性,见下面代码
                Dictionary<string, List<Attribute>> colDicOpts = properties.ToDictionary(property => property.Name,
                    property =>
                    {
                        var list = new List<Attribute>
                        {
                            property.GetCustomAttributes(typeof (DataOptionsAttribute), false).FirstOrDefault() as DataOptionsAttribute,
                            property.GetCustomAttributes(typeof (DisplayAttribute), false).FirstOrDefault() as DisplayAttribute
                        };
                        return list;
                    }
                    );
                   
    //开始拼接,天添加talbe 部分,id和其他的自己可改下代码,做成更灵活的 sb.AppendLine("<table id=\"dt\" class=\"easyui-datagrid\" data-options=\"" + options + "\" > <thead> <tr>"); //挨个遍历 处理,添加 tr foreach (PropertyInfo pro in properties) { //get CustomAttributes var custAttrs = colDicOpts.SingleOrDefault(n => n.Key == pro.Name); sb.AppendLine(AppenedTemplate(Template.DataGridTh, custAttrs, pro)); } sb.AppendLine(@" </tr> </thead> </table>"); return sb.ToString(); } private static string AppenedTemplate(string template, KeyValuePair<string, List<Attribute>> attributes, PropertyInfo proinfo = null) { var displayName = attributes.Value.SingleOrDefault(n => n is DisplayAttribute) as DisplayAttribute; //设置字段显示的名称,自己直接设置DisplayAttribute,这个大家肯定很熟悉的属性,如果设置有DisplayAttribute就显示设置的Name否则就是默认字段名称 string str = Template.RegV.Replace(template, displayName != null ? displayName.Name : attributes.Key); //设置显示的字段field,就是行column显示的字段,这个都是实在字段名,字段名就是key str = Template.RegF.Replace(str, attributes.Key); var dataOptions = attributes.Value.SingleOrDefault(n => n is DataOptionsAttribute) as DataOptionsAttribute; //由于我自己的需要,我要对DateTime类型进行特殊处理 if (proinfo != null && proinfo.PropertyType == typeof(DateTime)) { //没有自定义dataOptions属性的值 if (dataOptions == null) { //WebJs.Format.formatTime 自己的js时间格式化函数 str = Template.RegD.Replace(str, "formatter:WebJs.Format.formatTime");//默认时间格式 } else { str = dataOptions.Options.IndexOf("formatter", StringComparison.CurrentCultureIgnoreCase) >= 0 ? //已经设置formatter Template.RegD.Replace(str, dataOptions.Options) : //默认设置formatter Template.RegD.Replace(str, dataOptions.Options + "formatter:WebJs.Format.formatTime"); } } else { //替换data-option 的值, 如果为空就直接替换为空 str = dataOptions == null ? //把前面的逗号也替换掉 Template.RegDi.Replace(str, string.Empty) : Template.RegD.Replace(str, dataOptions.Options); } return str; } } }

    DataOptionsAttribute 为自定义属性,Options 的值,到时就直接替换到模板的 data-options里。既是改字段在表头显示的汉字。

    namespace WebSeat.Web.Core.Attributes
    {
        [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false), Serializable]
        public class DataOptionsAttribute : Attribute
        {
            public DataOptionsAttribute()
            {
                IsShowNotAttr = true;
            }
            /// <summary>
            /// data-options
            /// </summary>
            public string Options { get; set; }
            /// <summary>
            /// 是否显示类属性上没有打标记的元素
            /// </summary>
            public bool IsShowNotAttr { get; set; }
        }
    }

    //模板类 

    //模板,这里只用到这一部分
    public
    static class Template { public const string DataGridTh = "<th data-options=\"field:'{field}',align:'center',{d}\" > {v}</th>"; public static Regex RegV = new Regex(@"\{v\}"); public static Regex RegF = new Regex(@"\{field\}"); public static Regex RegD = new Regex(@"\{d\}"); public static Regex RegDi = new Regex(@",\{d\}"); }

    最后做成HtmlHelper 扩展方法,方便页面调用 ,这里贴出关键代码

    namespace WebSeat.Web.Core.Extends
    {
        public static class ExtendClass
        {     /// <summary>
            /// HtmlHelper扩展方法
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="html"></param>
            /// <param name="entity"></param>
            /// <returns></returns>
            public static MvcHtmlString CreateDataGridTemplate<T>(this HtmlHelper html, T entity) where T : new()
            {
                return new MvcHtmlString(GenerateDataGrid<T>.GetDataGridTemplate(entity));
            }       
        }
    }

    先是一个基类,然后是一个viewmodel继承基类,注意里面自定义的DataOptions 属性

        /// <summary>
        ///     模型基类
        /// </summary>
        public abstract class BaseViewModel
        {
            /// <summary>
            ///     ID
            /// </summary>
            [Display(Name = "主键ID")]
            public int Id { get; set; }
    
            /// <summary>
            ///     添加数据时间
            /// </summary>
            [Display(Name = "添加数据时间")]
            public DateTime CreateTime { get; set; }
        }
        /// <summary>
        ///     班级列表实体
        /// </summary>
        public class ClassGradeListViewModel : BaseViewModel
        {
            /// <summary>
            ///     班级名称
            /// </summary>
            [Display(Name = "班级名称")]
            public string Name { get; set; }
    
            /// <summary>
            ///     班级图片地址
            /// </summary>
            [DataOptions(Options = "ddd:'sdfdsf',xj:'321'")]//对应到列上的data-options 就写到这里,类也是一样
            public string PicUrl { get; set; }
        }

    以下是页面代码,我对easyUi做了一点封装,@Html.CreateDataGridTemplate(new ClassGradeListViewModel())//这句代码生成datagrid 模板

    @using WebSeat.FlipCourse.WebApi.ViewModels
    @using WebSeat.Web.Core.EasyUi
    @using WebSeat.Web.Core.Extends
    @{
        ViewBag.Title = "LoadClassList";
        Layout = "~/Areas/TestApi/Views/Shared/_EasyUiLayout.cshtml";
    }
    
    @section searchs{
        StudentId:<input type="text" id="StudentId" name="StudentId"  init="请输入StudentId" class="easyui-numberbox" validtype="isId" />
        ClassId:<input type="text" id="ClassId" name="ClassId" value="9" init="请输入ClassId" class="easyui-numberbox" validtype="isId" />
        <a href="javascript:;"class="easyui-linkbutton" data-options="@IconCls.Search" onclick="LoadClassList()">LoadClassList</a>
    }
    //一句话搞定模板生成,再也不用每次写一堆html代码了 @Html.CreateDataGridTemplate(
    new ClassGradeListViewModel())//这句代码生成datagrid 模板 @section scripts{ <script type="text/javascript"> function LoadClassList(opts) { WebJs.EasyUi.loadpageList('/api/Student/LoadClassList'); } </script> }

    //对应部分js代码,去掉了很多,大多是根据我们自己的需求来写的

    //EasyUi 
    WebJs.EasyUi = (function () {
        //datagrid的默认配置
        var defaultOpts = {
            collapsible: true,
            rownumbers: true,
            singleSelect: true,
            pagination: true,
            striped: true,
            fit: true,
            border: false,
            method: 'get',
            toolbar: "#Search",
            idField: 'Id',
            pageSize: 10,
            pageNumber: 1,
            headers: {
                "contentType": "application/json; charset=utf-8",
                "token": WebJs.Utils.GetCookie('Token') || "token"
            },
            loadFilter: filterData,
            reloadFunc: function () { return false; },
            onLoadError: WebJs.Common.ShowErrors
        },
            loadTimmer, //记录 timmer防止反复加载
            loadTime = 0, //多少毫秒加载一次
            accordion = '#aa',
            tabId = '#tabs',
            layOutId = '#body',
            dtId = '#dt';
        //取得Id
        function getdg(id) { //取得datagrid的Id  默认为 dt,  
            id = id || dtId;
            return $(id);
        }   
        //扩展EasyUI的验证
        function extendEasyUiValidate() {
            $.extend($.fn.validatebox.defaults.rules, {
                pattern: {
                    validator: function (value, param) {
                        var re = new RegExp('' + param[0], 'gi');
                        //if (param[1]) { msg = param[1]; }
                        //WebJs.Dialog.Tip(param[0] +param[1]+ "===" + value + "---" + re.test(value));
                        return re.test(value);
                    },
                    message: '输入格式不正确'
                },
                maxLength: {
                    validator: function (value, param) {
                        return value.trim().length <= param[0];
                    },
                    message: '最多只能输入{0}个字符'
                },
                list: {
                    validator: function (value, param) {
                        return /^\d[\d|,?]*/gi.test(value);
                    },
                    message: '输入格式不对,数字之间都好隔开'
                },
                isId: {
                    validator: function (value, param) {
                        return /^[1-9]\d*$/gi.test(value) && ((value | 0) > 0 && (value | 0) < 2e6);
                    },
                    message: 'Id必须是数字,类型为int'
                },
                equalTo: {
                    validator: function (value, param) {
                        return value == $(param[0]).val();
                    },
                    message: '两次输入的字符不一至'
                },
                number: {
                    validator: function (value, param) {
                        return /^\d+$/.test(value);
                    },
                    message: '请输入数字'
                }
            });
        }
        //专为我们自己的分页而生
        function loadpageList(url, id) {
            var form = $('#SearchForm');
            if (form.children().length && !form.form('validate')) {
                return;
            }
            var para = new BaseParams(),//和后台分页实体对应
                formjson = form.serializeJson(),//serializeJson 需要自己扩展
                params = $.extend(para, formjson),cfgs = {
                   method: 'post',
                   queryParams: params
                };
            //设置datagrid的分页参数 
            cfgs.pageSize = params.PageSize || 10;
            cfgs.pageNumber = params.PageIndex || 1;
            WebJs.EasyUi.LoadData(url,cfgs,id);
        }
        return {
            //加载datagrid的数据
            LoadData: function (url, opts, id) {
                //clearTimeout(loadTimmer);
                var defaults = $.extend(defaultOpts, opts || {});
                url && (defaults.url = url);
                //loadTimmer = setTimeout(function () {
                //可以对datagrid进行缓存
                getdg(id).datagrid(defaults);
                //}, loadTime);
            },
            //加载分页数据
            loadpageList: loadpageList,      
            filterData: filterData
        };
    })();

    //最终页面效果, 生成的datagrid模板

    调用一句话就生成datagrid模板,这个不适合复杂的模板。

    我暂时就想到这些,这样可以在项目组偷个懒。

    其实项目中很多地方都可以这样,只要有想法自己就去做,不管做的好还是差,做成功还是有点小成就感。

    做完这个东西并且在项目中实际运用,最后效果良好,各种好使,当然后来也有很多改动。

  • 相关阅读:
    黑马程序员——【Java基础】——Java IO流
    黑马程序员——【Java基础】——泛型、Utilities工具类、其他对象API
    黑马程序员——【Java基础】——集合框架
    nodeJs与elementUI实现上图片
    NodeJS连接mysql数据库
    nodeJs实现跨域
    将Express生成器下的pug修改为html
    git使用总结
    使用vue+elementUI组件实现表格自动完成
    nginx配置thinkphp5
  • 原文地址:https://www.cnblogs.com/Bond/p/3469798.html
Copyright © 2020-2023  润新知