使用 EPPlus 封装的 excel 表格导入功能

前言

最近做系统的时候有很多 excel导入 的功能,以前我前后端都做的时候是在前端解析,然后再做个批量插入的接口

我觉着这样挺好的,后端部分可以做的很简单(很偷懒的)

但是因为各种各样的原因,最终还是需要做个专门的 excel导入 接口

遇到的问题

由于之前从来没有在后端部分处理过表格,所以我选择看一下同事的代码是怎么写的

虽然我之前没写过相关的业务,但是直觉的认为这样写非常麻烦,那个 ExcelHelper 好像也没干什么事,我希望一套操作下来可以把 excel 转成能够直接传入 AddRange 进行批量新增的实体集合

所以我就决定自己封装。

最终代码

结果展示(略)

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

最终可以直接生成"初始化"数据的 result

代码/设计/想法

我希望使用的时候通过传入 表格字段数据实体.属性关系集合

实现解析表格的同时生成对应的 实体对象

然后我对上述 关系 的定义如下

  1. public class ExcelCellOption<T>
  2. {
  3. /// <summary>
  4. /// 对应excel中的header表头(title)
  5. /// </summary>
  6. public string ExcelField { get; set; }
  7. /// <summary>
  8. /// 对应字段的属性(实际上包含PropName)
  9. /// </summary>
  10. public PropertyInfo Prop { get; set; }
  11. /// <summary>
  12. /// 就是一个看起来比较方便的标识
  13. /// </summary>
  14. public string PropName { get; set; }
  15. /// <summary>
  16. /// 转换 表格 数据的方法(委托)
  17. /// </summary>
  18. public Func<string, object> Action { get; set; }
  19. }

之后给他加了个静态方法 GenExcelOption<E> 生成关系集合 ICollection<ExcelCellOption<T>>

  1. public static ICollection<ExcelCellOption<T>> GenExcelOption<E>(string field,
  2. Expression<Func<T, E>> prop, Func<string, object> action = null)
  3. {
  4. var member = prop.GetMember();
  5. return new List<ExcelCellOption<T>>{
  6. new ExcelCellOption<T>
  7. {
  8. PropName = member.Name,
  9. Prop = (PropertyInfo)member,
  10. ExcelField = field,
  11. Action = action
  12. }
  13. };
  14. }

为了方便之后加新的配置项

给返回类型 ICollection<ExcelCellOption<T>> 搞个扩展方法 Add

  1. public static class ExcelOptionExt
  2. {
  3. public static ICollection<ExcelCellOption<T>> Add<T, E>(this ICollection<ExcelCellOption<T>> origin,
  4. string field, Expression<Func<T, E>> prop, Func<string, object> action = null)
  5. {
  6. var member = prop.GetMember();
  7. origin.Add(new ExcelCellOption<T>
  8. {
  9. PropName = member.Name,
  10. Prop = (PropertyInfo)member,
  11. ExcelField = field,
  12. Action = action
  13. });
  14. return origin;
  15. }
  16. }

使用的时候就可以根据excel表格生成对应的 关系集合 (配置)

  1. var config = ExcelCellOption<TestDto>
  2. .GenExcelOption("姓名", item => item.Name)
  3. .Add("年龄", item => item.Age, item => int.Parse(item))
  4. .Add("性别", item => item.Gender, item => item == "男")
  5. .Add("身高", item => item.Height, item => double.Parse(item));

有了配置之后需要根据配置解析excel生成数据实体了

写了个方法如下

  1. public class ExcelOperation
  2. {
  3. /// <summary>
  4. /// 将表格数据转换为指定的数据实体
  5. /// </summary>
  6. public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options)
  7. {
  8. using ExcelPackage pack = new(excelStream);
  9. var sheet = pack.Workbook.Worksheets[1];
  10. int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns;
  11. // 获取对应设置的 表头 以及其 column下标
  12. var header = sheet.Cells[1, 1, 1, colCount ]
  13. .Where(item => options.Any(opt => opt.ExcelField == item.Value?.ToString().Trim()))
  14. .ToDictionary(item => item.Value?.ToString().Trim(), item => item.End.Column);
  15. List<T> data = new();
  16. // 将excel 的数据转换为 对应实体
  17. for (int r = 2; r <= rowCount; r++)
  18. {
  19. // 将单行数据转换为 表头:数据 的键值对
  20. var rowData = sheet.Cells[r, 1, r, colCount]
  21. .Where(item => header.Any(title => title.Value == item.End.Column))
  22. .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString().Trim()))
  23. .ToDictionary(item => item.Key, item => item.Value);
  24. var obj = Activator.CreateInstance(typeof(T));
  25. // 根据对应传入的设置 为obj赋值
  26. foreach (var option in options)
  27. {
  28. if (!string.IsNullOrEmpty(option.ExcelField))
  29. {
  30. var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty;
  31. if (!string.IsNullOrEmpty(value))
  32. option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value));
  33. }
  34. // 可以用来初始化与表格无关的字段 如 创建时间 Guid主键 之类的东西
  35. else
  36. option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
  37. }
  38. data.Add((T)obj);
  39. }
  40. return data;
  41. }
  42. }

