[Investor Relations]  |  官方微博

.NET培训

美国上市公司 · 亿元级外企Java培训企业

  • 全国服务监督电话4008270010
.Net培训 > NET学习笔记 > .NET开发工具之Excel导出公共类
  • .NET开发工具之Excel导出公共类

    发布:.Net培训  来源:NET学习笔记  时间: 2016年11月28日

  • .NET开发工具做一个列表的Excel导出功能。并且有很多页面都会使用这个功能。...

  • 最近接了一个任务,就是做一个列表的Excel导出功能。并且有很多页面都会使用这个功能。

    导出的Excel大体格式如图

    excel导出公共类

    很简单的列表,标题加背景色,然后不同类型,显示方式不一样。对齐方式不一样。不同页面除了内容以外,大体形式都差不多。

    当时本来是想直接用NPOI,IRow ICell。这样进行拼接页面,最简单也最方便。

    但是很多页面,都进行这种类似的设计。我实在是懒得做这种重复功能。所以花了一点时间,整理了一下帮助类。

    使用

    做好这个帮助类以后只要进行两点调用

    1.制作导出Excel的数据模型。这个没办法,毕竟要告诉系统,你要导出的内容都是什么东西。省略不了。

    2.调用帮助类的导出方法。初始化一下,ExportExcel(导出的数据集合); 然后Excel就直接下载完毕了。

    ExcelDownload downLoad = new ExcelDownload("员工信息", "年度员工汇总");

    downLoad.ExportExcel(testList);

    思路和过程

    接着,说一下我的思路和具体写法。做的不到,想的不周全的地方。还希望各位告知。源码地址在文章结尾处。

    帮助类

    因为我想做成使用最简单的类,所以我只暴露一个公共方法。其余一切都进行隐藏。

    但是因为可能需要导出的其他格式的Excel,那么我也可以接受一个自定义的Excel填充方法。

    这里我定义一个ExportExcel方法接受数据集合。并且添加一个重载方法,接受自定义Excel填充方法。

    导出方法

    ///

    /// 导出Excel

    ///

    /// 导出模型数据

    public void ExportExcel(IEnumerable list)

    {

    GenerateExcel(list);

    DownLoadExcel();

    }

    ///

    /// 导出Excel

    ///

    /// 操作Excel方法

    public void ExportExcel(Action excelSetMethod)

    {

    excelSetMethod.Invoke(hssfWork, hssfSheet);

    DownLoadExcel();

    }

    方法里面的私有方法,稍后会详细说明。这里调用这一个方法,普通导出和自定义导出,均可实现。

    模型和样式

    首先要考虑的问题就是单元格的样式问题和列头名称问题。

    如果不是公共方法,就非常简单了,直接在方法里面ICellStyle。但是既然是偷懒,肯定不能这样,而且又要考虑到可以自定义。

    那么,我采用的方法就是给模型实体类使用Attribute。可以在实体类上面针对不同字段,设定不同的显示样式。

    缺点也很显而易见,使用反射执行效率会稍微慢一点(各位有其他方法可以说一下)。

    实体类的定义就如同下面

    public class UserManagerTest

    {

    [ExcelInfo("名称")]

    public string Name { get; set; }

    [ExcelInfo("年龄", ExcelStyle = ExcelStyle.left)]

    public int Old { get; set; }

    [ExcelInfo("金额", ExcelStyle = ExcelStyle.money)]

    public double Money { get; set; }

    [ExcelInfo("时间", ExcelStyle = ExcelStyle.date | ExcelStyle.right)]

    public DateTime CreateDate { get; set; }

    }

    可以定义中文名称显示标题、设置单元格样式、设置单元格宽度。

    目前允许自定义的就这三个。

    单元格特性

    public class ExcelInfoAttribute : Attribute

    {

    ///

    /// 显示中文名

    ///

    public string Name { get; set; }

    ///

    /// 列宽

    ///

    public int Width { get; set; }

    ///

    /// 列样式

    ///

    public ExcelStyle ExcelStyle { get; set; }

    ///

    /// 默认左对齐,宽度2800

    ///

    public ExcelInfoAttribute(string name)

    {

    Name = name;

    Width = 2800;

    ExcelStyle = ExcelStyle.left;

    }

    }

    ExcelStyle,是列样式的一个枚举,针对不同的值,会进行不同的单元格设置。

    因为有可能一个单元格进行多种设置,例如时间格式并且右对齐。所以使用Flags,让其可以形成组。

    样式枚举

    [Flags]

    public enum ExcelStyle

    {

    ///

    /// 标题灰色背景

    ///

    title = 0x001,

    ///

    /// 左对齐

    ///

    left = 0x002,

    ///

    /// 右对齐

    ///

    right = 0x004,

    ///

    /// 时间格式,右对齐

    ///

    date = 0x008,

    ///

    /// 金钱格式,右对齐

    ///

    money = 0x016

    }

    样式有了接下来就要把他对应成ICellStyle单元格样式,这样才能具体的进行操作。

    这个时候,我们就需要一个针对样式枚举,返回单元格样式的方法。

    这样方法会进行以下几点操作

    设置单元格通用的属性。我这里设置的是单元格边框。

    针对Flags组,分别进行对应的单元格设定,并且最终返回一个ICellStyle。

    单元格设定,因为样式会很多。所以这里使用了多态代替判断条件。 并且使用了一个键值对,来实现享元设计模式的思路。

    Excel样式操作

    internal static class ExcelStyleMessage

    {

    ///

    /// 样式集合

    ///

    private static Dictionary styleList { get; set; }

    static ExcelStyleMessage()

    {

    styleList = new Dictionary();

    }

    ///

    /// 获取枚举对应CellStyle

    ///

    /// Excel样式枚举

    ///

    internal static ICellStyle GetCellStyle(T workbook, ExcelStyle excelStyle) where T : IWorkbook

    {

    if (styleList.ContainsKey(excelStyle.ToString()))

    {

    return styleList[excelStyle.ToString()];

    }

    ICellStyle _cellStyle = workbook.CreateCellStyle();

    _cellStyle.BorderTop = BorderStyle.Thin;

    _cellStyle.BorderRight = BorderStyle.Thin;

    _cellStyle.BorderLeft = BorderStyle.Thin;

    _cellStyle.BorderBottom = BorderStyle.Thin;

    CellStyleMethod styleMethod;

    if (excelStyle.ToString().IndexOf(',') > -1)

    {

    foreach (var styleItem in excelStyle.ToString().Replace(" ", "").Split(','))

    {

    if (Enum.IsDefined(typeof(ExcelStyle), styleItem))

    {

    ExcelStyle styleModel = (ExcelStyle)Enum.Parse(typeof(ExcelStyle), styleItem, true);

    styleMethod = GetStyleMethod(styleModel);

    styleMethod.SetCell(_cellStyle);

    }

    }

    return _cellStyle;

    }

    styleMethod = GetStyleMethod(excelStyle);

    styleMethod.SetCell(_cellStyle);

    styleList.Add(excelStyle.ToString(), _cellStyle);

    return _cellStyle;

    }

    ///

    /// 根据枚举加载对应操作类

    ///

    /// 样式枚举

    /// 操作类

    private static CellStyleMethod GetStyleMethod(ExcelStyle excelStyle)

    {

    switch (excelStyle)

    {

    case ExcelStyle.title:

    return new TitleBackgroundMethod();

    case ExcelStyle.left:

    return new LeftAligmentMethod();

    case ExcelStyle.right:

    return new RightAligmentMethod();

    case ExcelStyle.date:

    return new DateFormatMethod();

    case ExcelStyle.money:

    return new MoneyFormatMethod();

    default:

    throw new ArgumentException("参数无效");

    }

    }

    }

    具体样式的多态,我就不粘贴了。就是一个很简单的抽象类,然后集成实现SetCell。

    抽象类定义了workbook字段,用于创建IDataFormat。具体可以看最底下的源码地址。

    帮助类思路

    首先考虑一下需要全局的字段和属性。Excel名称,页签名称,IWorkbook,ISheet。

    那么,我们定义这四个,并且在构造函数里给他们赋值。

    构造函数

    private readonly string _excelName;

    private readonly string _excelSheetName;

    private IWorkbook hssfWork { get; set; }

    private ISheet hssfSheet { get; set; }

    ///

    /// 初始化Excel相关信息

    ///

    /// Excel名称

    /// 初始页签名称

    public ExcelDownload(string ExcelName, string ExcelSheetName)

    {

    _excelName = ExcelName;

    _excelSheetName = ExcelSheetName;

    hssfWork = new HSSFWorkbook();

    hssfSheet = hssfWork.CreateSheet(_excelSheetName);

    }

    自定义的Excel填充,就是一个执行然后下载。我们忽略,说一下通用的方法。

    public void ExportExcel(IEnumerable list)

    {

    GenerateExcel(list);

    DownLoadExcel();

    }

    执行两个方法,1.生成Excel,2.下载Excel

    生成Excel

    在生成方法里面,我们给样式的workbook赋值,然后设置Excel的列表和单元格内容。

    private void GenerateExcel(IEnumerable list)

    {

    if (list == null)

    {

    return;

    }

    CellStyleMethod.workbook = hssfWork;

    Dictionary _excelInfos = GetPropInfo();

    SetExcelTitle(_excelInfos);

    SetExcelContent(list, _excelInfos);

    }

    GetPropInfo 是一个反射的方法,反射实体类中的特性,并返回属性和样式特性的键值对。这个在设置里面会有用途。

    GetPropInfo

    private Dictionary GetPropInfo()

    {

    Dictionary _infos = new Dictionary();

    Type _type = typeof(T);

    PropertyInfo[] _propInfos = _type.GetProperties();

    foreach (var propInfo in _propInfos)

    {

    object[] objAttrs = propInfo.GetCustomAttributes(typeof(ExcelInfoAttribute), true);

    if (objAttrs.Length > 0)

    {

    ExcelInfoAttribute attr = objAttrs[0] as ExcelInfoAttribute;

    if (attr != null)

    {

    _infos.Add(propInfo, attr);

    }

    }

    }

    return _infos;

    }

    SetExcelTitle 是设置Excel的标题。

    SetTitle

    private void SetExcelTitle(Dictionary excelInfos)

    {

    IRow rowTitle = hssfSheet.CreateRow(0);

    int _cellIndex = 0;

    foreach (var item in excelInfos)

    {

    ICell celltitle = rowTitle.CreateCell(_cellIndex);

    celltitle.CellStyle = ExcelStyleMessage.GetCellStyle(hssfWork, ExcelStyle.title);

    celltitle.SetCellValue(item.Value.Name);

    hssfSheet.SetColumnWidth(_cellIndex, item.Value.Width);

    _cellIndex++;

    }

    }

    SetExcelContent 是设置Excel的内容

    SetContent

    private void SetExcelContent(IEnumerable list, Dictionary _excelInfos)

    {

    int _rowNum = 1;

    Dictionary cellStyleList = new Dictionary();

    foreach (T rowItem in list)

    {

    int _rowCell = 0;

    IRow _rowValue = hssfSheet.CreateRow(_rowNum);

    foreach (var cellItem in _excelInfos)

    {

    object _cellItemValue = cellItem.Key.GetValue(rowItem);

    ICell _cell = _rowValue.CreateCell(_rowCell);

    if (!cellStyleList.ContainsKey(cellItem.Value.ExcelStyle.ToString()))

    {

    ICellStyle _cellStyle = ExcelStyleMessage.GetCellStyle(hssfWork, cellItem.Value.ExcelStyle);

    cellStyleList.Add(cellItem.Value.ExcelStyle.ToString(), _cellStyle);

    }

    SetCellValue(cellItem, _cellItemValue, _cell);

    _cell.CellStyle = cellStyleList[cellItem.Value.ExcelStyle.ToString()];

    _rowCell++;

    }

    _rowNum++;

    }

    }

    这里就是使用键值对的属性,来获取Value值的。然后因为返回的object,所以我们进行一下类型转换。

    SetCellValue 就是根据Type,来进行强制转换。

    下载Excel

    下载就更简单了,我们使用FileStream,进行一个临时存储。将NPOI写入这个文件中。然后将其转换成字节流,输出出来。

    下载方法

    ///

    /// 导出Excel操作

    ///

    private void DownLoadExcel()

    {

    string _path = TemporarySave();

    FileStream fileStream = new FileStream(_path, FileMode.Open);

    int fileContent = (int)fileStream.Length;

    byte[] byData = new byte[fileContent];

    fileStream.Read(byData, 0, fileContent);

    fileStream.Close();

    File.Delete(_path);

    DownLoadExcel(byData);

    }

    ///

    /// 临时保存

    ///

    ///

    private string TemporarySave()

    {

    string _path = AppDomain.CurrentDomain.BaseDirectory;

    _path += string.Format(@"\TemporarySave{0}.xlsx", DateTime.Now.ToString("hhmmss"));

    using (FileStream file = new FileStream(_path, FileMode.Create))

    {

    hssfWork.Write(file);

    file.Close();

    }

    return _path;

    }

    ///

    /// 下载

    ///

    private void DownLoadExcel(byte[] byData)

    {

    HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}.xls", _excelName));

    HttpContext.Current.Response.BinaryWrite(byData);

    HttpContext.Current.Response.Flush();

    HttpContext.Current.Response.Close();

    }

    至此,这个帮助类的雏形,就算完成了。

  • 上一篇:5个独特的.Net服务器框架

    下一篇:.Net 基础开发这一点你必须知道

相关资讯
网站导航
2001-2016 达内时代科技集团有限公司 版权所有 京ICP证8000853号-56