NPOI操做EXCEL(四)——反射機制批量導出excel文件

前面咱們已經實現了反射機制進行excel表格數據的解析,既然有上傳就得有下載,咱們再來寫一個通用的導出方法,利用反射機制實現對系統全部數據列表的篩選結果導出excel功能。node

 

咱們來構想一下這樣一個畫面,管理員篩選出北京的全部員工數據,想導出成excel表格;管理員篩選出北京全部欠費的企業數據,想導出成excel表格;管理員想導出本月的工單報表到excel表格;管理員想導出近3月北京各崗位的運營報表到excel表格......工具

系統客服真是個神奇的職業,神馬都想導出到excel表格!字體

那麼對於咱們的程序來講,該怎麼作呢!因爲每一個導出功能對應的數據源都不同,簡單的方法很難作到,只能每一個業務單寫一個導出功能。spa

 

因此,咱們再次沿用導入時使用的xml文件配置作橋樑,經過反射技術作具體實現的方法,作一個通用的EXCEL導出工具:傳入DTO數據集合與xml規則集,返回excel文件流。excel

 

1.咱們建立一個xml文件,裏面存放全部須要導出功能涉及字段的規則集(博主項目涉及到的導出功能也就10來個列表,約涉及100多個字段(這兒未所有列出),故未分開成多個xml規則文件)code

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>

注:xml

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規則集的方法blog

 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個表單(一、東三省所有數據;二、遼寧省數據;三、吉林省數據;四、黑龍江省數據))

參數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的導入,會在下一篇博文貼出具體實現的代碼,敬請期待~~~

 

原創文章,代碼都是從本身項目裏貼出來的。轉載請註明出處哦,親~~~

相關文章
相關標籤/搜索