• EPPlus扩展封装


      开发过程中难免会遇到读取Excel的上百个title所有列的数据,而这种我们可以采用简单除暴的方式,直接通过Epplus取Sheet的行和列的位置,但是这种实现可读性非常差。

    针对这种情况,我通过可配置Mapping的方式实现,通过Excel的Title与Entity对象做个映射读取到DataTable,然后操作DataTable已读取好的Excel数据。

    以下实现支持Excel的Title多行合并配置

    1、首先定义接口类

        public interface IProcessExcel
        {
            ProcessExcel SetWorksheetIndex(int positionId);
            DataTable Execute(ExcelPackage excelPackage);
            Task<dynamic> ExcelLoadProcess(IFormFile formFile, Func<ExcelPackage, IProcessExcel, Task<dynamic>> func, CancellationToken cancellationToken);
            void SetProperty<T>(T entity, DataRow dataRow, string prefix = "") where T : class;
        }

    2、继承IProcessExcel 实现抽象接口的对应方法

     public class ProcessExcel : IProcessExcel
        {
            private int PositionId { get; set; }
            private int FromRow { get; set; }
            private int FromCol { get; set; }
            private int ToRow { get; set; }
            private bool IsOffset { get; set; }
            private int StartFromRow { get; set; }
            private ConcurrentDictionary<string, string> FieldsMapping { get; set; } = new ConcurrentDictionary<string, string>();
            private string SheetName { get; set; }
    
            public ProcessExcel SetWorksheetIndex(int positionId)
            {
                PositionId = positionId;
                return this;
            }
    
            public ProcessExcel SetExcelRange(int fromRow, int fromCol, int toRow)
            {
                FromRow = fromRow;
                FromCol = fromCol;
                ToRow = toRow;
                return this;
            }
    
            public ProcessExcel SetExcelRange(int startFromRow)
            {
                StartFromRow = startFromRow;
                return this;
            }
    
            public ProcessExcel SetOffset(bool isOffset)
            {
                IsOffset = isOffset;
                return this;
            }
    
            public ProcessExcel SetMapping(ConcurrentDictionary<string, string> fieldsMapping)
            {
                FieldsMapping = fieldsMapping;
                return this;
            }
    
            public ProcessExcel SetSheetName(string sheetName)
            {
                SheetName = sheetName;
                return this;
            }
    
            public async Task<dynamic> ExcelLoadProcess(IFormFile formFile, Func<ExcelPackage, IProcessExcel, Task<dynamic>> func, CancellationToken cancellationToken)
            {
                await using var stream = new MemoryStream();
                await formFile.CopyToAsync(stream, cancellationToken);
                using var package = new ExcelPackage(stream);
                return await func(package, this);
            }
    
            public DataTable Execute(ExcelPackage excelPackage)
            {
                var worksheet = excelPackage.Workbook.Worksheets[PositionId];
                if (!string.IsNullOrEmpty(SheetName))
                {
                    if (!worksheet.Name.Contains(SheetName)) throw new xxException($"未知的模板:{worksheet.Name},请检查!");
                }
                if (worksheet.Dimension == null) throw new xxException($"{worksheet.Name}没有数据");
    
                var column = worksheet.Dimension.End.Column;
                var rows = worksheet.Dimension.Rows;
    
                if (rows <= 0 || column <= 0) throw new xxException($"{worksheet.Name}没有数据");
    
                var dt = new DataTable(worksheet.Name);
                var headerName = string.Empty;
                foreach (var cell in worksheet.Cells[FromRow, FromCol, ToRow, column])
                {
                    if (IsOffset)
                    {
                        var headerValue = cell.Offset(cell.Rows - FromRow, cell.Columns - ToRow).Text;
                        if (!string.IsNullOrEmpty(headerValue))
                        {
                            headerName = headerValue.Trim();
                        }
                    }
    
                    var columnName = cell.Text.Trim();
                    columnName = string.IsNullOrEmpty(columnName) ? headerName : $"{headerName}-{columnName}";
    
                    if (FieldsMapping.Any() && FieldsMapping.TryGetValue(columnName, out var field) && !string.IsNullOrEmpty(field))
                    {
                        columnName = field.ToLower();
                    }
    
                    if (!dt.Columns.Contains(columnName) && !string.IsNullOrEmpty(columnName))
                    {
                        dt.Columns.Add(columnName);
                    }
                }
    
                for (var i = StartFromRow; i <= worksheet.Dimension.End.Row; i++)
                {
                    var row = worksheet.Cells[i, 1, i, column];
                    var newRow = dt.NewRow();
    
                    foreach (var cell in row)
                    {
                        if ((cell.Style.Numberformat.Format.IndexOf("mm-dd-yy", StringComparison.Ordinal) > -1 || cell.Style.Numberformat.Format.IndexOf("yyyy", StringComparison.Ordinal) > -1) && cell.Value != null)
                        {
                            newRow[cell.Start.Column - 1] = cell.GetValue<DateTime>();
                        }
                        else
                        {
                            newRow[cell.Start.Column - 1] = cell.Text;
                        }
                    }
    
                    dt.Rows.Add(newRow);
                }
    
                return dt;
            }

    3、实体字段映射关系,这里采用反射的方式处理的(如果考虑更高性能可以采用Expression表达式树的方式)

     public void SetProperty<T>(T entity, DataRow dataRow, string prefix = "") where T : class
            {
                var type = entity.GetType();
                foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    var attributeName = $"{prefix}{property.GetCustomAttribute<ColumnAttribute>()?.Name}".ToLower();
                    if (!FieldsMapping.Values.Contains(attributeName)) continue;
    
                    var value = dataRow[attributeName];
                    value = value is DBNull ? "" : value;
    
                    if (typeof(string) == property.PropertyType)
                    {
                        property.SetValue(entity, value, null);
                        continue;
                    }
    
                    if (typeof(bool) == property.PropertyType)
                    {
                        property.SetValue(entity, Equals(value, "1") || Equals(value, ""), null);
                    }
                }
            }
        }

    4、接口入参部分

     [HttpPost("import")]
            public async Task<dynamic> Import(IFormFile formFile, CancellationToken cancellationToken)
            {
                if (formFile == null || formFile.Length <= 0)
                {
                    return BadRequest("formfile is empty");
                }
    
                if (!Path.GetExtension(formFile.FileName).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
                {
                    return BadRequest("Not Support file extension");
                }
            }

    以上代码没有提供完整,仅提供部分核心代码仅供参考

  • 相关阅读:
    怎样写贪吃蛇小游戏?用100行python代码轻松解决!
    面试必问的celery,你了解多少?
    您的机器学习环保吗?一只AI训练排出180吨二氧化碳
    NLP技术应用到音乐领域,分分钟让你变成音乐大师!
    数据可视化“升级”修炼宝典
    一文掌握Python可视化库的两大王者
    多线程-模拟阻塞queue队列
    设计模式-单例模式
    多线程之wait,notify,volatile,synchronized,sleep
    spring与quartz整合
  • 原文地址:https://www.cnblogs.com/sunxuchu/p/15910974.html
Copyright © 2020-2023  润新知