最终调用

  1. ExcelOperation.ExcelToEntity(file.OpenReadStream(), config)

传入文件流和配置集合即可

完整代码

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using AutoMapper.Internal;
  8. using OfficeOpenXml;
  9. namespace XXX.XXX.XXX.XXX
  10. {
  11. public class ExcelOperation
  12. {
  13. /// <summary>
  14. /// 将表格数据转换为指定的数据实体
  15. /// </summary>
  16. public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options)
  17. {
  18. using ExcelPackage pack = new(excelStream);
  19. var sheet = pack.Workbook.Worksheets[1];
  20. int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns;
  21. // 获取对应设置的 表头 以及其 column
  22. var header = sheet.Cells[1, 1, 1, sheet.Dimension.Columns]
  23. .Where(item => options.Any(opt => opt.ExcelField == item.Value.ToString()))
  24. .ToDictionary(item => item.Value.ToString(), item => item.End.Column);
  25. List<T> data = new();
  26. // 将excel 的数据转换为 对应实体F
  27. for (int r = 2; r <= rowCount; r++)
  28. {
  29. // 将单行数据转换为 表头:数据 的键值对
  30. var rowData = sheet.Cells[r, 1, r, colCount]
  31. .Where(item => header.Any(title => title.Value == item.End.Column))
  32. .Select(item => new KeyValuePair<string, string>(header.First(title => title.Value == item.End.Column).Key, item.Value?.ToString()))
  33. .ToDictionary(item => item.Key, item => item.Value);
  34. var obj = Activator.CreateInstance(typeof(T));
  35. // 根据对应传入的设置 为obj赋值
  36. foreach (var option in options)
  37. {
  38. if (!string.IsNullOrEmpty(option.ExcelField))
  39. {
  40. var value = rowData.ContainsKey(option.ExcelField) ? rowData[option.ExcelField] : string.Empty;
  41. if (!string.IsNullOrEmpty(value))
  42. option.Prop.SetValue(obj, option.Action == null ? value : option.Action(value));
  43. }
  44. // 可以用来初始化与表格无关的字段 如 创建时间 Guid主键 之类的东西
  45. else
  46. option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
  47. }
  48. data.Add((T)obj);
  49. }
  50. return data;
  51. }
  52. }
  53. public class ExcelCellOption<T>
  54. {
  55. /// <summary>
  56. /// 对应excel中的header字段
  57. /// </summary>
  58. public string ExcelField { get; set; }
  59. /// <summary>
  60. /// 对应字段的属性(实际上包含PropName)
  61. /// </summary>
  62. public PropertyInfo Prop { get; set; }
  63. /// <summary>
  64. /// 就是一个看起来比较方便的标识
  65. /// </summary>
  66. public string PropName { get; set; }
  67. /// <summary>
  68. /// 转换 表格 数据的方法
  69. /// </summary>
  70. public Func<string, object> Action { get; set; }
  71. public static ICollection<ExcelCellOption<T>> GenExcelOption<E>(string field, Expression<Func<T, E>> prop, Func<string, object> action = null)
  72. {
  73. var member = prop.GetMember();
  74. return new List<ExcelCellOption<T>>{
  75. new ExcelCellOption<T>
  76. {
  77. PropName = member.Name,
  78. Prop = (PropertyInfo)member,
  79. ExcelField = field,
  80. Action = action
  81. }
  82. };
  83. }
  84. }
  85. public static class ExcelOptionAdd
  86. {
  87. 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)
  88. {
  89. var member = prop.GetMember();
  90. origin.Add(new ExcelCellOption<T>
  91. {
  92. PropName = member.Name,
  93. Prop = (PropertyInfo)member,
  94. ExcelField = field,
  95. Action = action
  96. });
  97. return origin;
  98. }
  99. }
  100. }

其实这已经是旧版本了

新的版本过几天大概会发

未完待续

