转载

NPOI操作EXCEL(四)——反射机制批量导出excel文件

前面我们已经实现了反射机制进行excel表格数据的解析,既然有上传就得有下载,我们再来写一个通用的导出方法,利用反射机制实现对系统所有数据列表的筛选结果导出excel功能。

我们来构想一下这样一个画面,管理员筛选出北京的所有员工数据,想导出成excel表格;管理员筛选出北京所有欠费的企业数据,想导出成excel表格;管理员想导出本月的工单报表到excel表格;管理员想导出近3月北京各岗位的运营报表到excel表格......

系统客服真是个神奇的职业,神马都想导出到excel表格!

那么对于我们的程序来说,该怎么做呢!由于每个导出功能对应的数据源都不一样,简单的方法很难做到,只能每个业务单写一个导出功能。

所以,我们再次沿用导入时使用的xml文件配置做桥梁,通过反射技术做具体实现的方法,做一个通用的EXCEL导出工具:传入DTO数据集合与xml规则集,返回excel文件流。

1.我们创建一个xml文件,里面存放所有需要导出功能涉及字段的规则集(博主项目涉及到的导出功能也就10来个列表,约涉及100多个字段(这儿未全部列出),故未分开成多个xml规则文件)

1 <?xml version="1.0" encoding="utf-8" ?> 2 <module> 3   <add ExportFieldName="姓名"                   PropertyName="Name"                                       DataType="System.String"/> 4   <add ExportFieldName="手机号码"               PropertyName="PhoneNumber"                                DataType="System.String"/> 5   <add ExportFieldName="性别"                   PropertyName="Sex"                                        DataType="System.String"/> 6   <add ExportFieldName="民族"                   PropertyName="Nation"                                     DataType="System.String"/> 7   <add ExportFieldName="出生日期"               PropertyName="Birthday"                                   DataType="System.String"/> 8   <add ExportFieldName="身份证号码"             PropertyName="Cardid"                                     DataType="System.String"/> 9 </module>

注:

1.导出的规则相对简单,所以我们创建一个简单的规则集类:

 1     /// <summary>  2     /// 导出excel-中英文规则类  3     /// </summary>  4     public class ExportRegular  5     {  6         /// <summary>  7         /// 属性名称(英文)  8         /// </summary>  9         public string PropertyName { get; set; } 10  11         /// <summary> 12         /// 数据类型 13         /// </summary> 14         public string DataType { get; set; } 15  16         /// <summary> 17         /// 导出名称(中文) 18         /// </summary> 19         public string ExportFieldName { get; set; } 20     }

2.然后是解析XML规则集的方法

 1         /// <summary>  2         /// 解析XML规则集文件  3         /// </summary>  4         /// <returns></returns>  5         public static List<ExportRegular> GetExportRegulars()  6         {  7             var result = new List<ExportRegular>();  8   9             var reader = new XmlTextReader(xmlpath); 10             var doc = new XmlDocument(); 11             //从指定的XMLReader加载XML文档 12             doc.Load(reader); 13  14             foreach (XmlNode node in doc.DocumentElement.ChildNodes) 15             { 16                 var header = new ExportRegular(); 17  18                 if (node.Attributes["PropertyName"] != null) 19                     header.PropertyName = node.Attributes["PropertyName"].Value; 20                 if (node.Attributes["DataType"] != null) 21                     header.DataType = node.Attributes["DataType"].Value; 22                 if (node.Attributes["ExportFieldName"] != null) 23                     header.ExportFieldName = node.Attributes["ExportFieldName"].Value; 24  25                 result.Add(header); 26             } 27  28             return result; 29         }

2.我们的excel导出工具对外暴露两个静态方法:

1 public static MemoryStream CreateExcelStreamByDatas(List<object> objectDatas, KeyValuePair<string, string> excelHeader) 2  3 public static MemoryStream CreateExcelStreamByDatas(List<KeyValuePair<List<object>, KeyValuePair<string, string>>> objectDatass)

