POI之EXCEL導出工具--PoiExportUtil入門優化篇--(三)


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效果圖:

 

(四)工具注意點:

(1)面向的是List-Map數據結構,請不要注入別的數據結構

(2)方法參數說明:

1)title是:表格的名稱
2)headersName標題欄的文字
3)headersId:對應標題欄的字段,為了准確導出到對應列而設計
4)dtoList:我們要導出的所有數據(把數據封裝在dtoList數據傳輸對象中)

(3)此處的入門篇工具兼容性並不很好,只是講解了工具的核心。博客抽象的工具是以這兩個demo工具為基准點去設計的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM