.Net Core 如何数据导出 Excel?(EPPlus->OfficeOpenXml 实现固定列和动态列导出)

net,core,如何,数据,导出,excel,epplus,officeopenxml,实现,固定,动态 · 浏览次数 : 412

小编点评

**代码说明** 该代码展示了如何使用 `EpplusHelperPublic` 类下载配置列表并添加动态数据到 Excel 工作表中。代码中包含以下部分: **1. 数据获取** - 使用 `DynamicParameters` 类创建动态参数对象。 - 通过 `switch` 语句根据不同的下载类型获取数据列名。 - 将数据列名加入 `headerscode` 列表。 **2. 动态数据添加** - 使用 `AddObjects` 方法添加动态数据到 Excel 工作表中。 - 动态参数对象包含数据列名、值等信息。 - 通过 `dict_lie` 字典存储动态数据。 **3. 设置列宽** - 使用 `worksheet.Column(1).Width = 8;` 等方式设置列宽。 - 设置其他列宽。 **4. 冻结第一行** - 使用 `worksheet.View.FreezePanes(2, 2);` 等方法冻结第一行和第一列。 **5. 代码格式** - 使用 `string sFileName = $\"{Guid.NewGuid()}.xlsx\";` 创建 Excel 文件名称。 - 使用 `FileInfo` 类保存 Excel 工作表。 - 使用 `ExcelPackage.LicenseContext` 设置 Excel 工作表格式。 - 使用 `string sFileName = $\"{Guid.NewGuid()}.xlsx\";` 创建 Excel 文件名称。 **6. 示例** 该代码展示了如何下载配置列表并添加动态数据到 Excel 工作表中。 **注意** 代码中的 `headerscode` 变量需要根据实际情况进行修改。

正文

〇、前言

特别注意:本文涉及的包(OfficeOpenXml.Extension.AspNetCore)依赖于 EPPlus 5.0.3 等更高版本,属于限制商业用途版本,因此只能用作个人或公司小范围内部使用。

对于将数据以 Excel 表格文件输出,还是比较常用的,也存在诸多情况,比如列固定或不固定、数据类型为 List<T>或 Json 对象等。

本文通过包 OfficeOpenXml.Extension.AspNetCore 实现两个方法导出列数固定和不固定的数据。

注意:OfficeOpenXml.Extension.AspNetCore 是一个基于 OfficeOpenXml 拓展,它依赖于 EPPlus,用于根据模板输出 Excel。

包控制台安装:

NuGet> Install-Package OfficeOpenXml.Extension.AspNetCore -Version 1.0.0

一、根据已知类型对象 List 下载

本章节方法适用背景:

  数据列数固定,且可罗列。

对于对象 List<T> 的属性,一般不会命名为汉字,那么就需要将列名转换为汉字,以方便数据清晰显示。

如下为一个基于 WebAPI 项目的固定列数,动态行数的下载实例:

// 安装包:OfficeOpenXml.Extension.AspNetCore // 支持 Core 3.1 及以上,Standard 2.0 及以上
using OfficeOpenXml;
using OfficeOpenXml.Style;
using Microsoft.AspNetCore.Mvc; // File 支持

[HttpGet]
public FileContentResult DownloadInfo()
{
    try
    {
        string sql_datalist = "";
        var resultlist = dapperFactory.Query<ShujuMXModel>(sql_datalist).ToList();
        string sFileName = $"{Guid.NewGuid()}.xlsx";
        FileInfo fileinfo = new FileInfo(System.IO.Path.Combine("C:/Files", sFileName));
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
        using (ExcelPackage package = new ExcelPackage(fileinfo))
        {
            // 添加 worksheet
            ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("明细表");
            // 添加头
            worksheet.Cells[1, 1].Value = "序号";
            worksheet.Cells[1, 2].Value = "公司";
            worksheet.Cells[1, 3].Value = "日期";
            // 添加值
            for (int i = 0; i < resultlist.Count; i++)
            {
                worksheet.Cells["A" + (i + 2)].Value = resultlist[i].xuhao;
                worksheet.Cells["B" + (i + 2)].Value = resultlist[i].gongsimc;
                worksheet.Cells["C" + (i + 2)].Value = resultlist[i].riqi.Substring(0,10);
            }
            worksheet.Column(1).Width = 10; // 设置列宽,从第 1 列开始
            worksheet.Column(2).Width = 30;
            worksheet.Column(3).Width = 15;
            worksheet.Row(1).Style.Font.Bold = true; // 给第一行内容设置加粗
            worksheet.Cells.Style.WrapText = true; // 自动换行
            worksheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Top;
            // 给有数据的区域添加边框
            using (ExcelRange excelRange = worksheet.Cells[1, 1, resultlist.Count + 1, 3]) // [从第一行开始,从第一列开始,到第几行,到第几列]
            {
                r.Style.Border.Top.Style = ExcelBorderStyle.Thin; // 实线
                r.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
                r.Style.Border.Left.Style = ExcelBorderStyle.Thin;
                r.Style.Border.Right.Style = ExcelBorderStyle.Thin;
                r.Style.Border.Top.Color.SetColor(System.Drawing.Color.Black); // 黑色
                r.Style.Border.Bottom.Color.SetColor(System.Drawing.Color.Black);
                r.Style.Border.Left.Color.SetColor(System.Drawing.Color.Black);
                r.Style.Border.Right.Color.SetColor(System.Drawing.Color.Black);
            }
            worksheet.Row(1).Style.Font.Bold = true;
            worksheet.Row(1).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; // 第一行内容水平居中
            package.Save();
        }
        using (FileStream fs= fileinfo.OpenRead())
        {
            BinaryReader br = new BinaryReader(fs);
            br.BaseStream.Seek(0, SeekOrigin.Begin); // 将文件指针设置到文件开
            byte[] fileBytes = br.ReadBytes((int)br.BaseStream.Length);
            return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, sFileName); // 返回文件对象,前端可直接进行下载动作
        }
    }
    catch (Exception ex)
    {
        return null;
    }
}

 二、动态列数据库下载

本章节方法适用背景:

  数据列数不固定,且可循环取出,表头和对应的数据顺序相同。

动态列就是,列总数不固定,程序根据传入的列数确定第一行表头。

下面是一个根据 json 字符串,以 Excel 文件形式保存数据的实例。其中包含 “tableheader”节点,来指定动态表头;“tablebody”代表全部数据列表。

// 安装包:OfficeOpenXml.Extension.AspNetCore // 支持 Core 3.1 及以上,Standard 2.0 及以上
// 由于 Excel 2003 版本 和 2007 之后版本文件结构的差异性,当前扩展无法同时兼容两种模式,仅支持 *.xlsx 文件
using OfficeOpenXml;
using OfficeOpenXml.Style;

public void DownloadByJsonstr(string xiazaisj)
{
    // string jsonstr = "{\"tableheader\":[{\"mingcheng\":\"列名一\",\"daima\":\"bumenx1\",\"shifoutz\":true},{\"mingcheng\":\"列名二\",\"daima\":\"bumenx2\",\"shifoutz\":true}],\"tablebody\":[{\"kemumc\":\"科目一\",\"bumenx1\":0.12,\"bumenx2\":6.0,\"heji\":6.12,\"erjimx\":[{\"kemumc\":\"科目一明细科目1\",\"bumenx1\":0.0,\"bumenx2\":9.82,\"heji\":9.82},{\"kemumc\":\"科目一明细科目2\",\"bumenx1\":0.12,\"bumenx2\":6.18,\"heji\":6.3}]}]}";
    var baobiaosj_json = Json_Object.StrToJson(xiazaisj);
    var tableheader = xiazaisj_json["tableheader"];
    // 前两列表头固定
    List<string> headersname = new List<string>(){ "科目", "合计" }; // 用于显示
    List<string> headerscode = new List<string>(){ "kemumc", "heji" }; // 用于取值
    // 从第三列开始,按默认顺序加入后续表头
    foreach (var thj in tableheader)
    {
        headersname.Add(thj["mingcheng"].ToString());
        headerscode.Add(thj["daima"].ToString());
    }
    string sFileName = $"{Guid.NewGuid()}.xlsx";
    FileInfo fileinfo = new FileInfo(System.IO.Path.Combine("C:/Log", sFileName));
    ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
    List<TableRowModel> tableRowModels = new List<TableRowModel>();
    using (ExcelPackage package = new ExcelPackage(fileinfo))
    {
        ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("数据表");
        EpplusHelperPublic.AddHeader(worksheet, headersname.ToArray()); // 添加表头
        var tablebody = xiazaisj_json["tablebody"];
        TableRowModel tableRowModel = new TableRowModel();
        Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
        foreach (var tablebody_first in tablebody)
        {
            tableRowModel = new TableRowModel();
            keyValuePairs = new Dictionary<string, string>();
            tableRowModel.kemumc = tablebody_first["kemumc"].ToString(); // "kemumc": "成本"
            tableRowModel.heji = tablebody_first["heji"].ToString();
            for (int ii = 2; ii < headerscode.Count; ii++)
            {
                keyValuePairs.Add(headerscode[ii], tablebody_first[headerscode[ii]].ToString()); // "bumenx1": 0.0
            }
            tableRowModel.dict_lie = keyValuePairs;
            tableRowModels.Add(tableRowModel);
            if (tablebody_first["erjimx"] != null)
            {
                foreach(var tablebody_second in tablebody_first["erjimx"])
                {
                    tableRowModel = new TableRowModel();
                    keyValuePairs = new Dictionary<string, string>();
                    tableRowModel.kemumc = tablebody_second["kemumc"].ToString(); // "kemumc": "成本"
                    tableRowModel.heji = tablebody_second["heji"].ToString();
                    for (int ii = 2; ii < headerscode.Count; ii++)
                    {
                        keyValuePairs.Add(headerscode[ii], tablebody_second[headerscode[ii]].ToString()); // "bumenx1": 0.0
                    }
                    tableRowModel.dict_lie = keyValuePairs;
                    tableRowModels.Add(tableRowModel);
                }
            }
        }
        if (tableRowModels.Count > 0)
        {
            //添加动态数据
            EpplusHelperPublic.AddObjects(worksheet, 2, tableRowModels, headerscode);
        }
        worksheet.Column(1).Width = 20; // 设置列宽
        worksheet.Column(2).Width = 20;
        for (int ii = 3; ii <= headerscode.Count; ii++) // 为动态列设置统一列宽
        {
            worksheet.Column(ii).Width = 16;
        }
        //worksheet.Cells.Style.WrapText = true; // 自动换行
        worksheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Top;
        using (ExcelRange r = worksheet.Cells[1, 1, tableRowModels.Count + 1, headersname.Count])
        {
            r.Style.Border.Top.Style = ExcelBorderStyle.Thin;
            r.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
            r.Style.Border.Left.Style = ExcelBorderStyle.Thin;
            r.Style.Border.Right.Style = ExcelBorderStyle.Thin;

            r.Style.Border.Top.Color.SetColor(System.Drawing.Color.Black);
            r.Style.Border.Bottom.Color.SetColor(System.Drawing.Color.Black);
            r.Style.Border.Left.Color.SetColor(System.Drawing.Color.Black);
            r.Style.Border.Right.Color.SetColor(System.Drawing.Color.Black);
        }
        worksheet.View.FreezePanes(2, 3); // 冻结第一行,以及前两列
        worksheet.Row(1).Style.Font.Bold = true; // 第一行加粗
        worksheet.Row(1).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;// 第一行水平居中
        package.Save();
    }
}

 EpplusHelperPublic.cs 类,用作循环添加表头和数据。

