POI導入導出及動態復雜表頭生成


 在此之前打開POI分類已存在三篇文章介紹了POI的使用及流下載,近期項目發現之前的使用中是有缺陷的,今天做一下總結,從現在起我們可以忽略前三篇文章對POI的使用,但是流下載方式還是可以參考的,這里還是再提一筆,流下載使用ajax會出異常,不生效,我是用的是提交form表單的方式來進行流下載,很遺憾,暫時取不到返回值

       下面我們繼續談一下POI的使用

       首先需要強調幾點,POI對於Excel2003和Excel2007+是區別對待的,分別使用了HSSFWorkbook和XSSFWorkbook,但它們實現了同一個接口Workbook,這對我們的編程實現提供了一定的靈活性

   建議:對於導出,我們直接使用XSSFWorkbook即可,HSSFWorkbook是存在一定缺陷,之前使用過HSSFWorkbook,數據量達到65536就會報錯導出失敗,近期做新的項目才發現原因

   相對於導入工作,需要動態對文件識別Excel2003或是Excel2007+,有些文章寫到通過后綴名來辨別,這存在一個問題,用戶修改后綴之后,結果可想而知,幸虧POI提供了一個便利的方法Workbook create(InputStream inp),通過輸入流動態創建,GOOD!!!下面,我也會提供相關的用法。在這里還要給一個提示,使用3.9版本這種方法報錯,在此,我來提供一個maven info

 

            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>3.15</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>3.15</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>3.15</version>
            </dependency>