使用 EPPlus 封装的 excel 表格导入功能 (.net core c#)的更多相关文章

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

    使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神 前言 接上一篇 使用 EPPlus 封装的 excel 表格导入功能 (一) 前一篇的是大概能用但是 ...

  2. WEB下的excel批量导入功能

    新手学习中,记录一下excel导出功能实现的整个流程.使用框架ssm. control层 importExcel+parseDataItem: @RequestMapping("import ...

  3. java实现excel表格导入数据库表

    导入excel就是一个上传excel文件,然后获取excel文件数据,然后处理数据并插入到数据库的过程 一.上传excel 前端jsp页面,我的是index.jsp 在页面中我自己加入了一个下载上传文 ...

  4. 从Excel表格导入数据到数据库

    数据库:SQL 1.小数据直接粘贴 2.用导入向导 3.用SSIS包 4.用SQL语句 现在详细说一下第4种方法,以.xlsx文件为例 .xlsx文件需要用provider“Microsoft.ACE ...

  5. Excel表格导入Mysql数据库,一行存入多条数据的前后台完整实现思路(使用mybatis框架)

    现在有一张Excel表格: 存入数据库时需要这样存放: 现在需要将Excel表格做处理,将每一行拆分成多条数据存入数据库. 1.首先在前台jsp页面画一个按钮:,加入点击事件: <td styl ...

  6. 使用Excel表格导入数据到Oracle表

    在工作中我们会遇到将通过数据手动录入到系统中的需求,如果数据量比较小,那么手动输入是可行的,倘若数据量很大,那么这些数据手动录入将会是一个很大的工作量,为了简化这个手动录入的操作流程,我们可以使用Ex ...

  7. 前端Excel表格导入导出,包括合并单元格,表格自定义样式等

    表格数据导入 读取导入Excel表格数据这里采用的是 xlsx 插件 npm i xlsx 读取excel需要通过 XLSX.read(data, {type: type}) 方法来实现,返回一个叫W ...

  8. C#解决从含身份证号码的Excel表格导入数据库的问题

    用C#做从Excel表导入SQL数据库时发现从EXCEL导入的身份证号码会变成科学表示方法. 解决这个问题是比较容易的,首先,打开电子表格,选中“身份证号码”一列,右键选择“设置单元格格式”,进入单元 ...

  9. Python脚本:实现excel表格导入到数据库,支持mysql,postgresql,MongoDB

    import xlrd,re from datetime import datetime from xlrd import xldate_as_tuple # 判断上传表格是否与模板要求一致 def ...

随机推荐

  1. js 的 ArrayBuffer 和 dataView

    arrayBuffer文档 一个十六进制代表4位,0xF = 1111,0xFF = 1111 1111,八位是1字节,所以通常用两个16进制代表1字节. 假如我申请一个8字节的内存空间,然后初始化为 ...

  2. Flutter Demo: PageView横向使用

    video import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends ...

  3. Vue学习笔记-Vue.js-2.X 学习(二)===>组件化开发

    ===重点重点开始 ========================== (三) 组件化开发 1.创建组件构造器: Vue.extends() 2.注册组件: Vue.component() 3.使用 ...

  4. 微信小程序:Navigator导航组件

    导航组件:类似超链接标签. url:要跳转的页面路径,可以放绝对路径,也可以放相对路径,绝对路径指从pages作为根目录开始找到你要的页面. 找到你要找的页面的相对地址的方法:在vscode中,该页面 ...

  5. 读懂框架设计的灵魂—Java反射机制

    尽人事,听天命.博主东南大学硕士在读,热爱健身和篮球,乐于分享技术相关的所见所得,关注公众号 @ 飞天小牛肉,第一时间获取文章更新,成长的路上我们一起进步 本文已收录于 CS-Wiki(Gitee 官 ...

  6. 基于docker快速搭建hbase集群

    一.概述 HBase是一个分布式的.面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文"Bigtable:一个结构化数据的分布式存储系统".就像Bigt ...

  7. Java(JDK/Tomcat/Maven)运行环境配置及工具(idea/eclipse)安装

    Java (计算机编程语言) Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征. Java语 ...

  8. 医学图像 | DualGAN与儿科超声心动图分割 | MICCAI

    文章转自微信公众号:「机器学习炼丹术」 作者:炼丹兄(已授权) 联系方式:微信cyx645016617(欢迎交流共同进步) 论文名称:"Dual Network Generative Adv ...

  9. 剑指 Offer 29. 顺时针打印矩阵 + 蛇形矩阵 + 模拟 + 思维题

    剑指 Offer 29. 顺时针打印矩阵 Offer_29 题目描述: 题解分析: 题目的初衷是将这道题当做一个简单题处理 这道题一开始想的太复杂了,其实可以参考迷宫广度优先搜索的过程,只不过在选定一 ...

  10. docker apollo配置中心分布式部署

    Apollo 简介 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服 ...