一个是单sheet表单导出接口,一个是多表单导出接口(例:管理员导出东三省的员工数据,则导出excel含4个表单(1、东三省全部数据;2、辽宁省数据;3、吉林省数据;4、黑龙江省数据))

参数objectDatas是从库中筛选到的结果DTO数据集,excelHeader是一个键值对:key-表头名称,value-sheet表单名称

3.我们具体来看单表单方法的实现:

 1         /// <summary>  2         /// 将数据转换成excel文件流输出  ->单表单导出接口  3         /// </summary>  4         /// <returns></returns>  5         public static MemoryStream CreateExcelStreamByDatas(List<object> objectDatas, KeyValuePair<string, string> excelHeader)  6         {  7             // 返回对象  8             var ms = new MemoryStream();  9  10             // excel工作簿 11             IWorkbook workbook = new HSSFWorkbook(); 12             //导入数据到sheet表单 13             CreateExcelSheetByDatas(objectDatas, excelHeader.Key, excelHeader.Value, ref workbook); 14  15             workbook.Write(ms); 16             ms.Flush(); 17             ms.Position = 0; 18  19             return ms; 20         }

我们将具体功能逻辑抽象到了方法CreateExcelSheetByDatas中,

那么多表单的实现只需要修改第13行为:

1             foreach (KeyValuePair<List<object>, KeyValuePair<string, string>> keyValuePair in objectDatass) 2             { 3                 //导入数据到sheet表单 4                 CreateExcelSheetByDatas(keyValuePair.Key, keyValuePair.Value.Key, keyValuePair.Value.Value, ref workbook); 5             }

4.我们来实现最核心的方法CreateExcelSheetByDatas(博主还没来得及重构代码,所有逻辑都写在里面了,略长...)

  1         /// <summary>   2         /// 根据传入数据新建sheet表单到指定workbook   3         /// </summary>   4         /// <param name="objectDatas"></param>   5         /// <param name="excelHeader"></param>   6         /// <param name="sheetName"></param>   7         /// <param name="regulars"></param>   8         /// <param name="workbook"></param>   9         private static void CreateExcelSheetByDatas(List<object> objectDatas, string excelHeader, string sheetName, ref IWorkbook workbook)  10         {  11             var regulars = GetExportRegulars();  12   13             // excel sheet表单  14             ISheet sheet = workbook.CreateSheet(sheetName);  15             // excel行数  16             int rows = 0;  17   18             #region 单元格 -表头格式  19   20             #region 表头字体  21   22             IFont fontTitle = workbook.CreateFont();  23             fontTitle.FontHeightInPoints = 12;  24             fontTitle.Boldweight = (short)FontBoldWeight.BOLD;  25   26             #endregion  27   28             ICellStyle styleTitle = workbook.CreateCellStyle();  29             styleTitle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER;  30             styleTitle.SetFont(fontTitle);  31             styleTitle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.CENTER;  32   33             #endregion  34   35             #region 单元格 -表体格式  36   37             #region 表体字体  38   39             IFont fontMessage = workbook.CreateFont();  40             fontMessage.FontHeightInPoints = 10;  41   42             #endregion  43   44             ICellStyle styleMessage = workbook.CreateCellStyle();  45             styleMessage.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER;  46             styleMessage.SetFont(fontMessage);  47             styleMessage.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.CENTER;  48   49             #endregion  50   51             // 创建表头并赋值  52             int firstRowCellCount = GetAttributeCount(objectDatas.First());  53             IRow headerRow = sheet.CreateRow(rows);  54             headerRow.HeightInPoints = 40;  55             var headerCell = headerRow.CreateCell(0);  56             headerCell.SetCellValue(excelHeader);  57   58             // 合并表头  59             var cellRangeAddress = new CellRangeAddress(rows, rows, 0, firstRowCellCount - 1);  60             sheet.AddMergedRegion(cellRangeAddress);  61             // 设置表头格式  62             headerCell.CellStyle = styleTitle;  63   64   65             //生成表头  66             if (objectDatas.Any())  67             {  68                 rows++;  69                 // excel列数  70                 int cells = -1;  71                 // 创建数据行  72                 var firstRow = sheet.CreateRow(rows);  73                 firstRow.HeightInPoints = 16;  74                 var objectData = objectDatas.FirstOrDefault();  75                 foreach (System.Reflection.PropertyInfo p in objectData.GetType().GetProperties())  76                 {  77                     cells++;  78                     var regular = regulars.Find(t => t.PropertyName == p.Name);  79                     if (regular == null)  80                     {  81                         throw new Exception("导出excel时,出现未配置字段。表:" + objectData.GetType().Name + ",字段:" + p.Name);  82                     }  83                     var firstRowCell = firstRow.CreateCell(cells);  84                     firstRowCell.SetCellValue(regular.ExportFieldName);  85                     sheet.SetColumnWidth(cells, regular.ExportFieldName.Length * 256 * 4);  86                     firstRowCell.CellStyle = styleMessage;  87                 }  88             }  89   90             // 反射object对象,遍历字段  91             foreach (var objectData in objectDatas)  92             {  93                 rows++;  94                 // excel列数  95                 int cells = -1;  96                 // 创建数据行  97                 var messageRow = sheet.CreateRow(rows);  98                 messageRow.HeightInPoints = 16;  99                 foreach (System.Reflection.PropertyInfo p in objectData.GetType().GetProperties()) 100                 { 101                     cells++; 102                     var regular = regulars.Find(t => t.PropertyName == p.Name); 103                     var messageCell = messageRow.CreateCell(cells); 104                     var value = p.GetValue(objectData); 105                     if (value == null) 106                     { 107                         messageCell.SetCellValue(""); 108                     } 109                     else 110                     { 111                         switch (regular.DataType) 112                         { 113                             case "datetime": 114                                 if (Convert.ToDateTime(value) == DateTime.MinValue) 115                                 { 116                                     messageCell.SetCellValue(""); 117                                 } 118                                 else 119                                 { 120                                     messageCell.SetCellValue( 121                                         Convert.ToDateTime(value).ToString("yyyy-MM-dd HH:mm:ss")); 122                                 } 123                                 break; 124                             case "int": 125                                 messageCell.SetCellValue(Convert.ToInt32(value)); 126                                 break; 127                             case "double": 128                                 messageCell.SetCellValue(Convert.ToDouble(value)); 129                                 break; 130                             case "bool": 131                                 var setValue = ""; 132                                 if (!(bool)value) 133                                 { 134                                     setValue = ""; 135                                 } 136                                 messageCell.SetCellValue(setValue); 137                                 break; 138                             default: 139                                 messageCell.SetCellValue(value.ToString()); 140                                 break; 141                         } 142                     } 143                     messageCell.CellStyle = styleMessage; 144                 } 145             } 146         }

注:

1.第18到62行均是对表体、表头字体格式的指定,并创建合并表头名称

2.第66行到88行是在遍历DTO属性,按规则集取出对应中文名称创建表头字段

此处特别说明:博主把所有导出DTO的所有属性字段都是做的简单类型字段,方便做反射。

3.第52行GetAttributeCount方法,是获取DTO对象所有属性个数

4.第91行到145行是按规则集规则将DTO中对应数据写进excel单元格

至此,我们就实现了将DTO集合按规则集导出到excel表格的方法。

我们只需要在各个导出服务中,先查库获取到需要的数据集合,再Map到DTO集合中,作为参数调用EXCEL导出方法即可返回需要的excel文件流。

到这儿,NPOI操作简单模板excel进行导入导出的相关代码就贴完了。如有什么地方写的不对或不好,欢迎指出,一定虚心请教~~~

上一篇博文说到的那些反人类的excel的导入,会在下一篇博文贴出具体实现的代码,敬请期待~~~

原创文章,代码都是从自己项目里贴出来的。转载请注明出处哦,亲~~~

正文到此结束
Loading...