沒錯,這三個包都是需要的,正是為了實現這個功能,我對此封裝了一個POI的工具包

  1 import org.apache.poi.hssf.usermodel.*;
  2 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  3 import org.apache.poi.ss.usermodel.*;
  4 import org.apache.poi.ss.util.CellRangeAddress;
  5 import org.apache.poi.ss.util.NumberToTextConverter;
  6 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  7 
  8 import java.io.FileOutputStream;
  9 import java.io.IOException;
 10 import java.io.InputStream;
 11 import java.text.DateFormat;
 12 import java.text.SimpleDateFormat;
 13 import java.util.*;
 14 
 15 public class PoiUtil {
 16     private PoiUtil() {
 17     }
 18 
 19     /**
 20      * Excel2003和Excel2007+創建方式不同
 21      * Excel2003使用HSSFWorkbook 后綴xls
 22      * Excel2007+使用XSSFWorkbook 后綴xlsx
 23      * 此方法可保證動態創建Workbook
 24      *
 25      * @param is
 26      * @return
 27      */
 28     public static Workbook createWorkbook(InputStream is) throws IOException, InvalidFormatException {
 29         return WorkbookFactory.create(is);
 30     }
 31 
 32     /**
 33      *導入數據獲取數據列表
 34      * @param wb
 35      * @return
 36      */
 37     public static List<List<Object>> getDataList(Workbook wb) {
 38         List<List<Object>> rowList = new ArrayList<>();
 39         for (int sheetNum = 0; sheetNum < wb.getNumberOfSheets(); sheetNum++) {
 40             Sheet sheet = wb.getSheetAt(sheetNum);
 41             for (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {
 42                 Row row = sheet.getRow(i);
 43                 if (null == row)
 44                     continue;
 45                 List<Object> cellList = new ArrayList<>();
 46                 for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
 47                     Cell cell = row.getCell(j);
 48                     cellList.add(getCellValue(cell));
 49                 }
 50                 rowList.add(cellList);
 51             }
 52         }
 53         return rowList;
 54     }
 55 
 56     private static String getCellValue(Cell cell) {
 57         String cellvalue = "";
 58         if (cell != null) {
 59             // 判斷當前Cell的Type
 60             switch (cell.getCellType()) {
 61                 // 如果當前Cell的Type為NUMERIC
 62                 case HSSFCell.CELL_TYPE_NUMERIC: {
 63                     short format = cell.getCellStyle().getDataFormat();
 64                     if (format == 14 || format == 31 || format == 57 || format == 58) {   //excel中的時間格式
 65                         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 66                         double value = cell.getNumericCellValue();
 67                         Date date = DateUtil.getJavaDate(value);
 68                         cellvalue = sdf.format(date);
 69                     }
 70                     // 判斷當前的cell是否為Date
 71                     else if (HSSFDateUtil.isCellDateFormatted(cell)) {  //先注釋日期類型的轉換,在實際測試中發現HSSFDateUtil.isCellDateFormatted(cell)只識別2014/02/02這種格式。
 72                         // 如果是Date類型則,取得該Cell的Date值           // 對2014-02-02格式識別不出是日期格式
 73                         Date date = cell.getDateCellValue();
 74                         DateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
 75                         cellvalue = formater.format(date);
 76                     } else { // 如果是純數字
 77                         // 取得當前Cell的數值
 78                         cellvalue = NumberToTextConverter.toText(cell.getNumericCellValue());
 79 
 80                     }
 81                     break;
 82                 }
 83                 // 如果當前Cell的Type為STRIN
 84                 case HSSFCell.CELL_TYPE_STRING:
 85                     // 取得當前的Cell字符串
 86                     cellvalue = cell.getStringCellValue().replaceAll("'", "''");
 87                     break;
 88                 case HSSFCell.CELL_TYPE_BLANK:
 89                     cellvalue = null;
 90                     break;
 91                 // 默認的Cell值
 92                 default: {
 93                     cellvalue = " ";
 94                 }
 95             }
 96         } else {
 97             cellvalue = "";
 98         }
 99         return cellvalue;
100     }
101 
102     /**
103      * 此方法生成表頭並寫入表頭名稱
104      *
105      * @param nodes 節點
106      * @param sheet 工作簿
107      * @param style 單元格樣式
108      * @return 數據加載開始行
109      */
110     public static int generateHeader(List<HeaderNode> nodes, Sheet sheet, CellStyle style) {
111         Map<RowKey, Row> hssfRowMap = new HashMap<>();
112         int dataStartRow = 0;
113         for (HeaderNode node : nodes) {
114             if (!(node.firstRow == node.getLastCol() || node.getFirstCol() == node.getLastCol())) {
115                 CellRangeAddress cra = new CellRangeAddress(node.getFirstRow(), node.getLastRow(),
116                         node.getFirstCol(), node.getLastCol());
117                 sheet.addMergedRegion(cra);
118             }
119             dataStartRow = dataStartRow >= node.getLastRow() ? dataStartRow : node.getLastRow();
120             RowKey key = new RowKey();
121             key.setFirstRow(node.getFirstRow());
122             key.setLastRow(node.getLastRow());
123             Row row = hssfRowMap.get(key);
124             if (null == row) {
125                 row = sheet.createRow(node.getFirstRow());
126                 hssfRowMap.put(key, row);
127             }
128             Cell cell = row.createCell(node.getFirstCol());
129             cell.setCellValue(node.getName());
130             cell.setCellStyle(style);
131         }
132         return dataStartRow+1;
133     }
134 
135     public static class HeaderNode {
136         private String name;
137         private int firstRow;
138         private int lastRow;
139         private int firstCol;
140         private int lastCol;
141 
142         public String getName() {
143             return name;
144         }
145 
146         public void setName(String name) {
147             this.name = name;
148         }
149 
150         public int getFirstRow() {
151             return firstRow;
152         }
153 
154         public void setFirstRow(int firstRow) {
155             this.firstRow = firstRow;
156         }
157 
158         public int getLastRow() {
159             return lastRow;
160         }
161 
162         public void setLastRow(int lastRow) {
163             this.lastRow = lastRow;
164         }
165 
166         public int getFirstCol() {
167             return firstCol;
168         }
169 
170         public void setFirstCol(int firstCol) {
171             this.firstCol = firstCol;
172         }
173 
174         public int getLastCol() {
175             return lastCol;
176         }
177 
178         public void setLastCol(int lastCol) {
179             this.lastCol = lastCol;
180         }
181     }
182 
183     private static class RowKey {
184         private int firstRow;
185         private int lastRow;
186 
187         public int getFirstRow() {
188             return firstRow;
189         }
190 
191         public void setFirstRow(int firstRow) {
192             this.firstRow = firstRow;
193         }
194 
195         public int getLastRow() {
196             return lastRow;
197         }
198 
199         public void setLastRow(int lastRow) {
200             this.lastRow = lastRow;
201         }
202 
203         @Override
204         public boolean equals(Object o) {
205             if (this == o) return true;
206             if (!(o instanceof RowKey)) return false;
207             RowKey key = (RowKey) o;
208             return firstRow == key.firstRow &&
209                     lastRow == key.lastRow;
210         }
211 
212         @Override
213         public int hashCode() {
214             return Objects.hash(firstRow, lastRow);
215         }
216     }
217 
218     public static void main(String[] args) {
219         // 第一步,創建一個webbook,對應一個Excel文件
220         Workbook workbook = new XSSFWorkbook();
221         // 第二步,在webbook中添加一個sheet,對應Excel文件中的sheet
222         Sheet sheet = workbook.createSheet("測試");
223         // 第四步,創建單元格,並設置值表頭 設置表頭居中
224         CellStyle style = workbook.createCellStyle();
225         style.setAlignment(HorizontalAlignment.CENTER); // 水平居中格式
226         style.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中
227         List<HeaderNode> nodes = new ArrayList<>();
228         HeaderNode headerNode1 = new HeaderNode();
229         headerNode1.setName("test1");
230         headerNode1.setFirstRow(0);
231         headerNode1.setLastRow(1);
232         headerNode1.setFirstCol(0);
233         headerNode1.setLastCol(5);
234         nodes.add(headerNode1);
235         HeaderNode headerNode34 = new HeaderNode();
236         headerNode34.setName("test4");
237         headerNode34.setFirstRow(3);
238         headerNode34.setLastRow(4);
239         headerNode34.setFirstCol(0);
240         headerNode34.setLastCol(5);
241         nodes.add(headerNode34);
242         HeaderNode headerNode2 = new HeaderNode();
243         headerNode2.setName("test2");
244         headerNode2.setFirstRow(2);
245         headerNode2.setLastRow(2);
246         headerNode2.setFirstCol(0);
247         headerNode2.setLastCol(4);
248         nodes.add(headerNode2);
249         HeaderNode headerNode3 = new HeaderNode();
250         headerNode3.setName("test3");
251         headerNode3.setFirstRow(2);
252         headerNode3.setLastRow(2);
253         headerNode3.setFirstCol(5);
254         headerNode3.setLastCol(5);
255         nodes.add(headerNode3);
256         generateHeader(nodes, sheet, style);
257         try {
258             FileOutputStream output = new FileOutputStream("e:\\workbook.xls");
259             workbook.write(output);
260             output.flush();
261         } catch (IOException e) {
262             e.printStackTrace();
263         }
264     }
265 }

