POI之EXCEL導出工具--PoiExportUtil入門優化篇--(三)
本篇章是對轉載自https://blog.csdn.net/Jack__Frost/article/details/77510892的入門篇進行了稍加改動,可供大家參考。
**********改動之處主要是:表格要展示的數據內容及字段順序 取決於 列標題字段。即:導出的數據順序以headersId為准;**************
文章結構:(1)面向JavaBean的導出工具;(2)面向List-Map結構的導出工具。
大家閱讀了前篇就知道Excel報表導出之JSP方式就是這么簡單了,查出數據直接對到jsp處理,樣式也可以在制作excel模板時自定義,相當簡單。但是我們要想當要導出大量數據的時候呢??難道我們也這樣實時導出??這樣一個正常系統而且在大量人使用的時候,對於系統的負載會非常非常高的,所以前篇我也給出了另一種方式:Excel報表導出之上傳文件流方式。在這樣的方式下,如何做出一個公用的適應各種情況的設計,這就是往后幾篇文章要探討的。
一、面向JavaBean的導出工具:
(一)設計的關鍵:
(1)兼容普通JavaBean;
(2)接口方法易用性;
(3)導出數據准確性;
(4)擴展性。
(二)基於POI抽象的關鍵步驟:
(1)設置表格標題
(2)設置標題欄
(3)設置內容欄(為了精確比對,需要給出標題欄對應的字段—DTO類(普通javabean)的屬性)
(4)導出寫入到流對象
(三)核心代碼與demo:
准備實體:(一個普通的JavaBean)
1 package com.etom.ebihm.module.rm.reportexport; 2 3 /** 4 * Created by zhaof on 2018/9/26. 5 */ 6 public class Student { 7 private int id; 8 private String name; 9 private String sex; 10 private String job; 11 12 public Student(int id, String name, String sex, String job) { 13 this.id = id; 14 this.name = name; 15 this.sex = sex; 16 this.job = job; 17 } 18 19 public String getJob() { 20 return job; 21 } 22 23 public void setJob(String job) { 24 this.job = job; 25 } 26 27 public int getId() { 28 return id; 29 } 30 31 public void setId(int id) { 32 this.id = id; 33 } 34 35 public String getName() { 36 return name; 37 } 38 39 public void setName(String name) { 40 this.name = name; 41 } 42 43 public String getSex() { 44 return sex; 45 } 46 47 public void setSex(String sex) { 48 this.sex = sex; 49 } 50 }
工具代碼:
1 package com.etom.ebihm.module.rm.reportexport; 2 3 import org.apache.poi.hssf.usermodel.*; 4 import org.apache.poi.ss.util.CellRangeAddress; 5 6 import java.io.FileNotFoundException; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 import java.lang.reflect.Field; 10 import java.lang.reflect.InvocationTargetException; 11 import java.lang.reflect.Method; 12 import java.util.*; 13 14 /** 15 * Created by zhaof on 2018/9/23. 16 */ 17 public class ExportBeanExcel<T> { 18 19 /** 20 * 這是一個通用的方法,利用了JAVA的反射機制,可以將放置在JAVA集合中並且符號一定條件的數據以EXCEL 的形式輸出 21 * <p> 22 * sheetName 表格sheet名稱 23 * headersName 表格屬性列名數組 24 * headersId 表格屬性列名對應的字段---你需要導出的字段名(為了更靈活控制你想要導出的字段) 25 * dtoList 需要顯示的數據集合,集合中一定要放置符合javabean風格的類的對象 26 * out 與輸出設備關聯的流對象,可以將EXCEL文檔導出到本地文件或者網絡中 27 * <p> 28 * dtoRow dtoList集合中每個對象記錄所在行序號(從1開始,第0行是列標題欄) 29 * zdCell 列標題字段所在單元格的列序號 30 */ 31 public void exportExcel(String sheetName, List<String> headersName, List<String> headersId, List<T> dtoList) { 32 /* 33 (一)表頭--標題欄 34 */ 35 Map<Integer, String> headersNameMap = new HashMap<>(); 36 int key = 0; 37 for (int i = 0; i < headersName.size(); i++) { 38 if (!headersName.get(i).equals(null)) { 39 headersNameMap.put(key, headersName.get(i)); 40 key++; 41 } 42 } 43 /* 44 (二)字段---標題對應的字段 45 */ 46 Map<Integer, String> headersFieldMap = new HashMap<>(); 47 int value = 0; 48 for (int i = 0; i < headersId.size(); i++) { 49 if (!headersId.get(i).equals(null)) { 50 headersFieldMap.put(value, headersId.get(i)); 51 value++; 52 } 53 } 54 /* 55 (三)聲明一個工作薄:包括構建工作簿、表格、樣式 56 */ 57 HSSFWorkbook wb = new HSSFWorkbook(); 58 HSSFSheet sheet = wb.createSheet(sheetName); 59 sheet.setDefaultColumnWidth(15); 60 // 生成一個樣式 61 HSSFCellStyle style = wb.createCellStyle(); 62 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 63 /* 64 合並第一行單元格標題 65 */ 66 HSSFRow row = sheet.createRow(0); 67 HSSFCell cell; 68 cell = row.createCell(0); 69 cell.setCellValue("學生基本信息表"); 70 cell.setCellStyle(style); 71 //CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) 72 wb.getSheet(sheetName).addMergedRegion(new CellRangeAddress(0,0,0,headersNameMap.size()-1)); 73 //創建列標題欄所在行 74 row = sheet.createRow(1); 75 76 Collection c = headersNameMap.values();//拿到表格所有列標題的value的集合 77 Iterator<String> it = c.iterator();//表格標題的迭代器 78 /* 79 (四)導出數據:包括導出標題欄以及內容欄 80 */ 81 //根據選擇的字段生成表頭 82 int size = 0; 83 while (it.hasNext()) { 84 cell = row.createCell(size); 85 cell.setCellValue(it.next().toString()); 86 cell.setCellStyle(style); 87 size++; 88 } 89 //表格列標題一行對應的字段的集合 90 Collection headersFieldCo = headersFieldMap.values(); 91 Iterator<T> labIt = dtoList.iterator();//總記錄的迭代器 92 int dtoRow = 2;//內容欄 導出數據dtoList的行序號 93 while (labIt.hasNext()) {//記錄的迭代器,遍歷總記錄 94 row = sheet.createRow(dtoRow); 95 dtoRow++; 96 T l = (T) labIt.next(); 97 // 利用反射,根據javabean屬性的先后順序,動態調用getXxx()方法得到屬性值 98 Field[] fields = l.getClass().getDeclaredFields();//獲得JavaBean全部屬性 99 for (short i = 0; i < fields.length; i++) {//遍歷屬性,比對 100 Field field = fields[i]; 101 String fieldName = field.getName();//屬性名 102 Iterator<String> zdIt = headersFieldCo.iterator();//一行列標題字段的集合的迭代器 103 int zdCell = 0; 104 while (zdIt.hasNext()) {//遍歷要導出的字段集合 105 if (zdIt.next().equals(fieldName)) {//比對JavaBean的屬性名,一致就寫入,不一致就丟棄 106 String getMethodName = "get" 107 + fieldName.substring(0, 1).toUpperCase() 108 + fieldName.substring(1);//拿到屬性的get方法 109 Class tCls = l.getClass();//拿到JavaBean對象 110 try { 111 Method getMethod = tCls.getMethod(getMethodName, 112 new Class[]{});//通過JavaBean對象拿到該屬性的get方法,從而進行操控 113 Object val = getMethod.invoke(l, new Object[]{});//操控該對象屬性的get方法,從而拿到屬性值 114 String textVal = null; 115 if (val != null) { 116 textVal = String.valueOf(val);//轉化成String 117 } else { 118 //字段內容值為null時,進行處理 119 textVal = ""; 120 } 121 row.createCell(zdCell).setCellValue(textVal);//寫進excel對象 122 } catch (SecurityException e) { 123 e.printStackTrace(); 124 } catch (IllegalArgumentException e) { 125 e.printStackTrace(); 126 } catch (NoSuchMethodException e) { 127 e.printStackTrace(); 128 } catch (IllegalAccessException e) { 129 e.printStackTrace(); 130 } catch (InvocationTargetException e) { 131 e.printStackTrace(); 132 } 133 }//if 134 zdCell++; 135 }//while 136 }//for 137 } 138 139 //行列分組 140 //wb.getSheet(sheetName).groupColumn(4, 7); 141 try { 142 FileOutputStream exportXls = new FileOutputStream("E://工單信息表.xls"); 143 wb.write(exportXls); 144 exportXls.close(); 145 System.out.println("導出成功!"); 146 } catch (FileNotFoundException e) { 147 System.out.println("導出失敗!"); 148 e.printStackTrace(); 149 } catch (IOException e) { 150 System.out.println("導出失敗!"); 151 e.printStackTrace(); 152 } 153 } 154 155 156 /*使用例子*/ 157 public static void main(String[] args) { 158 List<String> listName = new ArrayList<>(); 159 listName.add("id"); 160 listName.add("性別"); 161 listName.add("名字"); 162 List<String> listId = new ArrayList<>(); 163 listId.add("id"); 164 listId.add("sex"); 165 listId.add("name"); 166 List<Student> dotList = new ArrayList<>(); 167 dotList.add(new Student(111, "張三asdf", "男", "老師")); 168 dotList.add(new Student(121, null, "男2", "學生")); 169 dotList.add(new Student(131, "王五", "女", "醫生")); 170 171 172 ExportBeanExcel<Student> exportBeanExcelUtil = new ExportBeanExcel(); 173 exportBeanExcelUtil.exportExcel("測試POI導出EXCEL文檔", listName, listId, dotList); 174 175 } 176 }
導出excel效果圖:
(四)工具注意點:
(1)應用泛型,代表任意一個符合javabean風格的類
(2)注意這里為了簡單起見,boolean型的屬性xxx的get器方式為getXxx(),而不是isXxx()
(3) T這里代表一個不確定是實體類,即參數實體
二、面向List-Map結構的導出工具:
(一)設計的關鍵:
(1)兼容普通List-Map結構;
(2)接口方法易用性;
(3)導出數據准確性;
(4)擴展性。
(二)基於POI抽象的關鍵步驟:
(1)設置表格標題
(2)設置標題欄
(3)設置內容欄(為了精確比對,需要給出標題欄對應的字段—dtoList(List-Map結構中的key))
(4)導出寫入到流對象
(三)核心代碼與demo:
1 package com.etom.ebihm.module.rm.reportexport; 2 3 import org.apache.poi.hssf.usermodel.*; 4 import org.apache.poi.ss.util.CellRangeAddress; 5 6 import java.io.FileNotFoundException; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 import java.util.*; 10 11 /** 12 * Created by zhaof on 2018/9/27. 13 */ 14 public class ExportMapExcel { 15 public void exportExcel(String sheetName, List<String> headersName, List<String> headersId, 16 List<Map<String, Object>> dtoList) { 17 /* 18 (一)表頭--標題欄 19 */ 20 Map<Integer, String> headersNameMap = new HashMap<>(); 21 int key = 0; 22 for (int i = 0; i < headersName.size(); i++) { 23 if (!headersName.get(i).equals(null)) { 24 headersNameMap.put(key, headersName.get(i)); 25 key++; 26 } 27 } 28 /* 29 (二)字段---標題對應的字段 30 */ 31 Map<Integer, String> titleFieldMap = new HashMap<>(); 32 int value = 0; 33 for (int i = 0; i < headersId.size(); i++) { 34 if (!headersId.get(i).equals(null)) { 35 titleFieldMap.put(value, headersId.get(i)); 36 value++; 37 } 38 } 39 /* 40 (三)聲明一個工作薄:包括構建工作簿、表格、樣式 41 */ 42 HSSFWorkbook wb = new HSSFWorkbook(); 43 HSSFSheet sheet = wb.createSheet(sheetName); 44 sheet.setDefaultColumnWidth(15); 45 // 生成一個樣式 46 HSSFCellStyle style = wb.createCellStyle(); 47 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 48 /* 49 合並第一行單元格標題 50 */ 51 HSSFRow row = sheet.createRow(0); 52 HSSFCell cell; 53 cell = row.createCell(0); 54 cell.setCellValue("學生基本信息表Map"); 55 cell.setCellStyle(style); 56 //CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) 57 wb.getSheet(sheetName).addMergedRegion(new CellRangeAddress(0,0,0,headersNameMap.size()-1)); 58 //創建列標題欄所在行 59 row = sheet.createRow(1); 60 Collection c = headersNameMap.values();//拿到表格所有標題的value的集合 61 Iterator<String> headersNameIt = c.iterator();//表格標題的迭代器 62 /* 63 (四)導出數據:包括導出標題欄以及內容欄 64 */ 65 //根據選擇的字段生成表頭--標題 66 int size = 0; 67 while (headersNameIt.hasNext()) { 68 cell = row.createCell(size); 69 cell.setCellValue(headersNameIt.next().toString()); 70 cell.setCellStyle(style); 71 size++; 72 } 73 //表格一行的字段的集合,以便拿到迭代器 74 Collection headersFieldCo = titleFieldMap.values(); 75 Iterator<Map<String, Object>> dtoMapIt = dtoList.iterator();//總記錄的迭代器 76 int zdRow = 2;//內容欄 真正數據記錄的行序號 77 while (dtoMapIt.hasNext()) {//記錄的迭代器,遍歷總記錄 78 Map<String, Object> mapTemp = dtoMapIt.next();//拿到一條記錄 79 row = sheet.createRow(zdRow); 80 zdRow++; 81 int zdCell = 0; 82 Iterator<String> headersFieldIt = headersFieldCo.iterator();//一條記錄的字段的集合的迭代器 83 while (headersFieldIt.hasNext()) { 84 String tempField = headersFieldIt.next();//字段的暫存 85 if (mapTemp.get(tempField) != null) { 86 row.createCell(zdCell).setCellValue(String.valueOf(mapTemp.get(tempField)));//寫進excel對象 87 // zdCell++; 88 }else{ 89 //字段內容值為null時,進行處理 90 row.createCell(zdCell).setCellValue("*");//寫進excel對象 91 } 92 zdCell++; 93 } 94 } 95 //行列分組 96 //wb.getSheet(sheetName).groupColumn(4, 7); 97 try { 98 FileOutputStream exportXls = new FileOutputStream("E://工單信息表Map.xls"); 99 wb.write(exportXls); 100 exportXls.close(); 101 System.out.println("導出成功!"); 102 } catch (FileNotFoundException e) { 103 System.out.println("導出失敗!"); 104 e.printStackTrace(); 105 } catch (IOException e) { 106 System.out.println("導出失敗!"); 107 e.printStackTrace(); 108 } 109 } 110 111 public static void main(String[] args) { 112 113 List<String> listName = new ArrayList<>(); 114 listName.add("id"); 115 listName.add("性別"); 116 listName.add("名字"); 117 listName.add("職業"); 118 List<String> listId = new ArrayList<>(); 119 listId.add("id"); 120 listId.add("sex"); 121 listId.add("name"); 122 listId.add("job"); 123 124 List<Map<String, Object>> listB = new ArrayList<>(); 125 for (int t = 0; t < 6; t++) { 126 Map<String, Object> map = new HashMap<>(); 127 map.put("id", t); 128 map.put("name", "abc" + t); 129 map.put("sex", "男" + t); 130 map.put("job", "學生" + t); 131 listB.add(map); 132 } 133 Map<String, Object> map = new HashMap<>(); 134 map.put("id", 77); 135 map.put("name", "蛋蛋超人"); 136 map.put("sex", null); 137 map.put("job", null); 138 listB.add(map); 139 140 Map<String, Object> map2 = new HashMap<>(); 141 map2.put("id", 88); 142 map2.put("name", "笨笨"); 143 map2.put("sex", null); 144 map2.put("job", null); 145 listB.add(map2); 146 147 System.out.println("listB : " + listB.toString()); 148 ExportMapExcel exportExcelUtil = new ExportMapExcel(); 149 exportExcelUtil.exportExcel("測試POI導出EXCEL文檔", listName, listId, listB); 150 151 } 152 }
導出excel效果圖: