通过实例学习Fireasy开发(补充)

      本文目录

通过实例学习Fireasy开发(上篇)

通过实例学习Fireasy开发(中篇)

通过实例学习Fireasy开发(下篇)

      通过实例学习Fireasy开发(补充)

前面的功能已经开发完成了,但是这里专门用一章来进行补充。

      一、EasyUI验证

不知道你有没有发现,我们虽然在EmployeeMetada里加了验证特性RequiredAttribute、StringLengthAttribute,但是页面并没有在data-options里生成validType。这是由于少了Fireasy.Portal组件造成了。我们只需要把ValidateBoxSettingBinder和NumberBoxSettingBinder这两个类拷贝过来就行了。

ValidateBoxSettingBinder主要负责将基本的验证绑定到ValidateBoxSettings对象的ValidType属性中。

    /// <summary>
    /// <see cref="ValidateBoxSettings"/> 的绑定者。
    /// </summary>
    public class ValidateBoxSettingBinder : ISettingsBinder
    {
        public bool CanBind(ISettingsBindable settings)
        {
            return typeof(ValidateBoxSettings).IsAssignableFrom(settings.GetType());
        }

        public void Bind(Type modelType, string propertyName, ISettingsBindable settings)
        {
            //模型类型必须实现自 IEntity
            if (!typeof(IEntity).IsAssignableFrom(modelType))
            {
                return;
            }

            //获取对应的依赖属性
            var property = PropertyUnity.GetProperty(modelType, propertyName);
            if (property == null)
            {
                return;
            }

            var vsettings = settings as ValidateBoxSettings;
            //获取依赖属性所指定的验证特性
            var validTypes = new List<string>();
            foreach (var validation in ValidationUnity.GetValidations(property))
            {
                ParseValidation(vsettings, validation, validTypes);
            }

            vsettings.ValidType = validTypes.ToArray();
        }

        /// <summary>
        /// 解析 <see cref="ValidationAttribute"/> 对象。
        /// </summary>
        /// <param name="settings"></param>
        /// <param name="validation">要解析的 <see cref="ValidationAttribute"/> 对象。</param>
        /// <param name="validTypes">如果 <paramref name="validation"/>  能与 EasyUI 的客户端验证所对应,则添加到 validType 属性中。</param>
        private void ParseValidation(ValidateBoxSettings settings, ValidationAttribute validation, List<string> validTypes)
        {
            //必填验证特性
            var required = validation as RequiredAttribute;
            if (required != null)
            {
                settings.Required = true;
                return;
            }

            //长度验证特性
            var stringLength = validation as StringLengthAttribute;
            if (stringLength != null)
            {
                validTypes.Add(string.Format("length[{0},{1}]", stringLength.MinimumLength, stringLength.MaximumLength));
                return;
            }

            //电话验证特性
            var telphone = validation as TelphoneAttribute;
            if (telphone != null)
            {
                validTypes.Add("phone");
                return;
            }

            //手机验证特性
            var mobile = validation as MobileAttribute;
            if (mobile != null)
            {
                validTypes.Add("mobile");
                return;
            }

            //手机或电话验证特性
            var telOrMobile = validation as TelphoneOrMobileAttribute;
            if (telOrMobile != null)
            {
                validTypes.Add("phoneOrMobile");
                return;
            }

            //邮箱验证特性
            var email = validation as EmailAttribute;
            if (email != null)
            {
                validTypes.Add("email");
                return;
            }

            var ascii = validation as AsciiCodingAttribute;
            if (ascii != null)
            {
                validTypes.Add("ascii");
                return;
            }

            var un = validation as UserNameAttribute;
            if (un != null)
            {
                validTypes.Add("username");
                return;
            }

            var chinese = validation as ChineseCodingAttribute;
            if (chinese != null)
            {
                validTypes.Add("chinese");
            }
        }
    }