下面是導出報表及流下載的代碼

 1        List<PoiUtil.HeaderNode> nodes = new ArrayList<>();
 2         for (RpStyleItem item : styleItems){
 3             PoiUtil.HeaderNode headerNode = new PoiUtil.HeaderNode();
 4             headerNode.setFirstRow(item.getRow() - 1);
 5             headerNode.setLastRow(headerNode.getFirstRow()+item.getSizeY() - 1);
 6             headerNode.setFirstCol(item.getCol() - 1);
 7             headerNode.setLastCol(headerNode.getFirstCol() + item.getSizeX() - 1);
 8             headerNode.setName(item.getName());
 9             nodes.add(headerNode);
10         }
11         // 第一步,創建一個webbook,對應一個Excel文件
12         // XSSFWorkbook針對於excel2007+
13         // HSSFWorkbook針對於Excel2003(數據超過65536會報錯)
14         Workbook workbook = new XSSFWorkbook();
15         // 第二步,在webbook中添加一個sheet,對應Excel文件中的sheet
16         Sheet sheet = workbook.createSheet(template.getName());
17         // 第三步,創建單元格樣式
18         CellStyle style = workbook.createCellStyle();
19         style.setAlignment(HorizontalAlignment.CENTER); // 水平居中格式
20         style.setVerticalAlignment(VerticalAlignment.CENTER); //垂直居中
21         int rowNum = PoiUtil.generateHeader(nodes,sheet,style);
22         String sql = template.getReportSql().replace("\n", " ");
23         String reportDate = com.jrq.components.date.DateUtil.dateFormat(new Date(), "yyyyMMdd");
24         //測試數據 String reportDate = "20170711";
25         List<Map<String, Object>> datas = reportService.listReportData(reportDate, sql);
26         for (Map<String, Object> map : datas){
27             Collection<Object> values = map.values();
28             int index = 0; //cell單元格索引
29             Row row = sheet.createRow(rowNum++);
30             for (Object obj : values){
31                 row.createCell(index++).setCellValue(obj.toString());
32             }
33         }
34       /* 直接將將文件保存在本地,供測試樣式使用
35         try {
36             OutputStream output=new FileOutputStream("e:\\workbook.xls");
37             workbook.write(output);
38             output.flush();
39             output.close();
40         } catch (IOException e) {
41             e.printStackTrace();
42         }*/
43         String downFileName = new String(template.getType().getName()+reportDate+".xls");
44         try {
45             //若不進行編碼在IE下會亂碼
46             downFileName = URLEncoder.encode(downFileName, "UTF-8");
47         } catch (UnsupportedEncodingException e) {
48             e.printStackTrace();
49         }
50         try {
51             // 清空response
52             response.reset();
53             response.setContentType("application/msexcel");//設置生成的文件類型
54             response.setCharacterEncoding("UTF-8");//設置文件頭編碼方式和文件名
55             response.setHeader("Content-Disposition", "attachment; filename=" + downFileName);
56             OutputStream os=response.getOutputStream();
57             workbook.write(os);
58             os.flush();
59             os.close();
60         } catch (IOException e) {
61             LOG.error("文件流操作異常");
62             jr.setRet("文件流操作異常");
63             return jr;
64         }
65         jr.setSuc(JsonResponse.SUCCESS);
66         return jr;

下面是導入功能的代碼

1         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
2         MultipartFile file = multipartRequest.getFile("fileUpload");
3         if (!file.isEmpty()) {
4             Workbook workbook = PoiUtil.createWorkbook(file.getInputStream());
5             if (null != workbook) {
6                 List<List<Object>> list = PoiUtil.getDataList(workbook);}}

可以看到這里是前端上傳了excel文件這里,前端的HTML也貼一下

   <form method="POST" enctype="multipart/form-data" id="form1"
                                  action="/center/addition/list/uploadfile">
                                <input class="typeahead scrollable" type="file" id="fileUpload"
                                       name="fileUpload"/>
                                <input type="submit" value="上傳" id="btn_submit"/>
                            </form>

https://blog.csdn.net/ab7253957/article/details/76076600


免責聲明!

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



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