使用 EPPlus 封装的 excel 表格导入功能 (.net core c#)
使用 EPPlus 封装的 excel 表格导入功能
前言
最近做系统的时候有很多 excel导入 的功能,以前我前后端都做的时候是在前端解析,然后再做个批量插入的接口
我觉着这样挺好的,后端部分可以做的很简单(很偷懒的)
但是因为各种各样的原因,最终还是需要做个专门的 excel导入 接口
遇到的问题
由于之前从来没有在后端部分处理过表格,所以我选择看一下同事的代码是怎么写的
虽然我之前没写过相关的业务,但是直觉的认为这样写非常麻烦,那个 ExcelHelper
好像也没干什么事,我希望一套操作下来可以把 excel 转成能够直接传入 AddRange
进行批量新增的实体集合
所以我就决定自己封装。
结果展示(略)
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;
}
最终可以直接生成"初始化"数据的 result
代码/设计/想法
我希望使用的时候通过传入 表格字段
与 数据实体.属性
的关系集合
实现解析表格的同时生成对应的 实体对象
然后我对上述 关系 的定义如下
public class ExcelCellOption<T>
{
/// <summary>
/// 对应excel中的header表头(title)
/// </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; }
}
之后给他加了个静态方法 GenExcelOption<E>
生成关系集合 ICollection<ExcelCellOption<T>>
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
}
};
}
为了方便之后加新的配置项
给返回类型 ICollection<ExcelCellOption<T>>
搞个扩展方法 Add
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;
}
}
使用的时候就可以根据excel表格生成对应的 关系集合 (配置)
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));
有了配置之后需要根据配置解析excel生成数据实体了
写了个方法如下
public class ExcelOperation
{
/// <summary>
/// 将表格数据转换为指定的数据实体
/// </summary>
public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options)
{
using ExcelPackage pack = new(excelStream);
var sheet = pack.Workbook.Worksheets[1];
int rowCount = sheet.Dimension.Rows, colCount = sheet.Dimension.Columns;
// 获取对应设置的 表头 以及其 column下标
var header = sheet.Cells[1, 1, 1, colCount ]
.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();
// 将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));
}
// 可以用来初始化与表格无关的字段 如 创建时间 Guid主键 之类的东西
else
option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
}
data.Add((T)obj);
}
return data;
}
}
最终调用
ExcelOperation.ExcelToEntity(file.OpenReadStream(), config)
传入文件流和配置集合即可
完整代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using AutoMapper.Internal;
using OfficeOpenXml;
namespace XXX.XXX.XXX.XXX
{
public class ExcelOperation
{
/// <summary>
/// 将表格数据转换为指定的数据实体
/// </summary>
public static ICollection<T> ExcelToEntity<T>(Stream excelStream, ICollection<ExcelCellOption<T>> options)
{
using ExcelPackage pack = new(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()))
.ToDictionary(item => item.Value.ToString(), item => item.End.Column);
List<T> data = new();
// 将excel 的数据转换为 对应实体F
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()))
.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));
}
// 可以用来初始化与表格无关的字段 如 创建时间 Guid主键 之类的东西
else
option.Prop.SetValue(obj, option.Action == null ? null : option.Action(string.Empty));
}
data.Add((T)obj);
}
return data;
}
}
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 ExcelOptionAdd
{
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;
}
}
}
其实这已经是旧版本了
新的版本过几天大概会发
未完待续
使用 EPPlus 封装的 excel 表格导入功能 (.net core c#)的更多相关文章
- 使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神
使用 EPPlus 封装的 excel 表格导入功能 (二) delegate 委托 --永远滴神 前言 接上一篇 使用 EPPlus 封装的 excel 表格导入功能 (一) 前一篇的是大概能用但是 ...
- WEB下的excel批量导入功能
新手学习中,记录一下excel导出功能实现的整个流程.使用框架ssm. control层 importExcel+parseDataItem: @RequestMapping("import ...
- java实现excel表格导入数据库表
导入excel就是一个上传excel文件,然后获取excel文件数据,然后处理数据并插入到数据库的过程 一.上传excel 前端jsp页面,我的是index.jsp 在页面中我自己加入了一个下载上传文 ...
- 从Excel表格导入数据到数据库
数据库:SQL 1.小数据直接粘贴 2.用导入向导 3.用SSIS包 4.用SQL语句 现在详细说一下第4种方法,以.xlsx文件为例 .xlsx文件需要用provider“Microsoft.ACE ...
- Excel表格导入Mysql数据库,一行存入多条数据的前后台完整实现思路(使用mybatis框架)
现在有一张Excel表格: 存入数据库时需要这样存放: 现在需要将Excel表格做处理,将每一行拆分成多条数据存入数据库. 1.首先在前台jsp页面画一个按钮:,加入点击事件: <td styl ...
- 使用Excel表格导入数据到Oracle表
在工作中我们会遇到将通过数据手动录入到系统中的需求,如果数据量比较小,那么手动输入是可行的,倘若数据量很大,那么这些数据手动录入将会是一个很大的工作量,为了简化这个手动录入的操作流程,我们可以使用Ex ...
- 前端Excel表格导入导出,包括合并单元格,表格自定义样式等
表格数据导入 读取导入Excel表格数据这里采用的是 xlsx 插件 npm i xlsx 读取excel需要通过 XLSX.read(data, {type: type}) 方法来实现,返回一个叫W ...
- C#解决从含身份证号码的Excel表格导入数据库的问题
用C#做从Excel表导入SQL数据库时发现从EXCEL导入的身份证号码会变成科学表示方法. 解决这个问题是比较容易的,首先,打开电子表格,选中“身份证号码”一列,右键选择“设置单元格格式”,进入单元 ...
- Python脚本:实现excel表格导入到数据库,支持mysql,postgresql,MongoDB
import xlrd,re from datetime import datetime from xlrd import xldate_as_tuple # 判断上传表格是否与模板要求一致 def ...
随机推荐
- qt 获取窗口句柄的线程id和进程id GetWindowThreadProcessId
int lpdwProcessId; int id = GetWindowThreadProcessId((HWND)0x707d6, (LPDWORD)&lpdwProcessId); qD ...
- Techme Inc热心公益事业 积极开展公益活动
从2015年起,Techme inc(公司编号:20151524696)便通过优质的产品和服务,帮助顾客实现营养与健康的目标.与此同时,Techme inc(公司编号:20151524696)多年来始 ...
- iOS拍个小视频
需求 公司混合开发,uni端拍小视频不是很理想,为达到仿微信效果,原生插件走起 思路 第1步:1个AVCaptureSession, 1块AVCaptureVideoPreviewLayer[考虑兼容 ...
- JS判断年份是否为闰年
//闰年能被4整除且不能被100整除,或能被400整除.function year(){ if(year%4==0&&year%100!=0||year%400==0){ ...
- HashMap是如何进行扩容的?
HashMap通过resize()方法进行扩容. 源码解析: resize()函数有两种使用情况: 一.当table数组为null时初始化hash表. 二.当table数组不为null时进行扩容. 1 ...
- Oracle数据库在给表添加字段的sql中用comment报错
原因:不同于mysql,Oracle数据库在添加表字段时不能直接用comment,而是单独写一个sql语句,如下: alter table SYS_USER add SENDMSG_LASTTIME ...
- Java常用类:Scanner类
一.简介 java.util.Scanner是Java5的新特征,我们可以通过Scanner类来获取用户的输入. 二.创建对象 示例: Scanner scanner = new Scanner(Sy ...
- (数据科学学习手札109)Python+Dash快速web应用开发——静态部件篇(中)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- 2.5w字 + 36 张图爆肝操作系统面试题,太牛逼了!
欢迎各位大佬访问我的 github ,跪求 star bestJavaer 大家好,我是 cxuan,我之前汇总了一下关于操作系统的面试题,最近又重新翻阅了一下发现不是很全,现在也到了面试季了,所以我 ...
- LeetCode113. 路径总和 II
原题链接 1 class Solution: 2 def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]: 3 ans,tm ...