zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    卢卡斯定理算法模板
    求组合数的O(n^2)和O(n)解法及模板
    求逆元的方法及模板
    扩展欧基里德算法模板
    牛客练习赛43-F(简单容斥)
    容斥原理
    牛客网练习赛43-C(图论)
    折半搜索
    枚举+树状数组(经典)
    思维并查集/网络流和二分
  • 原文地址:https://www.cnblogs.com/myjoan/p/8797621.html
Copyright © 2011-2022 走看看