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文件与模板不符合");
                        else
                            throw new FriendlyException(npoiException.Message);


                    }
                    else
                    {
                        throw new FriendlyException(ex.Message);
                    }
                }

            }

注意对于文件中除了表头没有数据有两种:第一种是除了表头,其他没有单元格没有任何填充(包括单元格背景设置),这种是需要自己判断处理,如上throw new FriendlyException(“Excel文件中没有任何数据”);
还有一种就是单元格有填充但无数据,这种就不是空,如果设置了数据验证就会抛出异常。

版本1.1.11 基于Json格式的数据导出到Excel,支持多sheet

你需要按照格式生成一个如下的JsonArray的数据:
JsonArray里面的每一个JsonObject,则对应输出到一个Sheet,所以这里可以输出多个Sheet

其中ColumnTitles指明列名,可选项,也可不传,不传以后面Datas数据中属性名称为列名 例如"Name":“小李” 这里以Name为列名
其中SheetName指明Sheet表的名称,可选项,
其中Datas指明数据,必须项,为一个JsonArray,里面是所有数据
其中IsOrder指定是否输出序号,true表示输入,可选项,默认为true

[{"ColumnTitles":["姓名","部门"],"SheetName":"第一个sheet名称","Datas":[{"Name":"小李","Department":"管理部"}],"IsOrder":true},{}]

简单的只有数据

[{"Datas":[{"Name":"小李","Department":"管理部"}]},{}]

//使用方式如下

/// <summary>
        ///导出json数据到excel并返回流文件供下载
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<FileResult> ExportJsonToExcel(string JsonData)
        {
            NpoiMemoryStream npoiMemoryStream = new NpoiMemoryStream();

            ExcelHandle excelHandle=new ExcelHandle();
            excelHandle.exportJsonToExcel(npoiMemoryStream,JsonData);
            npoiMemoryStream.Seek(0, SeekOrigin.Begin);

            return File(npoiMemoryStream, "application/stream", $"{Guid.NewGuid()}.xlsx");
        }

//结果
在这里插入图片描述

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值