using System;
using System.Collections.Generic;
using OfficeOpenXml;

public static class EpplusHelperPublic
{
    /// <summary>
    /// 通过 名称数组 添加表头
    /// </summary>
    /// <param name="sheet"></param>
    /// <param name="headertexts"></param>
    public static void AddHeader(ExcelWorksheet sheet, params string[] headertexts)
    {
        for (var i = 0; i < headertexts.Length; i++)
        {
            AddHeader(sheet, i + 1, headertexts[i]);
        }
    }
    /// <summary>
    /// 直接添加表头
    /// </summary>
    /// <param name="sheet"></param>
    /// <param name="columnindex"></param>
    /// <param name="headertext"></param>
    public static void AddHeader(ExcelWorksheet sheet, int columnindex, string headertext)
    {
        sheet.Cells[1, columnindex].Value = headertext;
        sheet.Cells[1, columnindex].Style.Font.Bold = true;
    }
    /// <summary>
    /// 添加动态数据
    /// </summary>
    /// <param name="worksheet"></param>
    /// <param name="startrowindex">从第几行开始</param>
    /// <param name="items">行数据列表</param>
    /// <param name="headerscode">列名代码列表,用于取数据</param>
    public static void AddObjects(ExcelWorksheet worksheet, int startrowindex, IList<TableRowModel> items, List<string> headerscode)
    {
        for (var i = 0; i < items.Count; i++)
        {
            worksheet.Cells[i + startrowindex, 1].Value = items[i].kemumc; // 注意此处为兼容前两列固定列
            worksheet.Cells[i + startrowindex, 2].Value = items[i].heji;
            for (var j = 2; j < headerscode.Count; j++) // headercode:kemumc,heji,bumenx1,bumenx2...
            {
                worksheet.Cells
                    [i + startrowindex,
                    j + 1]
                    .Value
                    = items[i].dict_lie[headerscode[j]];
            }
        }
    }
}

代码参考:C# 使用Epplus导出Excel [2]:导出动态列数据

三、多目标对象的情况下统一下载入口 --20230717

注意:本章节通过定义一个通用的对象,将不同表的不同字段对应到统一的对象,在对统一的对象进行下载操作。

以下为实现代码,其中也用到了本文第二章节中的 EpplusHelperPublic.cs 类。

代码中,将两个不同的对象,通过数据库 SQL 语句,让查询结果为同一对象,从而方便统一导出操作。

