zoukankan      html  css  js  c++  java
  • 使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神

    使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神

    前言

    接上一篇 使用 EPPlus 封装的 excel 表格导入功能 (一)

    前一篇的是大概能用但是不一定好用的版本

    后来我又重新封装扩展了一下

    支持自定义更多东西(但是封装地是否有必要我就说不清了)

    上个版本的问题

    上个版本封装之后的使用代码:

    public ICollection<TestDto> ExcelImport(IFormFile file)
    {
        var config = ExcelCellOption<TestDto>
        .GenExcelOption("姓名", item => item.Name)
        .Add("年龄", item => item.Age, item => int.Parse(item))
        .Add("性别", item => item.Gender, item => item == "男")
        .Add("身高", item => item.Height, item => double.Parse(item));
    
        ICollection<TestDto> result = ExcelOperation.ExcelToEntity(file.OpenReadStream(), config);
    
        return result;
    }
    

    设计逻辑是 一个单元格 对应 实体中的一个字段

    这个设计一开始是没什么问题的,将excel中的数据导入到 DTO集合 中,然后就可以进行下一步的操作

    但在实际使用的时候发现,拿到 DTO集合 之后,总是需要再套个 foreach 做一些初始化操作

    比如:

    • 通过身份证号码判断性别
    • 通过用户名查询账单信息
    • 给某个字段赋值
    • 对应导入的数据生成其他的数据
    • ......

    基于以上的需要,重新修改后的调用代码如下:

    public ICollection<TestDto> ExcelImport(IFormFile file)
    {
        var config = new ExcelImportOption<TestDto>()
        .Add("姓名", item => item.Name)
        .Add("年龄", item => item.Age, item => int.Parse(item))
        .Default(item => item.Height, 233)
        .AddInit(item =>
        {
            item.Name += "hhhhhhhh";
            item.Gender = false;
            return item;
        });
        ICollection<TestDto> result = ExcelOperation.ExcelToEntity(file.OpenReadStream(), config);
    
        return result;
    }
    

    代码/设计/想法

    由于我想在解析 excel 的同时进行初始化操作,所以委托这东西必不可少

    Func<T, T> Init { get; set; }
    

    由于现阶段的需求比较简单,不需要什么复杂的参数,所以使用 Func<>Action<> 都可以

    定义这个初始化 Init 之后,单纯的 ICollection<ExcelCellOption<T>> 已经是不够用了

    所以重新定义了一个 配置

    public class ExcelOption<T>
    {
        public ICollection<ExcelCellOption<T>> FieldOption { get; set; } = new List<ExcelCellOption<T>>();
        public ICollection<ExcelCellOption<T>> DefaultOption { get; set; } = new List<ExcelCellOption<T>>();
        public Func<T, T> Init { get; set; }
    }
    

    其中的 DefaultOption 没有也行

    然后对 ExcelOption<T> 进行扩展

    
    public static class ExcelOptionExt
    {
    
        ......
    
        public static ExcelOption<T> AddInit<T>(this ExcelOption<T> origin, Func<T, T> action = null)
        {
            if (origin.Init == null) origin.Init = action;
            return origin;
        }
        // 没有 DefaultOption 的情况下使用 FieldOption 也行
        public static ExcelOption<T> Default<T, E>(this ExcelOption<T> origin, Expression<Func<T, E>> prop, object defaultValue = null)
        {
            var member = prop.GetMember();
            if (origin.DefaultOption == null) origin.DefaultOption = new List<ExcelCellOption<T>>();
            origin.DefaultOption.Add(new ExcelCellOption<T>
            {
                PropName = member.Name,
                Prop = (PropertyInfo)member,
                ExcelField = string.Empty,
                Action = item => defaultValue
            });
            return origin;
        }
    
        ......
    }
    

    配置 接口改变之后,ExcelOperationExcelToEntity 方法也要进行修改

    
    public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ExcelOption<T> options)
    {
        using ExcelPackage pack = new ExcelPackage(excelStream);
        // 合并 FieldOption 和 DefaultOption
        var propOptions = options.FieldOption.Concat(options.DefaultOption);
    
        var sheet = pack.Workbook.Worksheets[1];
        int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns;
        // 获取对应设置的 表头 以及其 column
        var header = sheet.Cells[1, 1, 1, sheet.Dimension.Columns]
        .Where(item => propOptions.Any(opt => opt.ExcelField == item.Value?.ToString().Trim()))
        .ToDictionary(item => item.Value?.ToString().Trim(), item => item.End.Column);
        List<T> data = new List<T>();
        // 将excel 的数据转换为 对应实体
        for (int r = 2; r <= rowCount; r++)
        {
            // 将单行数据转换为 表头:数据 的键值对
            var rowData = sheet.Cells[r, 1, r, colCount]
            .Where(item => header.Any(title => title.Value == item.End.Column))
            .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString().Trim()))
            .ToDictionary(item => item.Key, item => item.Value);
            var obj = Activator.CreateInstance(typeof(T));
            // 根据对应传入的设置 为obj赋值
            foreach (var option in propOptions)
            {
                if (!string.IsNullOrEmpty(option.ExcelField))
                {
                    var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty;
                    if (!string.IsNullOrEmpty(value))
                        option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value));
                }
                else
                    option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
            }
            // 实际上只是加了个 Init 操作
            if (options.Init != null)
                obj = options.Init((T)obj);
            data.Add((T)obj);
        }
        return data;
    }
    

    然后这个阶段就算是大功告成了!

    再贴一次使用时的代码

    public ICollection<TestDto> ExcelImport(IFormFile file)
    {
        var config = new ExcelImportOption<TestDto>()
        .Add("姓名", item => item.Name)
        .Add("年龄", item => item.Age, item => int.Parse(item))
        .Default(item => item.Height, 233)
        .AddInit(item =>
        {
            item.Name += "hhhhhhhh";
            item.Gender = false;
            return item;
        });
        ICollection<TestDto> result = ExcelOperation.ExcelToEntity(file.OpenReadStream(), config);
    
        return result;
    }
    

    完整代码

    
    public class ExcelOperation
    {
    
        public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ExcelOption<T> options)
        {
            using ExcelPackage pack = new ExcelPackage(excelStream);
            // 合并 FieldOption 和 DefaultOption
            var propOptions = options.FieldOption.Concat(options.DefaultOption);
    
            var sheet = pack.Workbook.Worksheets[1];
            int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns;
            // 获取对应设置的 表头 以及其 column
            var header = sheet.Cells[1, 1, 1, sheet.Dimension.Columns]
            .Where(item => propOptions.Any(opt => opt.ExcelField == item.Value?.ToString().Trim()))
            .ToDictionary(item => item.Value?.ToString().Trim(), item => item.End.Column);
            List<T> data = new List<T>();
            // 将excel 的数据转换为 对应实体
            for (int r = 2; r <= rowCount; r++)
            {
                // 将单行数据转换为 表头:数据 的键值对
                var rowData = sheet.Cells[r, 1, r, colCount]
                .Where(item => header.Any(title => title.Value == item.End.Column))
                .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString().Trim()))
                .ToDictionary(item => item.Key, item => item.Value);
                var obj = Activator.CreateInstance(typeof(T));
                // 根据对应传入的设置 为obj赋值
                foreach (var option in propOptions)
                {
                    if (!string.IsNullOrEmpty(option.ExcelField))
                    {
                        var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty;
                        if (!string.IsNullOrEmpty(value))
                            option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value));
                    }
                    else
                        option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
                }
                if (options.Init != null)
                    obj = options.Init((T)obj);
                data.Add((T)obj);
            }
            return data;
        }
    
        /// <summary>
        /// 将表格数据转换为指定的数据实体
        /// </summary>
        public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options)
        {
            using ExcelPackage pack = new ExcelPackage(excelStream);
            var sheet = pack.Workbook.Worksheets[1];
            int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns;
            // 获取对应设置的 表头 以及其 column
            var header = sheet.Cells[1, 1, 1, sheet.Dimension.Columns]
            .Where(item => options.Any(opt => opt.ExcelField == item.Value?.ToString().Trim()))
            .ToDictionary(item => item.Value?.ToString().Trim(), item => item.End.Column);
            List<T> data = new List<T>();
            // 将excel 的数据转换为 对应实体
            for (int r = 2; r <= rowCount; r++)
            {
                // 将单行数据转换为 表头:数据 的键值对
                var rowData = sheet.Cells[r, 1, r, colCount]
                .Where(item => header.Any(title => title.Value == item.End.Column))
                .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString().Trim()))
                .ToDictionary(item => item.Key, item => item.Value);
                var obj = Activator.CreateInstance(typeof(T));
                // 根据对应传入的设置 为obj赋值
                foreach (var option in options)
                {
                    if (!string.IsNullOrEmpty(option.ExcelField))
                    {
                        var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty;
                        if (!string.IsNullOrEmpty(value))
                            option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value));
                    }
                    else
                        option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
                }
                data.Add((T)obj);
    
            }
            return data;
        }
    }
    
    public class ExcelOption<T>
    {
        public ICollection<ExcelCellOption<T>> FieldOption { get; set; } = new List<ExcelCellOption<T>>();
        public ICollection<ExcelCellOption<T>> DefaultOption { get; set; } = new List<ExcelCellOption<T>>();
        public Func<T, T> Init { get; set; }
    }
    
    public class ExcelCellOption<T>
    {
        /// <summary>
        /// 对应excel中的header字段
        /// </summary>
        public string ExcelField { get; set; }
        /// <summary>
        /// 对应字段的属性(实际上包含PropName)
        /// </summary>
        public PropertyInfo Prop { get; set; }
        /// <summary>
        /// 就是一个看起来比较方便的标识
        /// </summary>
        public string PropName { get; set; }
        /// <summary>
        /// 转换 表格 数据的方法 (现在是个鸡肋了)
        /// </summary>
        public Func<string, object> Action { get; set; }
        public static ICollection<ExcelCellOption<T>> GenExcelOption<E>(string field, Expression<Func<T, E>> prop, Func<string, object> action = null)
        {
            var member = prop.GetMember();
            return new List<ExcelCellOption<T>>{
                new ExcelCellOption<T>
                {
                    PropName = member.Name,
                    Prop = (PropertyInfo)member,
                    ExcelField = field,
                    Action = action
                }
            };
        }
    }
    
    public static class ExcelOptionExt
    {
        public static ICollection<ExcelCellOption<T>> Add<T, E>(this ICollection<ExcelCellOption<T>> origin, string field, Expression<Func<T, E>> prop, Func<string, object> action = null)
        {
            var member = prop.GetMember();
            origin.Add(new ExcelCellOption<T>
            {
                PropName = member.Name,
                Prop = (PropertyInfo)member,
                ExcelField = field,
                Action = action
            });
            return origin;
        }
    
        public static ExcelOption<T> Add<T, E>(this ExcelOption<T> origin, string field, Expression<Func<T, E>> prop, Func<string, object> action = null)
        {
            var member = prop.GetMember();
            if (origin.FieldOption == null) origin.FieldOption = new List<ExcelCellOption<T>>();
            origin.FieldOption.Add(new ExcelCellOption<T>
            {
                PropName = member.Name,
                Prop = (PropertyInfo)member,
                ExcelField = field,
                Action = action
            });
            return origin;
        }
        public static ExcelOption<T> Default<T, E>(this ExcelOption<T> origin, Expression<Func<T, E>> prop, object defaultValue = null)
        {
            var member = prop.GetMember();
            if (origin.DefaultOption == null) origin.DefaultOption = new List<ExcelCellOption<T>>();
            origin.DefaultOption.Add(new ExcelCellOption<T>
            {
                PropName = member.Name,
                Prop = (PropertyInfo)member,
                ExcelField = string.Empty,
                Action = item => defaultValue
            });
            return origin;
        }
        public static ExcelOption<T> AddInit<T>(this ExcelOption<T> origin, Func<T, T> action = null)
        {
            if (origin.Init == null) origin.Init = action;
            return origin;
        }
    }
    
    

    未完待续

  • 相关阅读:
    Python动态展示遗传算法求解TSP旅行商问题
    MOEAD算法中均匀权向量的实现---Python
    HDU 5294 多校第一场1007题 最短路+最小割
    POJ 3261 Milk Patterns sa+二分
    HDU 4292 FOOD 2012 ACM/ICPC Asia Regional Chengdu Online
    CodeForces 201A Clear Symmetry
    POJ 1679 The Unique MST 确定MST是否唯一
    POJ 3268 Silver Cow Party 最短路 基础题
    POJ 2139 SIx Degrees of Cowvin Bacon 最短路 水題
    POJ2229 Sumsets 基礎DP
  • 原文地址:https://www.cnblogs.com/CollapseNav/p/14683298.html
Copyright © 2011-2022 走看看