NumberBoxSettingBinder主要负责把小数位、最大值、最小值绑定到NumberBoxSettings对象中。

    /// <summary>
    /// <see cref="NumberBoxSettings"/> 的绑定者。
    /// </summary>
    public class NumberBoxSettingBinder : ISettingsBinder
    {
        public bool CanBind(ISettingsBindable settings)
        {
            return typeof(NumberBoxSettings).IsAssignableFrom(settings.GetType());
        }

        public void Bind(Type modelType, string propertyName, ISettingsBindable settings)
        {
            var nsettings = settings as NumberBoxSettings;
            if (!typeof(IEntity).IsAssignableFrom(modelType))
            {
                return;
            }

            //获取对应的依赖属性
            var property = PropertyUnity.GetProperty(modelType, propertyName);
            if (property == null)
            {
                return;
            }

            nsettings.Precision = property.Info.Scale;

            //找 RangeAttribute 特性
            var range = ValidationUnity.GetValidations(property).Where(s => s is RangeAttribute).Cast<RangeAttribute>().FirstOrDefault();
            if (range != null)
            {
                nsettings.Min = range.Minimum.To<decimal?>();
                nsettings.Max = range.Maximum.To<decimal?>();
            }
        }
    }

最后,在global.asax的Application_Start方法里,加入以下的代码:

        protected void Application_Start(object sender, EventArgs e)
        {
            //资源打包配置
            BundleHelper.Config();

            //默认是使用MEF导出服务的,改成使用aspx对应的类文件作为服务
            HttpConfiguration.Default.ServiceFactory = new AspPageServiceFactory();

            //配置http服务的路由,依子目录的级数而定
            HttpConfiguration.MapHttpRoute("{service}.ajx/{action}");
            HttpConfiguration.MapHttpRoute("{p1}/{service}.ajx/{action}");
            HttpConfiguration.MapHttpRoute("{p1}/{p2}/{service}.ajx/{action}");
            HttpConfiguration.MapHttpRoute("{p1}/{p2}/{p3}/{service}.ajx/{action}");

            SettingsBindManager.RegisterBinder("validatebox", new ValidateBoxSettingBinder());
            SettingsBindManager.RegisterBinder("numberbox", new NumberBoxSettingBinder());
        }

为了达到效果,我们修改一下WebApplication1.Data项目下的EmployeeMetadata类(在Employee_Ex.cs文件内),为Mobile加上手机验证,为Name、Post、Sex和Birthday加上必填验证。

    public class EmployeeMetadata
    {

        /// <summary>
        /// 属性 Id 的验证特性。
        /// </summary>

        [Required]
        [StringLength(36)]
        public object Id { get; set; }

        /// <summary>
        /// 属性 DeptId 的验证特性。
        /// </summary>

        [Required]
        [StringLength(36)]
        public object DeptId { get; set; }

        /// <summary>
        /// 属性 No 的验证特性。
        /// </summary>

        [StringLength(20)]
        public object No { get; set; }

        /// <summary>
        /// 属性 Sex 的验证特性。
        /// </summary>
                [Required]
        public object Sex { get; set; }

        /// <summary>
        /// 属性 Name 的验证特性。
        /// </summary>

        [Required]
        [StringLength(20)]
        public object Name { get; set; }

        /// <summary>
        /// 属性 Birthday 的验证特性。
        /// </summary>

        [Required]
        public object Birthday { get; set; }

        /// <summary>
        /// 属性 Post 的验证特性。
        /// </summary>

        [Required]
        public object Post { get; set; }

        /// <summary>
        /// 属性 Mobile 的验证特性。
        /// </summary>

        [Fireasy.Data.Validation.Mobile]
        [StringLength(20)]
        public object Mobile { get; set; }

        /// <summary>
        /// 属性 Address 的验证特性。
        /// </summary>

        [StringLength(100)]
        public object Address { get; set; }

        /// <summary>
        /// 属性 Description 的验证特性。
        /// </summary>

        [StringLength(500)]
        public object Description { get; set; }

        /// <summary>
        /// 属性 State 的验证特性。
        /// </summary>

        public object State { get; set; }

        /// <summary>
        /// 属性 DelFlag 的验证特性。
        /// </summary>

        public object DelFlag { get; set; }

        /// <summary>
        /// 属性 Photo 的验证特性。
        /// </summary>

        [StringLength(200)]
        public object Photo { get; set; }
    }