/// <summary>
/// 下载配置列表(共用)
/// </summary>
/// <param name="inParametersModel"></param>
/// <returns></returns>
[HttpPost]
public void DownloadConfigList([FromBody] InParametersModel inpara)
{
    List<string> tableheaders = new List<string>();
    string tablename = string.Empty,selectparameters = string.Empty,condition =string.Empty;
    DynamicParameters dynamicParameters = new DynamicParameters();
    int lieshu = 0;
    switch (inpara.xiazailx) // 下载类型 1公司 2部门
    {
        case 1: // 1名称
            tableheaders = new List<string>() { "序号", "编码", "公司名称", "公司系" };
            tablename = "CompanyInfo";
            selectparameters = "ROW_NUMBER() OVER (ORDER BY gongsibm) xuhao,gongsibm lieming1,gongsimc lieming2,gongsix lieming3";
            if (inpara.mingcheng != null && inpara.mingcheng.Length > 0)
            {
                condition = "and (gongsibm like @gongsibm or gongsimc like @gongsibm) ";
                dynamicParameters.Add("@gongsibm", $"%{inpara.mingcheng}%");
            }
            lieshu = tableheaders.Count;
            break;
        case 2: // 2部门
            tableheaders = new List<string>() { "序号", "编码", "部门名称", "描述", "上级部门" };
            tablename = "DeptmentInfo";
            selectparameters = "ROW_NUMBER() OVER (ORDER BY bumenbm) xuhao,bumenbm lieming1,bumenmc lieming2,miaoshu lieming3,shangjibmbm lieming4";
            if (inpara.mingcheng != null && inpara.mingcheng.Length > 0)
            {
                condition = "and (bumenbm like @bumenbm or bumenmc like @bumenbm) ";
                dynamicParameters.Add("@bumenbm", $"%{inpara.mingcheng}%");
            }
            if (inpara.shifoujy != null && inpara.shifoujy.Length > 0)
            {
                dynamicParameters.Add("@shifoujy", inpara.shifoujy);
                condition += "and shifoujy = @shifoujy ";
            }
            lieshu = tableheaders.Count;
            break;
        default:
            return null;
    }
    // AnonymousModel 为通用 Model,字段为 xuhao、lieming1、lieming2、、、
    var resultlist = dapperFactory.Query<AnonymousModel>($"select {selectparameters} from {tablename} where Flag>0 {condition}", dynamicParameters).ToList();
    string sFileName = $"{Guid.NewGuid()}.xlsx";
    FileInfo fileinfo = new FileInfo(System.IO.Path.Combine("C:/Log", sFileName));
    ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
    List<TableRowPublicModel> tableRowModels = new List<TableRowPublicModel>();
    using (ExcelPackage package = new ExcelPackage(fileinfo))
    {
        ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("配置信息表");
        EpplusHelperPublic.AddHeader(worksheet, tableheaders.ToArray()); // 添加表头
        List<string> headerscode = new List<string>();
        TableRowPublicModel tableRowModel = new TableRowPublicModel();
        Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
        foreach (var resultinfo in resultlist)
        {
            tableRowModel = new TableRowPublicModel();
            // 通过反射来取对象的属性代码和值 https://www.cnblogs.com/chenwolong/p/fanshe.html
            Type t = resultinfo.GetType(); 
            PropertyInfo[] PropertyList = t.GetProperties();
            keyValuePairs = new Dictionary<string, string>();
            foreach (PropertyInfo item in PropertyList)
            {
                object value = item.GetValue(resultinfo, null);
                keyValuePairs.Add(item.Name, value?.ToString());
                if(headerscode.Count< lieshu) // 取对应的有效列数
                    headerscode.Add(item.Name);
            }
            tableRowModel.dict_lie = keyValuePairs;
            tableRowModels.Add(tableRowModel);
        }
        if (tableRowModels.Count > 0)
        {
            //添加动态数据
            EpplusHelperPublic.AddObjects(worksheet, 2, tableRowModels, headerscode);
        }
        worksheet.Column(1).Width = 8; // 设置列宽
        for (int ii = 2; ii <= headerscode.Count; ii++)
        {
            worksheet.Column(ii).Width = 20;
        }
        //worksheet.Cells.Style.WrapText = true; // 自动换行
        worksheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Top;
        using (ExcelRange r = worksheet.Cells[1, 1, tableRowModels.Count + 1, tableheaders.Count])
        {
            r.Style.Border.Top.Style = ExcelBorderStyle.Thin;
            r.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
            r.Style.Border.Left.Style = ExcelBorderStyle.Thin;
            r.Style.Border.Right.Style = ExcelBorderStyle.Thin;

            r.Style.Border.Top.Color.SetColor(System.Drawing.Color.Black);
            r.Style.Border.Bottom.Color.SetColor(System.Drawing.Color.Black);
            r.Style.Border.Left.Color.SetColor(System.Drawing.Color.Black);
            r.Style.Border.Right.Color.SetColor(System.Drawing.Color.Black);
        }
        worksheet.View.FreezePanes(2, 2); // 冻结第一行,以及第一列
        worksheet.Row(1).Style.Font.Bold = true; // 第一行加粗
        worksheet.Row(1).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;// 第一行水平居中
        package.Save();
    }
}
public class TableRowPublicModel
{
    public Dictionary<string,string> dict_lie { get; set; }
}

与.Net Core 如何数据导出 Excel?(EPPlus->OfficeOpenXml 实现固定列和动态列导出)相似的内容:

.Net Core 如何数据导出 Excel?(EPPlus->OfficeOpenXml 实现固定列和动态列导出)

对于将数据以 Excel 表格文件输出,还是比较常用的,也存在诸多情况,比如列固定或不固定、数据类型为 List

.NET Core反射获取带有自定义特性的类,通过依赖注入根据Attribute元数据信息调用对应的方法

前言 前段时间有朋友问道一个这样的问题,.NET Core中如何通过Attribute的元数据信息来调用标记的对应方法。我第一时间想到的就是通过C#反射获取带有Custom Attribute标记的类,然后通过依赖注入(DI)的方式获取对应服务的方法并通过反射动态执行类的方法,从而实现更灵活的编程方

【ASP.NET Core】MVC操作方法如何绑定Stream类型的参数

咱们都知道,MVC在输入/输出中都需要模型绑定。因为HTTP请求发送的都是文本,为了使其能变成各种.NET 类型,于是在填充参数值之前需 ModelBinder 的参与,以将文本转换为 .NET 类型。 尽管 ASP.NET Core 已内置基础类型和复杂类型的各种 Binder,但有些数据还是不能

Skywalking APM监控系列(二、Mysql、Linux服务器与前端JS接入Skywalking监听)

前言 上篇我们介绍了Skywalking的基本概念与如何接入.Net Core项目,感兴趣可以去看看: Skywalking APM监控系列(一丶.NET5.0+接入Skywalking监听) 本篇我们主要讲解一下Skywalking如何接入mysql数据库监听与Linux服务器的监听 其实从Sky

.NET Core MongoDB数据仓储和工作单元模式实操

前言 上一章节我们主要讲解了MongoDB数据仓储和工作单元模式的封装,这一章节主要讲的是MongoDB用户管理相关操作实操。如:获取所有用户信息、获取用户分页数据、通过用户ID获取对应用户信息、添加用户信息、事务添加用户信息、用户信息修改、用户信息删除等实战教程。 MongoDB从入门到实战的相关

Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: Users'.

今天使用asp.net core + sqlite 创建了一个demo项目,本地运行一切正常。可以添加,修改,删除数据。一旦发布到服务器上(Linux系统)就报错,错误信息如下: ![](https://img2023.cnblogs.com/blog/2912666/202308/2912666-

WTM的项目中EFCore如何适配人大金仓数据库

一、WTM是什么 WalkingTec.Mvvm框架(简称WTM)最早开发与2013年,基于Asp.net MVC3 和 最早的Entity Framework, 当初主要是为了解决公司内部开发效率低,代码风格不统一的问题。2017年9月,将代码移植到了.Net Core上,并进行了深度优化和重构,

XUnit数据共享与并行测试

引言 在单元或者集成测试的过程中,需要测试的用例非常多,如果测试是一条一条过,那么需要花费不少的时间。从 V2 开始,默认情况下 XUnit 自动配置并行(参考资料),大大提升了测试速度。本文将对 ASP.NET CORE WEBAPI 程序进行集成测试,并探讨 XUnit 的数据共享与测试并行的方

Asp-Net-Core开发笔记:快速在已有项目中引入EFCore

前言 很多项目一开始选型的时候没有选择EFCore,不过EFCore确实好用,也许由于种种原因后面还是需要用到,这时候引入EFCore也很方便。 本文以 StarBlog 为例,StarBlog 目前使用的 ORM 是 FreeSQL ,引入 EFCore 对我来说最大的好处是支持多个数据库,如果是

使用EF 连接 数据库 SQLserver、MySql 实现 CodeFirst

1.新建项目,下载Nuget安装包 创建项目需要注意几点,如果是基于 .net framework 的项目 需要选择 相应版本的 EF, 如果是跨平台则选择EF Core版本。 我这里选择的是 .net framework 版本。红框里面是 实现EF Code First 需要的包。 对应的版本: