Export 之 简单导出excel

  • A+
所属分类:.NET技术

选择第三方库

  • Epplus : 5.0后出现授权问题 out
  • Magicodes.IE : 基于Epplush 4.x , IExporterHeaderFilter 这个的性能很渣,而且动态调整order会出现顺序错乱 out
  • NPOI : 个人不是太喜欢
  • ClosedXML : 基于 Document.OpenXML ,性能不错但是需要自己封装一些业务功能 i like this

简单导出功能

//导出 protected override void Action() {     //创建workbook     var wb = new XLWorkbook(XLEventTracking.Disabled);     wb.Worksheets.Add("test", Datas);      wb.SaveAs($"{Guid.NewGuid()}.xlsx"); }   internal static class ClosedXMLExtension {     //添加IXLWorksheet扩展  你也可以基于函数封装     public static IXLWorksheet Add<T>(this IXLWorksheets wss, string sheetName, IEnumerable<T> datas)     {         var ws = wss.Add(sheetName);         var props = typeof(T).GetProperties();         int row = 1, col = 1;                  foreach (var data in datas)         {             foreach (var prop in props)             {                 ws.Cell(row, col).Value = prop.GetValue(data);                 col++;             }             col = 1;             row++;         }         return ws;     } }  

进一步封装

说明
  • 整体使用反射获取值向cell中填充
  • header可以动态控制,但是控制流实现的比较简单
  • 使用model字段的小写与动态header进行匹配
public static class ClosedXMLExtension {     /// <summary>     /// 向单个sheet填充数据     /// </summary>     /// <typeparam name="T"></typeparam>     /// <param name="wss">IXLWorksheets</param>     /// <param name="sheetName">sheet 名称(需要唯一)</param>     /// <param name="dataSource">数据源</param>     /// <returns></returns>     public static IXLWorksheet Add<T>(this IXLWorksheets wss, string sheetName, IEnumerable<T> dataSource, Dictionary<string, DynamicHeader> headers = null)     {         if (dataSource == null)             throw new ArgumentNullException(nameof(dataSource), "datasource cant be null");         if (string.IsNullOrEmpty(sheetName))             throw new ArgumentNullException(nameof(dataSource), "sheet's name cant be null");          //创建sheet         var ws = wss.Add(sheetName);          //如果header中没有数据,直接返回         if (headers != null && !headers.Any())             return ws;          var props = typeof(T).GetProperties();         headers = ChangeDynamicHeadersOrder(headers);          AddHeader(ws, headers == null ?             props.Select(x => x.Name) :             headers.Select(x => x.Value.DisplayName));          int row = 2, col = 1;          foreach (var data in dataSource)         {             foreach (var prop in props)             {                 if (headers == null)                 {                     ws.Cell(row, col).Value = prop.GetValue(data);                     col++;                 }                 else if (headers.TryGetValue(prop.Name.ToLower(), out var dynamicHeader))                     ws.Cell(row, dynamicHeader.Index).Value = prop.GetValue(data);             }              col = 1;             row++;         }          return ws;     }      /// <summary>     /// 添加表格头     /// </summary>     /// <param name="ws"></param>     /// <param name="headerNames"></param>     private static void AddHeader(IXLWorksheet ws, IEnumerable<string> headerNames)     {         int row = 1, col = 1;         foreach (var name in headerNames)         {             var cell = ws.Cell(row, col);             cell.Value = name;             cell.Style.Font.Bold = true;             cell.Style.Fill.SetBackgroundColor(XLColor.LightBlue);              col++;         }     }      /// <summary>     /// 修改header的顺序防止数据重叠     /// </summary>     /// <param name="headers"></param>     /// <returns></returns>     private static Dictionary<string, DynamicHeader> ChangeDynamicHeadersOrder(Dictionary<string, DynamicHeader> headers)     {         if (headers == null) return null;          var temp = headers             .OrderBy(x => x.Value.Index)             .Select((x, index) =>                 new KeyValuePair<string, DynamicHeader>(                     x.Key.ToLower(),                     new DynamicHeader() { Index = index + 1, DisplayName = x.Value.DisplayName }                 ));          return temp.ToDictionary(x => x.Key, x => x.Value);     } }  public class DynamicHeader {     /// <summary>     /// 序号     /// </summary>     public int Index { get; set; }      /// <summary>     /// Header显示名称     /// </summary>     public string DisplayName { get; set; } }