好了,我们现在来看看EmployeeEdit.aspx有表单有没有加上数据验证:

      二、数据列表的排序

datagrid的columns中,我们默认生成了sortable属性,但是后台代码中并没有使用排序。其实代码是生成了的,只需将注释行Order(sorting)取消就要以了。

        /// <summary>
        /// 根据查询条件获取员工。
        /// </summary>
        /// <param name="deptNo">部门编码。</param>
        /// <param name="startTime">开始日期。</param>
        /// <param name="endTime">结束时间。</param>
        /// <param name="post">岗位类别。</param>
        /// <param name="keyword">关键字</param>
        /// <returns></returns>
        [ExceptionBehavior(true)]
        public object GetEmployees(string deptNo, DateTime? startTime, DateTime? endTime, PostKinds? post, string keyword)
        {
            var pager = EasyUIHelper.GetDataPager();
            var sorting = EasyUIHelper.GetSorting();
            using (var context = new DbContext())
            {
                var list = context.Employees
                    .Segment(pager)
                    .OrderBy(sorting)
                    .AssertWhere(!string.IsNullOrEmpty(deptNo), s => s.Dept.No.StartsWith(deptNo))
                    .AssertWhere(startTime != null, s => s.Birthday >= startTime.Value.StartOfDay())
                    .AssertWhere(endTime != null, s => s.Birthday <= endTime.Value.EndOfDay())
                    .AssertWhere(post != null, s => s.Post == post)
                    .AssertWhere(!string.IsNullOrEmpty(keyword), s => s.Name.Contains(keyword))
                    .Select(s => new
                        {
                            s.Id,
                            s.No,
                            s.Name,
                            Sex = ((Sex)s.Sex).GetDescription(),
                            Post = s.Post.GetDescription(),
                            s.Birthday,
                            s.Mobile,
                            s.Address,
                            s.Description
                        })
                    .ToList();
                return EasyUIHelper.Transfer(pager, list);
            }
        }

但有一种情况,即没有单击列头的情况下,默认使用某一属性排序,比如按编码降序排列,这时,Order方法可以这样写:

        /// <summary>
        /// 根据查询条件获取员工。
        /// </summary>
        /// <param name="deptNo">部门编码。</param>
        /// <param name="startTime">开始日期。</param>
        /// <param name="endTime">结束时间。</param>
        /// <param name="post">岗位类别。</param>
        /// <param name="keyword">关键字</param>
        /// <returns></returns>
        [ExceptionBehavior(true)]
        public object GetEmployees(string deptNo, DateTime? startTime, DateTime? endTime, PostKinds? post, string keyword)
        {
            var pager = EasyUIHelper.GetDataPager();
            var sorting = EasyUIHelper.GetSorting();
            using (var context = new DbContext())
            {
                var list = context.Employees
                    .Segment(pager)
                    .OrderBy(sorting, u => u.OrderByDescending(t => t.No))
                    .AssertWhere(!string.IsNullOrEmpty(deptNo), s => s.Dept.No.StartsWith(deptNo))
                    .AssertWhere(startTime != null, s => s.Birthday >= startTime.Value.StartOfDay())
                    .AssertWhere(endTime != null, s => s.Birthday <= endTime.Value.EndOfDay())
                    .AssertWhere(post != null, s => s.Post == post)
                    .AssertWhere(!string.IsNullOrEmpty(keyword), s => s.Name.Contains(keyword))
                    .Select(s => new
                        {
                            s.Id,
                            s.No,
                            s.Name,
                            Sex = ((Sex)s.Sex).GetDescription(),
                            Post = s.Post.GetDescription(),
                            s.Birthday,
                            s.Mobile,
                            s.Address,
                            s.Description
                        })
                    .ToList();
                return EasyUIHelper.Transfer(pager, list);
            }
        }

      三、图片上传

