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("
", " ");
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

原文地址:https://www.cnblogs.com/myjoan/p/8797621.html