使用C#和NPOI实现Excel导出功能

在.NET开发中,经常需要实现将数据导出到Excel文件的功能。本文将介绍如何使用C#和NPOI库在ASP.NET MVC环境中实现这一功能。

准备工作

在开始之前,需要了解本文的核心概念:通过引入NPOI库,可以轻松地将数据导出到Excel文件。为了实现这一功能,将创建两个C#文件,并将它们包含在示例项目中。

探索代码

为了更好地理解实现过程,创建了一个GitHub仓库,其中包含了使用ASP.NET MVC的代码示例。可以通过以下链接访问这个仓库:

使用NPOI DLL来实现Excel导出功能,这是免费的。可以在NPOI的NuGet页面找到更多详细信息。

在开发过程中,经常需要实现将数据导出到Excel的功能。许多人通常会使用StringBuilder,然后将其转换为Excel,或者使用Interop、ITextSharp或NPOI等其他方法来实现。这些方法在各自的上下文中都是正确的,但如果有一种方法可以像传递对象一样简单,就可以得到所需的输出,生活将变得更加轻松。

使用代码

首先,有一个名为Export()的实用函数,它将C#List对象转换为NPOI对象,然后最终提供HttpResponseMessage类型,这可以在WEB API Action中使用。

为了实现这一点,需要两个文件,可以在本文附加的解决方案中找到它们:

  • ExcelExport文件夹在根目录下:
  • AbstractDataExport.cs - 包含通用代码
  • AbstractDataExportBridge.cs - 将List转换为NPOI Excel对象

让从第一个文件AbstractDataExport.cs开始。

创建一个新的Excel对象:

_workbook = new XSSFWorkbook();

创建一个新的Excel工作表对象:

_sheet = _workbook.CreateSheet(_sheetName);

调用WriteData() - 稍后解释

最后,创建并返回MemoryStream对象:

using (var memoryStream = new MemoryStream())

创建MemoryStream

在AbstractDataExport.cs中,定义了一个接口IAbstractDataExport,它包含一个Export方法,用于导出数据。还定义了一个抽象类AbstractDataExport,它实现了这个接口。

现在,让继续第二个也是最后一个文件,即AbstractDataExportBridge.cs。以下是WriteData(List exportData)的解释:

将List转换为DataTable,使用Reflection读取属性名称,列标题将来自这里。遍历DataTable以创建Excel行。

在这个过程中,有一些改进的余地,可以根据需要进行必要的更改,例如完全去除DataTable。

代码示例

以下是AbstractDataExport.cs的代码示例:

using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; namespace GenericExcelExport.ExcelExport { public interface IAbstractDataExport { HttpResponseMessage Export(List exportData, string fileName, string sheetName); } public abstract class AbstractDataExport : IAbstractDataExport { protected string _sheetName; protected string _fileName; protected List _headers; protected List _type; protected IWorkbook _workbook; protected ISheet _sheet; private const string DefaultSheetName = "Sheet1"; public HttpResponseMessage Export(List exportData, string fileName, string sheetName = DefaultSheetName) { _fileName = fileName; _sheetName = sheetName; _workbook = new XSSFWorkbook(); _sheet = _workbook.CreateSheet(_sheetName); var headerStyle = _workbook.CreateCellStyle(); var headerFont = _workbook.CreateFont(); headerFont.IsBold = true; headerStyle.SetFont(headerFont); WriteData(exportData); Header var header = _sheet.CreateRow(0); for (var i = 0; i < _headers.Count; i++) { var cell = header.CreateCell(i); cell.SetCellValue(_headers[i]); cell.CellStyle = headerStyle; _sheet.AutoSizeColumn(i); } using (var memoryStream = new MemoryStream()) { _workbook.Write(memoryStream); var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(memoryStream.ToArray()) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = $"{_fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx" }; return response; } } public abstract void WriteData(List exportData); } }

以下是AbstractDataExportBridge.cs的代码示例:

using NPOI.SS.UserModel; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Text.RegularExpressions; namespace GenericExcelExport.ExcelExport { public class AbstractDataExportBridge : AbstractDataExport { public AbstractDataExportBridge() { _headers = new List(); _type = new List(); } public override void WriteData(List exportData) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T)); DataTable table = new DataTable(); foreach (PropertyDescriptor prop in properties) { var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; _type.Add(type.Name); table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); string name = Regex.Replace(prop.Name, "([A-Z])", "$1").Trim(); _headers.Add(name); } foreach (T item in exportData) { DataRow row = table.NewRow(); foreach (PropertyDescriptor prop in properties) row[prop.Name] = prop.GetValue(item) ?? DBNull.Value; table.Rows.Add(row); } IRow sheetRow = null; for (int i = 0; i < table.Rows.Count; i++) { sheetRow = _sheet.CreateRow(i + 1); for (int j = 0; j < table.Columns.Count; j++) { ICell Row1 = sheetRow.CreateCell(j); string cellvalue = Convert.ToString(table.Rows[i][j]); if (string.IsNullOrWhiteSpace(cellvalue)) { Row1.SetCellValue(string.Empty); } else if (_type[j].ToLower() == "string") { Row1.SetCellValue(cellvalue); } else if (_type[j].ToLower() == "int32") { Row1.SetCellValue(Convert.ToInt32(table.Rows[i][j])); } else if (_type[j].ToLower() == "double") { Row1.SetCellValue(Convert.ToDouble(table.Rows[i][j])); } else if (_type[j].ToLower() == "datetime") { Row1.SetCellValue(Convert.ToDateTime(table.Rows[i][j]).ToString("dd/MM/yyyy hh:mm:ss")); } else { Row1.SetCellValue(string.Empty); } } } } } }

注意事项

当需要为20多个表单提供Excel导出功能时,遇到了这个解决方案,不愿意使用传统的方法,因为这将非常耗时。

在所有事物中,总有改进的余地。如果看到任何改进的地方,请在评论中更新。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485