员工表设计了一个照片的字段,但是之前我们并没有用到它,现在我们就把照片上传给加上。

首先,要引入上传所需的js,只需要在 BundleHelper.Render 后面再加上 upload 就可以了。

    <%= BundleHelper.Render("base", "upload") %>

 接下来修改一下表单的table,加一个图片和上传图片的链接:

        <table class="form-body">
            <tr>
                <td class="addon">部门</td>
                <td><%= Html.ComboBox(s => s.DeptId).MarkDelayedSet().MarkNoClear()%></td>
                <td rowspan="4" style="text-align:center">
                    <img id="img" src="../Images/nopic1.png" style="width: 161px; height: 110px" /><br />
                    <a target="#img" class="uploader">上传图片</a>
                </td>
            </tr>
            <tr>
                <td class="addon">编号</td>
                <td><%= Html.TextBox(s => s.No) %></td>
            </tr>
            <tr>
                <td class="addon">性别</td>
                <td><%= Html.ComboBox(s => s.Sex, typeof(WebApplication.Data.Model.Sex), new ComboBoxSettings { PanelHeight = 0 }).MarkNoClear() %></td>
            </tr>
            <tr>
                <td class="addon">姓名</td>
                <td><%= Html.TextBox(s => s.Name) %></td>
            </tr>
            <tr>
                <td class="addon">出生日期</td>
                <td><%= Html.DateBox(s => s.Birthday) %></td>
            </tr>
            <tr>
                <td class="addon">职务</td>
                <td><%= Html.ComboBox(s => s.Post, typeof(WebApplication.Data.Model.PostKinds), new ComboBoxSettings { PanelHeight = 0 }).MarkNoClear() %></td>
            </tr>
            <tr>
                <td class="addon">手机号码</td>
                <td><%= Html.TextBox(s => s.Mobile) %></td>
            </tr>
            <tr>
                <td class="addon">家庭住址</td>
                <td><%= Html.TextBox(s => s.Address) %></td>
            </tr>
            <tr>
                <td class="addon">个人说明</td>
                <td colspan="3"><%= Html.TextMultiBox(s => s.Description) %></td>
            </tr>
            <tr>
                <td class="addon">可用</td>
                <td><%= Html.CheckBox(s => s.State, true) %></td>
            </tr>
        </table>

增加一个initUploader函数,用于添加“上传图片”的事件初始化,并在页面加载完成后调用initUploader函数:

        $(function () {
            loadInfo();
            initUploader();
        });

        //初始化上传插件
        function initUploader() {
            $(‘.uploader‘).upload({
                extFilter: ‘png;jpg;jpeg;gif‘,
                action: ‘EmployeeEdit.ajx/UploadPhoto?id=‘ + id,
                useHttpModule: false,
                onFileExtError: function () {
                    common.alert(‘只允许上传png、jpg、jpeg、gif类型的文件。‘)
                },
                onComplete: function (result, index, ele) {
                    $(ele.attr(‘target‘)).attr(‘src‘, ‘../‘ + result.fileName);
                    $(ele.attr(‘target‘)).attr(‘file‘, result.fileName);
                    if (id != ‘‘) {
                        var data = { id: id, url: encodeURI(result.fileName) };
                        $.post(‘EmployeeEdit.ajx/UpdatePhoto‘, data);
                    }
                }
            });
        }

upload是一个jquery插件,可以为.uploader标签添加上传文件的事件。上传的处理请求是UploadPhoto方法,上传完后,更新员工的照片,即不需要点击保存按钮,也能生效。在EmployeeEdit.aspx.cs里增加UploadPhoto方法:

        /// <summary>
        /// 上传照片。
        /// </summary>
        /// <returns></returns>
        public object UploadPhoto()
        {
            ServiceContext.Current.ResultWriter = new FileUploadResultWriter();
            var request = HttpContext.Current.Request;
            if (request.Files.Count == 0)
            {
                return null;
            }

            var file = request.Files[0];
            var virtualPath = "upfiles\\photos";
            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, virtualPath);
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            var fileId = Guid.NewGuid().ToString();
            var fileExt = file.FileName.Substring(file.FileName.LastIndexOf("."));

            var fileName = Path.Combine(path, fileId + fileExt);
            var virtualFile = Path.Combine(virtualPath, fileId + fileExt).Replace("\\", "/");
            file.SaveAs(fileName);

            return Result.Success("上传成功。", new { fileId, fileName = virtualFile });
        }

DefaultResultWriter用于改变content-type,因为默认是使用application/json的,但是此时它会提示下载json,因此把content-type改成text/json即可。

    /// <summary>
    /// 针对文件上传的结果写入器。
    /// </summary>
    public class FileUploadResultWriter : DefaultResultWriter
    {
        protected override void WriteJson(ServiceContext serviceContext, HttpResponseBase response, object value)
        {
            response.ContentType = "text/json";
            response.Write(JsonSerialize(serviceContext, value));
        }
    }

再增加一个UpdatePhoto方法,只用更新实体的Photo属性就可以了:

        /// <summary>
        /// 更新照片路径。
        /// </summary>
        /// <param name="id"></param>
        /// <param name="url"></param>
        public void UpdatePhoto(string id, string url)
        {
            using (var context = new DbContext())
            {
                context.Employees.Update(new Employee { Photo = url }, s => s.Id == id);
            }
        }

最后,在EmployeeEdit.aspx中修改loadInfo函数的saveInfo函数如下:

        //加载信息
        function loadInfo() {
            if (id != ‘‘) {
                $.getJSON(‘EmployeeEdit.ajx/GetEmployee?id=‘ + id, function (data) {
                    common.processResult(data, function () {
                        $(‘#form1‘).form(‘load‘, data);
                        deptId = data.DeptId;
                        loadDepts();

                        if (data.Photo) {
                            $(‘#img‘).attr(‘file‘, data.Photo);
                            $(‘#img‘).attr(‘src‘, data.Photo);
                        }

                    });
                });

                $(‘#btnSaveAndNew‘).remove();
            }
            else {
                loadDepts();
            }
        }

        //保存信息
        function saveInfo(isNew) {
            if (!$(‘#form1‘).form(‘validate‘)) {
                return;
            }

            var postData = new Object();

            //将表单填充的内容序列化为json
            var data = $(‘#form1‘).form(‘save‘);
            data.DeptId = $(‘#cboDeptId‘).combotree(‘getValue‘);
            data.Photo = $(‘#img‘).attr(‘file‘);
            postData["info"] = JSON.stringify(data);

            common.showProcess();
            $.post(‘EmployeeEdit.ajx/SaveEmployee?id=‘ + id, postData, function (result) {
                common.processResult(result, function () {
                    if (isNew) {
                        $(‘#form1‘).form(‘clear‘);
                    }

                    id = isNew ? ‘‘ : result.data;
                    common.setReturnValue(true);
                });
            });
        }

照片上传至此结束。

非常感谢你的支持,在此附上示例的源代码:

★★★源代码下载★★★

时间: 2024-10-12 21:00:39

通过实例学习Fireasy开发(补充)的相关文章

通过实例学习Fireasy开发(下篇)

      本文目录 通过实例学习Fireasy开发(上篇) 通过实例学习Fireasy开发(中篇)       通过实例学习Fireasy开发(下篇) 通过实例学习Fireasy开发(补充)       一.员工列表页面 EmployeeList.aspx页面的需求是这样的,左边是部门树,右边是员工列表,点击部门节点后右边显示该部门下面的员工,同时提供岗位.生日期间查询. 对table:#dg处进行改造,加下一个treegrid列表: <div data-options="region:

通过实例学习Fireasy开发(中篇)

      本文目录 通过实例学习Fireasy开发(上篇) 通过实例学习Fireasy开发(下篇) 通过实例学习Fireasy开发(补充) 上篇我们介绍了进行Fireasy开发的前期准备,接下来,我们将通过两个小功能来演示怎么进行业务开发.       一.部门列表页面 部门是树型结构,Fireasy采用了00010001这样的编码来支持树结构实体的快速开发. 1. 修改Dept类(使用Dept_Ex分部类文件),在类名称上添加EntityTreeMappingAttribute特性,Inne

通过实例学习Fireasy开发(上篇)

Fireasy一直在发布新版本,但是怎么用,到底好不好用,估计大家都有这样的疑惑.所以,今天花点时间通过一个简单的示例一步一步来介绍fireasy的用法. 首先有必要介绍一下Fireasy的组件构成: Fireasy.Common 公共组件库,主要包含缓存管理.日志管理.序列化.动态编译.扩展方法等. Fireasy.Data 数据库组件库,提供数据库的操作,语法.批量插入.数据库构架等. Fireasy.Data.Entity 实体组件库,ORMapper.LINQ解析.数据上下文.树实体持久

python3全栈开发-补充UDP的套接字、操作系统、并发的理论基础

一.基于UDP的套接字 udp套接字简单示例 import socket ip_port=('1.1.1.1',8181) BUFSIZE=1024 udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) udp_server_client.bind(ip_port) while True: msg,addr=udp_server_client.recvfrom(BUFSIZE) print(msg,addr) udp_

彩票历史记录分析工具 -- 通过实例学习wpf开发

前言 虽然本人对彩票不感兴趣,仍然有不少人对此情有独钟.他们花大量时间精力去分析彩票的历史记录,企图发现规律,为下一次投注做指导,希望“赢的“”概率增大.不管研究历史记录是否有意义,我用软件实现了对彩票的分析,手工分析彩票几天工作量,现在一秒可以实现. 执行程序,点我下载! 程序界面 处理原理分析: 程序实际上是对六合彩分析(彩票种类很多,本文只处理一种).数据格式如下: 2010001 11 13 22 16 21 182010002 22 28 16 5 14 262010003 5 14

终端开发补充 : 读 curses模块官方文档...

curses是一个提供终端屏幕打印和键盘处理的库, 我个人的理解就是终端里的gui(当然它是基于文本的)... 写2048的时候用到了这个库, 所以现在过来好好研究一下这个库... 下面是文档内容 : 首先在你做任何事之前, 你必须先调用 initscr() 初始化curses, 这个函数主要的作用是决定当前终端的类型, 然后发送一些必要的设置给终端, 并且创建独立的内部数据结构. 如果成功初始化的话, 该函数会返回一个代表屏幕的对象, 我们通常称为 stdscr (C语言就有的惯例). 另一方

**iOS开发系列--IOS程序开发概览

http://www.cnblogs.com/kenshincui/p/3890880.html 概览 终于到了真正接触IOS应用程序的时刻了,之前我们花了很多时间去讨论C语言.ObjC等知识,对于很多朋友而言开发IOS第一天就想直接看到成果,看到可以运行的IOS程序.但是这里我想强调一下,前面的知识是你日后开发IOS的基础,没有那些知识你开发IOS会很痛苦,现在很多开发人员做开发都是一知半解,程序质量确实令人担忧,所以还是希望大家能够熟练掌握前面的内容,开发过程中多思考,彻底理解程序运行的原理

iOS开发系列--IOS程序开发概览ios基础

iOS开发系列--IOS程序开发概览 2014-08-04 19:42 by KenshinCui, 72273 阅读, 81 评论, 收藏,  编辑 概览 终于到了真正接触IOS应用程序的时刻了,之前我们花了很多时间去讨论C语言.ObjC等知识,对于很多朋友而言开发IOS第一天就想直接看到成果,看到可以运行的IOS程序.但是这里我想强调一下,前面的知识是你日后开发IOS的基础,没有那些知识你开发IOS会很痛苦,现在很多开发人员做开发都是一知半解,程序质量确实令人担忧,所以还是希望大家能够熟练掌

HTTP协议web开发知识点

HTTP协议那些事儿(Web开发补充知识点) HTTP协议 HTTP协议简介 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网的数据通信的基础. HTTP的发展是由蒂姆·伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起.HTTP的标准制定由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering