C#基于Npoi通过特性的方式导出简单数据到Excel或基于特性以及基于Excel模板导出数据到Excel以及从Excel中把数据导入到对象中
导出数据到Excel表格以及从Excel表格中读取数据是我们日常开发很多情况都会遇到的,这里或许只是导出一些简单的数据到excel,这里或许会按照一定的模板导出数据到excel,这里也可能需要从Excel中读取数据。为了避免重复性的劳动,这里本人结合开发中遇到情况,在基于Npoi操作Excel的情况进一步对Excel的操作进行封装,旨在更方便的开发,开箱即用,只需要短短几行代码即可实现。如果您需要使用这个包,可以在NuGet上搜索OpenDeepSpace.Npoi进行使用。
本人采用基于特性,以及基于Excel模板的方式实现了:
1.无模板数据导出到Excel
2.基于模板导出数据到Excel
3.从Excel读取数据
以下我将通过代码的形式来告诉你该如何使用他。由于以下所有的案列都是基于同一个输出对象。
首先将为大家介绍ExcelColumn特性的使用。如果某一个类的某些数据需要导出到Excel中,你就需要在类上打上ExcelColumn特性。
ExcelColumn特性有两个参数可以进行设置。
参数名 | 含义 |
---|---|
colName | 列名(输出到Excel中的列名) |
colOrder | 列顺序(该列在Excel中顺序) |
源码见github:OpenDeepSpace.Npoi
例如下面这个输出对象 本文所有导出到Excel的数据都采用该对象
/// <summary>/// 泛指ExcelData数据输出对象/// </summary>public class ExcelDataOutDto{[ExcelColumn("唯一标识",1)]//通过ExcelColumn特性指定为需要输出到Excel的列,参数分别为列名,列排序/// <summary>/// Id/// </summary>public string Id { get; set; }[ExcelColumn("姓名", 2)]/// <summary>/// 姓名/// </summary>public string Name { get; set; }[ExcelColumn("年龄", 3)]/// <summary>/// 年龄/// </summary>public int Age { get; set; }[ExcelColumn("出生日期",4)]/// <summary>/// 出生日期/// </summary>public DateTime BirthDate { get; set; }/// <summary>/// 其他信息/// </summary>public string OtherInfo { get; set; }}
这是我定义的一些初始数据
List<ExcelDataOutDto> excelDataOutDtos = new List<ExcelDataOutDto>() {new ExcelDataOutDto(){Id=Guid.NewGuid().ToString(),Name="小张",Age=20,BirthDate=DateTime.Today.AddYears(-20),OtherInfo="我是小张,我不嚣张"},new ExcelDataOutDto(){Id=Guid.NewGuid().ToString(),Name="小李",Age=24,BirthDate=DateTime.Today.AddYears(-24),OtherInfo="面对疾风吧"},new ExcelDataOutDto(){Id=Guid.NewGuid().ToString(),Name="小吴",Age=27,BirthDate=DateTime.Today.AddYears(-27),OtherInfo="哈哈哈笑而不语"},};
无模板导出数据到Excel
无模板导出数据到指定路径
这里你只需简单的两行代码即可完成最简单数据导出到Excel
ExcelHandler excelHandler = new ExcelHandler();//构造一个ExcelHandler处理对象
excelHandler.exportObjectToExcel($@"D:\excelexport\{Guid.NewGuid().ToString("N")}.xlsx", excelDataOutDtos);//导出数据
导出的结果以及说明如下:
如果你不需要序号以及需要设置导出的日期格式
excelHandler.setIsSetOrder(false);//不设置序列号
excelHandler.getExcelDatePattern().setDatePattern("yyyy/MM/dd");//指定日期的格式化模式
如果需要进一步筛选需要导出的字段,即打了ExcelColumn特性的列不需要全部导出,可以加入如下代码:
//指定导出列 默认只要写了ExcelColumn特性的都会导出,这里可以对ExcelColumn进行进一步筛选List<string> colNames = new List<string>();colNames.Add("姓名");colNames.Add("出生日期");ExcelHandler excelHandler = new ExcelHandler();excelHandler.exportObjectToExcel($@"D:\excelexport\{Guid.NewGuid().ToString("N")}.xlsx", excelDataOutDtos,colNames);
无模板导出到流
ExcelHandler excelHandler = new ExcelHandler();NpoiMemoryStream npoiMemoryStream=new NpoiMemoryStream();excelHandler.exportObjectToExcel(npoiMemoryStream, excelDataOutDtos);npoiMemoryStream.Seek(0, SeekOrigin.Begin);return File(npoiMemoryStream, "application/stream", $"{Guid.NewGuid()}.xlsx");
根据模板导出到Excel
Excel模板的制作需要的一些规则:
Excel模板中的占位符 | 含义 |
---|---|
datas | 填在Excel的单元格表示数据开始位置 |
styles | 填在Excel的单元格表示该列所有单元格的样式 |
defaultStyles | 填在Excel的单元格表示单元格的默认样式 |
# | 以#号开头紧接着包含英文 表示非规则的信息填充 一般用在头部或底部 例如#datetime |
order | 填在excel单元格中 指定序号占位符 可以以此来自定义序号列的名称 |
例如如下三个模板:
无头部底部模板:
有头部底部的模板:
有头部底部带序号的模板
模板不包含头部底部信息的导出
模板如下:
存在空列这里如果不设置空列数将整体先前移动,即会自动移动到A列开始
根据模板文件导出不包含头部底部信息到指定路径
ExcelHandler excelHandler = new ExcelHandler();
excelHandler.getExcelTemplate().setExcelColNums(4);//设置excel的列数
excelHandler.getExcelTemplate().setDataStartColNum(2);//设置数据开始列
excelHandler.exportObjectToExcelByTemplate(Path.Combine(@"ExcelTemplates/导出的数据模板无头部底部.xlsx"), $@"D:\excelexporttemplate\指定路径模板{Guid.NewGuid().ToString("N")}.xlsx", excelDataOutDtos);//Path.Combine表示模板文件是放在工程启动项目所在文件夹下面
根据模板文件导出不包含头部底部信息到流
ExcelHandler excelHandler = new ExcelHandler();
excelHandler.getExcelTemplate().setExcelColNums(4 );//设置excel的列数
//导出到流文件
NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream(); excelHandler.exportObjectToExcelByTemplate(Path.Combine(@"ExcelTemplates/导出的数据模板无头部底部.xlsx"), npoiMemoryStream, excelDataOutDtos);
npoiMemoryStream.Seek(0, SeekOrigin.Begin);
return File(npoiMemoryStream, "application/stream", $"模板流文件无头部底部{Guid.NewGuid()}.xlsx");
根据模板文件流导出不包含头部底部信息到指定路径
public async Task<FileResult> ExportObjectToExcelByTemplate(IFormFile templateFormFile){var streamone=templateFormFile.OpenReadStream();ExcelHandler excelHandler = new ExcelHandler();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.getExcelTemplate().setDataStartColNum(2);//导出到指定路径excelHandler.exportObjectToExcelByTemplate(streamone, $@"D:\excelexportstreamtemplate\指定路径模板{Guid.NewGuid().ToString("N")}.xlsx", excelDataOutDtos);}
根据模板文件流导出不包含头部底部信息到流
public async Task<FileResult> ExportObjectToExcelByTemplate(IFormFile templateFormFile){var streamone=templateFormFile.OpenReadStream();//导出到流ExcelHandler excelHandler=new ExcelHandler();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.getExcelTemplate().setDataStartColNum(2);NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream();excelHandler.exportObjectToExcelByTemplate(streamThree, npoiMemoryStream, excelDataOutDtos);npoiMemoryStream.Seek(0, SeekOrigin.Begin);return File(npoiMemoryStream, "application/stream", $"模板流文件无头部底部{Guid.NewGuid()}.xlsx");}
导出数据结果如下:
模板包含头部底部信息的导出
模板如下:
根据模板导出包含头部底部信息到指定路径
ExcelHandler excelHandler=new ExcelHandler();excelHandler.getExcelTemplate().setExcelColNums(4 );Dictionary<string, object> headerAndFooterMaps = new Dictionary<string, object>();//头部底部信息 key为#号后面的部分headerAndFooterMaps.Add("datetime", DateTime.Now);headerAndFooterMaps.Add("exporter", "OpenDeepSpace管理员");headerAndFooterMaps.Add("count", excelDataOutDtos.Count);excelHandler.exportObjectToExcelByTemplate(@"C:\Users\lenovo\Desktop\导出的数据模板含头部底部.xlsx", $@"D:\excelexporthftemplate\指定路径带头部底部模板{Guid.NewGuid().ToString("N")}.xlsx",headerAndFooterMaps,excelDataOutDtos);
根据模板导出包含头部底部信息到流
ExcelHandler excelHandler = new ExcelHandler();NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.exportObjectToExcelByTemplate(@"C:\Users\lenovo\Desktop\导出的数据模板含头部底部.xlsx",npoiMemoryStream, headerAndFooterMaps, excelDataOutDtos);npoiMemoryStream.Seek(0, SeekOrigin.Begin);return File(npoiMemoryStream, "application/stream", $"模板流文件有头部底部{Guid.NewGuid()}.xlsx");}
根据模板文件流导出包含头部底部信息到指定路径
public async Task<FileResult> ExportObjectToExcelByTemplateIncludeHeaderAndFooter(IFormFile templateFormFile){var streamone = templateFormFile.OpenReadStream();Dictionary<string, object> headerAndFooterMaps = new Dictionary<string, object>();headerAndFooterMaps.Add("datetime", DateTime.Now);headerAndFooterMaps.Add("exporter", "OpenDeepSpace管理员");headerAndFooterMaps.Add("count", excelDataOutDtos.Count);excelHandler.exportObjectToExcelByTemplate(streamone, $@"D:\excelexporthftemplate\指定路径模板{Guid.NewGuid().ToString("N")}.xlsx",headerAndFooterMaps, excelDataOutDtos);}
根据模板文件流导出包含头部底部信息到流
public async Task<FileResult> ExportObjectToExcelByTemplateIncludeHeaderAndFooter(IFormFile templateFormFile){var streamone = templateFormFile.OpenReadStream();Dictionary<string, object> headerAndFooterMaps = new Dictionary<string, object>();headerAndFooterMaps.Add("datetime", DateTime.Now);headerAndFooterMaps.Add("exporter", "OpenDeepSpace管理员");headerAndFooterMaps.Add("count", excelDataOutDtos.Count);//导出到流excelHandler = new ExcelHandler();excelHandler.getExcelTemplate().setExcelColNums(4);NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream();excelHandler.exportObjectToExcelByTemplate(streamone, npoiMemoryStream,headerAndFooterMaps, excelDataOutDtos);npoiMemoryStream.Seek(0, SeekOrigin.Begin);return File(npoiMemoryStream, "application/stream", $"模板流文件有头部底部{Guid.NewGuid()}.xlsx");}
导出结果如下:
模板已经存在列名的导出
如果模板中已经存在列名,将不会使用ExcelColumn特性中的colName作为列名
模板如下:
根据模板导出存在列名包含头部底部信息到指定路径
ExcelHandler excelHandler = new ExcelHandler();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.setIsClasspath(false);//指定模板是否在工程路径下excelHandler.getExcelTemplate().setIsOrder(true);excelHandler.getExcelTemplate().setOrderName("排序号");//给序号列设置名称Dictionary<string, object> headerAndFooterMaps = new Dictionary<string, object>();headerAndFooterMaps.Add("datetime", DateTime.Now);headerAndFooterMaps.Add("exporter", "OpenDeepSpace管理员");headerAndFooterMaps.Add("count", excelDataOutDtos.Count);excelHandler.exportObjectToExcelByTemplateHasColName(@"C:\Users\lenovo\Desktop\导出的数据模板含头部底部有列名.xlsx", $@"D:\excelexporthftemplate\指定路径带头部底部模板{Guid.NewGuid().ToString("N")}.xlsx", headerAndFooterMaps, excelDataOutDtos);
根据模板导出存在列名包含头部底部信息到流
ExcelHandler excelHandler = new ExcelHandler();NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.getExcelTemplate().insertOrder();excelHandler.getExcelTemplate().setOrderName("排序号");excelHandler.exportObjectToExcelByTemplateHasColName(@"C:\Users\lenovo\Desktop\导出的数据模板含头部底部有列名.xlsx", npoiMemoryStream, headerAndFooterMaps, excelDataOutDtos);npoiMemoryStream.Seek(0, SeekOrigin.Begin);return File(npoiMemoryStream, "application/stream", $"模板流文件有头部底部{Guid.NewGuid()}.xlsx");
根据模板文件流导出存在列名包含头部底部信息到指定路径
public async Task<FileResult> ExportObjectToExcelHasColNameByStream(IFormFile templateFormFile){var streamone = templateFormFile.OpenReadStream();ExcelHandler excelHandler = new ExcelHandler();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.setIsClasspath(false);excelHandler.getExcelTemplate().setIsOrder(true);excelHandler.getExcelTemplate().insertOrder();excelHandler.getExcelTemplate().setOrderName("排序号");//给序号列设置名称Dictionary<string, object> headerAndFooterMaps = new Dictionary<string, object>();headerAndFooterMaps.Add("datetime", DateTime.Now);headerAndFooterMaps.Add("exporter", "OpenDeepSpace管理员");headerAndFooterMaps.Add("count", excelDataOutDtos.Count);excelHandler.exportObjectToExcelByTemplateHasColName(streamone, $@"D:\excelexporthftemplate\指定路径带头部底部模板{Guid.NewGuid().ToString("N")}.xlsx", headerAndFooterMaps, excelDataOutDtos);}
根据模板文件流导出存在列名包含头部底部信息到流
public async Task<FileResult> ExportObjectToExcelHasColNameByStream(IFormFile templateFormFile){var streamone = templateFormFile.OpenReadStream();ExcelHandler excelHandler = new ExcelHandler();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.setIsClasspath(false);excelHandler.getExcelTemplate().setIsOrder(true);excelHandler.getExcelTemplate().insertOrder();excelHandler.getExcelTemplate().setOrderName("排序号");//给序号列设置名称Dictionary<string, object> headerAndFooterMaps = new Dictionary<string, object>();headerAndFooterMaps.Add("datetime", DateTime.Now);headerAndFooterMaps.Add("exporter", "OpenDeepSpace管理员");headerAndFooterMaps.Add("count", excelDataOutDtos.Count);NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream();excelHandler.getExcelTemplate().setExcelColNums(4);excelHandler.getExcelTemplate().insertOrder();excelHandler.getExcelTemplate().setOrderName("排序号");excelHandler.exportObjectToExcelByTemplateHasColName(streamone, npoiMemoryStream, headerAndFooterMaps, excelDataOutDtos);npoiMemoryStream.Seek(0, SeekOrigin.Begin);return File(npoiMemoryStream, "application/stream", $"模板流文件有头部底部{Guid.NewGuid()}.xlsx");}
导出结果如下:
从Excel导出数据到对象集合
这个是根据Excel列名对应ExcelColumn特性来进行导入。
Excel数据截图如下:
从Excel文件导出数据
ExcelHandler excelHandler = new ExcelHandler();var excelDatas = excelHandler.exportExcelToObject<ExcelDataOutDto>(@"C:\Users\lenovo\Desktop\Excel数据导出到对象.xlsx");
从Excel流文件导出数据
public void ExportExcelToObjectByStream(IFormFile formFile){ExcelHandler excelHandler = new ExcelHandler();var excelDatas = excelHandler.exportExcelToObject<ExcelDataOutDto>(formFile.OpenReadStream());}
导出图片到Excel中
暂未实现
多Sheet的导出
暂未实现
注意:从1.1.0版本开始ExcelHandler变为ExcelHandle,并且新增合并单元格操作以及为DateTime字段指定时间格式 1.1.2版本增加基于列的合并特性
合并相同列以及指定Datetime格式化
public class ExcelDataOutDto{[ExcelColumn("唯一标识",1,MergeColumn =true)]//通过ExcelColumn特性指定为需要输出到Excel的列,参数分别为列名,列排序/// <summary>/// Id/// </summary>public string Id { get; set; }[ExcelColumn("姓名", 2,IsBaselineCol =true,MergeColumn =true)]/// <summary>/// 姓名/// </summary>public string Name { get; set; }[ExcelColumn("年龄", 3,MergeColumn =true)]/// <summary>/// 年龄/// </summary>public int Age { get; set; }[ExcelColumn("出生日期",4,DatePattern ="yyyy-MM-dd HHmmss")]//指定日期/// <summary>/// 出生日期/// </summary>public DateTime BirthDate { get; set; }/// <summary>/// 其他信息/// </summary>public string OtherInfo { get; set; }}
Excel导出效果如下:
增加数据验证特性
这里如果你需要对导入或导出的数据验证,在1.1.3版本中可以通过继承DataValidationAttribute特性,实现IsValid方法来完成数据的验证.目前还没有提供一些默认的验证特性,后续考虑提供。
如下代码:
实现数据验证特性
//不为空
public class NotNullAttribute:DataValidationAttribute{public override DataValidationResult? IsValid(object data){if (data == null || string.IsNullOrWhiteSpace(data.ToString()))return new DataValidationResult(ErrorMessage);return DataValidationResult.Success;}}
//最大长度
public class MaxLengthAttribute : DataValidationAttribute{public int MaxLength { get; set; }public override DataValidationResult IsValid(object data){if (data.ToString().Length > MaxLength)return new DataValidationResult(ErrorMessage);return DataValidationResult.Success;}}
使用数据验证特性:
[NotNull(ErrorMessage ="姓名不能为空")][MaxLength(MaxLength =100, ErrorMessage ="姓名最大长度不能超过100个字符")][ExcelColumn("姓名", 2,IsBaselineCol =true,MergeColumn =true)]/// <summary>/// 姓名/// </summary>public string Name { get; set; }
版本1.1.7中增加基于ExcelSheetAttribute特性以及基于父子级递归关联方式的多Sheet导出(仅限基于非模板方式的导出,且原则上支持无限级)
版本1.1.7增加ExcelSheetAttribute特性
ExcelSheetAttribute特性可以使用在类上和属性上,可以设置SheetName,即表示指定类输出到的Sheet的名称。
使用在类上:表示该类对应的数据输出的Sheet的名称
使用在属性上:表示该属性是一个关联的Sheet导出,建议采用List
结合ExcelSheetAttribute实现基于父子级递归关联方式的多Sheet导出
例子如下:
三级关联例子
/// <summary>/// 泛指ExcelData数据输出对象/// </summary>[ExcelSheet(SheetName = "主数据")]public class ExcelDataOutDto{[ExcelColumn("唯一标识", 1, MergeColumn = true)]//通过ExcelColumn特性指定为需要输出到Excel的列,参数分别为列名,列排序/// <summary>/// Id/// </summary>public string Id { get; set; }//[NotNull(ErrorMessage = "姓名不能为空")]s//[MaxLength(MaxLength = 100, ErrorMessage = "姓名最大长度不能超过100个字符")][ExcelColumn("姓名", 2, IsBaselineCol = true, MergeColumn = true)]/// <summary>/// 姓名/// </summary>public string Name { get; set; }[ExcelColumn("年龄", 3, MergeColumn = true)]/// <summary>/// 年龄/// </summary>public int Age { get; set; }[ExcelColumn("出生日期", 4, DatePattern = "yyyy-MM-dd HHmmss")]/// <summary>/// 出生日期/// </summary>public DateTime BirthDate { get; set; }/// <summary>/// 其他信息/// </summary>public string OtherInfo { get; set; }/// <summary>/// 关联数据/// </summary>[ExcelSheet]public List<ExcelRelationDataOutDto> ExcelRelationDataOutDtos { get; set; }}[ExcelSheet(SheetName = "关联数据")]public class ExcelRelationDataOutDto{[ExcelColumn(ColOrder =1,ColName ="名称",MergeColumn =true,IsBaselineCol =true)]public string Name { get; set; }/// <summary>/// 关联子数据/// </summary>[ExcelSheet]public List<ExcelRelationDataRelationOutDto> RelationData { get; set; }}
/// <summary>/// <see cref="ExcelRelationDataOutDto"/>的关联子数据/// </summary>[ExcelSheet(SheetName = "孙子数据")]public class ExcelRelationDataRelationOutDto{[ExcelColumn(ColOrder = 1, ColName = "名称", MergeColumn = true, IsBaselineCol = true)]public string Name { get; set; }}
三级关联的数据
List<ExcelDataOutDto> excelDataOutDtos = new List<ExcelDataOutDto>() {new ExcelDataOutDto(){Id=Guid.NewGuid().ToString(),Name="小张",Age=20,BirthDate=DateTime.Today.AddYears(-20),OtherInfo="我是小张,我不嚣张",ExcelRelationDataOutDtos=new List<ExcelRelationDataOutDto>(){ new ExcelRelationDataOutDto(){ Name="小张关联"},new ExcelRelationDataOutDto(){ Name="小张关联"},new ExcelRelationDataOutDto(){ Name="小张关联3",//子数据的子数据RelationData =new List<ExcelRelationDataRelationOutDto>(){ new ExcelRelationDataRelationOutDto(){ Name="小张孙子数据"}}},}},new ExcelDataOutDto(){Id="b66f90b7-178b-11ed-98e5-00155d562808",Name="小李",Age=24,BirthDate=DateTime.Today.AddYears(-24),OtherInfo="面对疾风吧"},new ExcelDataOutDto(){Id="b66f90b7-178b-11ed-98e5-00155d562808",Name="小李",Age=24,BirthDate=DateTime.Today.AddYears(-24),OtherInfo="面对疾风吧八八八",ExcelRelationDataOutDtos=new List<ExcelRelationDataOutDto>(){new ExcelRelationDataOutDto(){ Name="小李关联",//子数据的子数据RelationData =new List<ExcelRelationDataRelationOutDto>(){new ExcelRelationDataRelationOutDto(){ Name="小李孙子数据"},new ExcelRelationDataRelationOutDto(){ Name="小李孙子数据"},new ExcelRelationDataRelationOutDto(){ Name="小李孙子数据2"}}}}},/*new ExcelDataOutDto(){Id=Guid.NewGuid().ToString(),Name="小红",Age=24,BirthDate=DateTime.Today.AddYears(-24),OtherInfo="面对疾风吧八八八"},*/new ExcelDataOutDto(){Id="b66f90b7-178b-11ed-98e5-00155d5s2808",Name="小吴",Age=27,BirthDate=DateTime.Today.AddYears(-27),OtherInfo="哈哈哈笑而不语",ExcelRelationDataOutDtos=new List<ExcelRelationDataOutDto>(){new ExcelRelationDataOutDto(){ Name="小吴关联"},new ExcelRelationDataOutDto(){ Name="小吴关联3"}}},new ExcelDataOutDto(){Id="b66f90b7-178b-11ed-98e5-00155d5s2808",Name="小吴",Age=27,BirthDate=DateTime.Today.AddYears(-27),OtherInfo="哈哈哈笑笑笑"},new ExcelDataOutDto(){Id="b66f90b7-178b-11ed-98e5-00155d5s2809",Name="",Age=27,BirthDate=DateTime.Today.AddYears(-27),OtherInfo="哈哈哈笑笑笑"},};
导出例子:
/// <summary>/// 无模板导出数据到excel并返回流文件供下载/// </summary>/// <returns></returns>[HttpGet]public async Task<FileResult> ExportObjectToExcelToStream(){ExcelHandle ExcelHandle = new ExcelHandle();NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream();List<ExcelDataOutDto> excelDataOutDtosOver = new List<ExcelDataOutDto>();for (int i = 0; i < 10000; i++){excelDataOutDtosOver.AddRange(excelDataOutDtos);}ExcelHandle.exportObjectToExcel(npoiMemoryStream, excelDataOutDtosOver);npoiMemoryStream.Seek(0, SeekOrigin.Begin);return File(npoiMemoryStream, "application/stream", $"{Guid.NewGuid()}.xlsx");}
导出结果如下:
版本1.1.8
修复部分错误。数据验证错误信息ErrorMessage中增加 {row} 占位符,来实现行下标的错误数据的提示。
比如:
/// <summary>/// 部门/// </summary>[ColumnNotNull(ErrorMessage = "第{row}行数据:部门不能为空")][ExcelColumn(ColOrder = 1, ColName = "部门")]public string Department { get; set; }
测试结果如下如果部门列下对应的数据为空,就会抛出如下异常:
当然如果你想自己处理异常,抛出你自己定义的友好异常可以try catch捕获这个异常然后处理。
版本1.1.9 异常处理优化
这里我分为两种异常,一种是数据异常,一种是列名表头异常。
/// <summary>/// Npoi异常码/// </summary>public class NpoiExceptionCode{/// <summary>/// 数据异常/// </summary>public const int DataException = 1000;/// <summary>/// 列名异常/// </summary>public const int ColumnNameException = 2000;}
数据异常就是:数据验证的时候出现异常,通过NpoiException包裹
列名异常就是:读取Excel中的数据时,如果对应列名查找不到那么就会通过NpoiException包裹 ColumnNameException。
你可以通过try catch捕获它,然后来实现用自己的异常抛出处理。比如这样:
//读取文件中数据ExcelHandle excelHandle = new ExcelHandle();List<EmergencyWorkerInDto> emergencyWorkerInDtos = new List<EmergencyWorkerInDto>();using (var stream = file.OpenReadStream()){try{var fileContent = excelHandle.exportExcelToObject<EmergencyWorkerInDto>(stream,IsAutoSkipNullRow:false);if (fileContent.Count == 0)throw new FriendlyException("Excel文件中没有任何数据");foreach (var item in fileContent){item.ResponseLevelId = ResponseLevelId;emergencyWorkerInDtos.Add(item);}}catch (Exception ex){if (ex is NpoiException npoiException){if (npoiException.ExceptionCode == NpoiExceptionCode.ColumnNameException)throw new FriendlyException("Excel文件与模板不符合");elsethrow new FriendlyException(npoiException.Message);}else{throw new FriendlyException(ex.Message);}}}
注意对于文件中除了表头没有数据有两种:第一种是除了表头,其他没有单元格没有任何填充(包括单元格背景设置),这种是需要自己判断处理,如上throw new FriendlyException(“Excel文件中没有任何数据”);
还有一种就是单元格有填充但无数据,这种就不是空,如果设置了数据验证就会抛出异常。
C#基于Npoi通过特性的方式导出简单数据到Excel或基于特性以及基于Excel模板导出数据到Excel以及从Excel中把数据导入到对象中相关推荐
- 如何将skp文件中的模型导入到UE4中
首先,skp文件是不能直接导入到UE4中的. 解决方法:用SketchUp(草图大师)打开skp文件,在SketchUp中将模型转换成fbx格式,然后再将模型导入UE4中 目录 1.打开skp文件 2 ...
- js给对象添加变量属性 js 更改对象中的属性名 数组对象中每个对象添加一个字段-map用法和forEarch用法
js给对象添加变量属性 & js 更改对象中的属性名 & 数组对象中每个对象添加一个字段-map用法和forEarch用法 1.js给对象添加变量属性 1.js创建一个对象或者在原有对 ...
- 将dblp中的文件导入到endnote中
将dblp中的文件导入到endnote中 复制要导入的论文题目到dblp中搜索 点击第一个按钮的第一个链接 跳转后页面点击cite 点击1 Endnote,然后点击2下载. 此时并没有下载文件,页面跳 ...
- 网络编程8/17——将dict.txt中的内容导入到数据库中
目录 代码 运行结果 dict.txt 作业:将dict.txt中的内容导入到数据库中 注意: 导入后检查解释意思是否完整,双词性 中间有空格的单词 o'clock 代码 #include<st ...
- python中使用什么导入模块-Python中使用语句导入模块或包的机制研究
这篇文章讨论了Python的from import *和from import *,它们怎么执行以及为什么使用这种语法(也许)是一个坏主意. 从一个模块导入全部 from import * means ...
- python 中matplotlib 画图导入到word中如何保证分辨率
python 中利用matplotlib 画图导入到word中如何保证分辨率 在写论文时,如果是菜鸟级别,可能不会花太多时间去学latex,直接用word去写,但是这有一个问题,当我们用其他工具画完实 ...
- java中id name_关于DOM对象中的id与name的区别
例1: value="admin"> id="un" name="username" value="silas"& ...
- 关于python中requests模块导入问题-python中requests模块的使用方法
本文实例讲述了python中requests模块的使用方法.分享给大家供大家参考.具体分析如下: 在HTTP相关处理中使用python是不必要的麻烦,这包括urllib2模块以巨大的复杂性代价获取综合 ...
- 如何将数据库中的记录表导入到VC中
具体步骤如下: 首先新建一个基于对话框的工程,在对话框CConnectDatabaseDialog中添加按钮:IDC_ScoreSequery,Caption:导入表,双击"导入表" ...
最新文章
- 学习笔记TF065:TensorFlowOnSpark
- Linux内核分析 - 网络[四]:路由表
- Fiddler 自定义规则编写
- 146. LRU Cache
- shell中执行hive命令错误:delimited by end-of-file (wanted `EOF')
- 使用docker-compose搭建AspNetCore开发环境
- 微信小程序上传大于4m_微信定制小程序开发
- oracle linux 图形化,Linux7图形化安装Oracle11g教程,亲测实用有效!
- abap object-oriented–使用事件
- NYOJ96 - n-1位数
- 什么软件画er图方便_ER模型怎么画?必备入门级模型图绘制软件
- 同IP不同端口导致cookie冲突的解决方法
- Azure vNet
- sMRI影像数据3维CNN卷积
- centos 6.9部署svn服务器和客户端(客户端含windows、linux版本)
- JQuery对联广告
- 葫芦书笔记----CNN和RNN
- 王者荣耀的技术修炼之路
- 人民邮电报丨智链助力北大荒大米实现区块链全生命周期追溯
- 游戏自定义金币单位换算管理类