JavaPOI导出Excel合集——Java导出全内容

最近接手了一个需求,开启了一段苦逼的加班之路,也收获了不少,对于Excel导出的功能也更加熟悉了,接下来我就介绍一下我遇到的问题跟解决的方式。

问题一:

EasyExcel在Linux环境导出失败。

这是我在开发这个需求其中一个报表发现的问题——当我使用EasyExcel进行导出的时候本地导出没有问题,但是在测试环境与生产环境导出的时候就很不稳定时常导出一个只有表头的空表,改了很多遍,想了很多种原因。

例如:

1.可能是实体类字段类型无法识别,尤其像LocalDateTime这种类型的字段

2.可能是pom依赖问题

3.可能是接口超时问题

4.可能是响应对象类型没有改成excel对应类型的问题

5.可能是数据量过大问题

如上类似问题全部都是有异常显示的,但是我的导出没有异常报错,这就令我的问题查找十分困难,并且我在另一个项目中完美导出,说明可能是服务器环境有一些配置导致EasyExcel导出出现了问题公司的服务器确实不敢动呀,改起来也相对比较麻烦

这时候我们就需要改变方式,使用另外一种方式导出,这种方式就是POI,虽然POI被诟病容易OOM内存溢出,但是确实是排除超大数据量导出之外的一种比较好的选择了(EasyExcel不好用且找不到问题的备用选择,毕竟工作没人会等你研究明白了再让你开发O(∩_∩)O),所以我找了几个POI灵活导出的例子,供大家选择,但是最好我推荐还是用EasyExcel,是又省事又好用

正常使用POI导出,需要区分workbook对象。

  • HSSFWorkbook 用于Excel2003版及更早版本(扩展名为.xls)的导出。
  • XSSFWorkbook 用于Excel2007版(扩展名为.xlsx)的导出。
  • SXSSFWorkbook相对前面两种,会在导出数据达到万以上的数据,会报内存不足,导致失败的问题,所以用sxssf,简约sf来导出较大数据量

像上面这种区别的情况下,我们最好优先选择使用SXSSFWorkbook对象来进行Excel的导出,避免出现内存不足的情况

首先我们还是要导入POI的依赖。

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <artifactId>commons-compress</artifactId>
            <groupId>org.apache.commons</groupId>
            <version>1.19</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>

默认导出方式:

    /**
     * list 入参查询条件
     * service 业务层对象
     *
     */
    @PostMapping("/poi/excel")
    public void getExcelByPoi(@RequestBody @ApiParam list inDto, HttpServletResponse response) {
        InputStream inputStream = null;
        try{
            List<Object> excelList = service.queryToExcel(inDto);
            // 判断返回集合内容不为空
            if (CollectionUtils.isEmpty(excelList)) {
                return;
            }
            String fileType = ".xlsx";
            String fileName = "fileName";
            // keep 100 rows in memory, exceeding rows will be flushed to disk
            try (SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(100);
                 OutputStream os = response.getOutputStream();
                 ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
                //创建一个Sheet页
                SXSSFSheet sheet1 = sxssfWorkbook.createSheet("Sheet1");
                CellStyle cellStyle = service.headFont(sheet1.getWorkbook());
                //第一行是标题行
                Row titleRow = sheet1.createRow(0);
                // 写表头
                service.writerHeaderOne(titleRow);
                // 写表体
                for (int i = 1; i < excelList.size() + 1; i++) {
                    SXSSFRow contentRow = sheet1.createRow(i);
                    contentRow.createCell(0).setCellValue(i);
                    service.writerContent(contentRow, excelList.get(i - 1));
                }
                response.setContentType("application/vnd.ms-excel"); // 设置下载类型
                response.setHeader("Content-Disposition", "attachment;filename=" + fileName + fileType); // 设置文件的名称
                sheet1.setForceFormulaRecalculation(true);
                //创建临时文件  文件输出流
                sxssfWorkbook.write(byteStream);
                byteStream.flush();
                sxssfWorkbook.dispose();// 释放workbook所占用的所有windows资源*/
                byte[] b = new byte[4096];
                // 必须在这里创建,否则获取不到行数
                inputStream = new ByteArrayInputStream(byteStream.toByteArray());
                int size = inputStream.read(b);
                while (size > 0) {
                    os.write(b, 0, size);
                    size = inputStream.read(b);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("报表导出失败", e);
        }finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getLocalizedMessage());
                }
            }
        }
    }

写表头方法

     /**
     * 写标题
     *
     * @param titleRow 表头行对象
     */
     public void writerHeaderOne(Row titleRow) {
        titleRow.createCell(0).setCellValue("id");
        titleRow.createCell(1).setCellValue("姓名");
        titleRow.createCell(2).setCellValue("年龄");
    }

写表体方法

    /**
     * 导出写入数据
     *
     * @param contentRow 表体行
     * @param result 结果对象
     */
    public void writerContent(SXSSFRow contentRow, Object result) {
        contentRow.createCell(0).setCellValue(result.getId());
        contentRow.createCell(1).setCellValue(result.getName());
        contentRow.createCell(2).setCellValue(result.getAge());
    }

这种方法确实可以导出,但是缺少了表头的样式,看起来很不舒服,但是SXSSFWorkbook对象的表头样式修改我简单尝试了一下没有实现,所以又出现了如下方式。

DIY特殊表头方式:

这种方式可以随心所欲的设置表头样式,关键是还很简单,我们只需要创建一个只有表头的Excel,设置好我们想要的样式。如下图:

创建好的Excel保存到项目中的resources ——> template 目录下 

然后我们创建导出方法

    /**
     * service为业务类对象
     * @param inDto 导出查询条件
     * @param response
     */
    @PostMapping("/excel")
    public void getExcelByPoi(@RequestBody @ApiParam list inDto, HttpServletResponse response) {
        try {
            List<Object> excelList = service.queryToExcel(inDto);
            // 判断返回列表不为空
            if (CollectionUtils.isEmpty(excelList)) {
                return;
            }
            //导出数据列表
            List<Map<String, Object>> dataList = new ArrayList<>();

            SXSSFWorkbook workbook = null;
            InputStream inputStream = null;
            XSSFWorkbook workbookBuff = null;
            //处理
            try {
                //获取流
                inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("template/Excel.xlsx");
                //读表格
                workbookBuff = new XSSFWorkbook(inputStream);
                workbook = new SXSSFWorkbook(workbookBuff, 100);
                //获取sheet
                SXSSFSheet sheet = workbook.getSheetAt(0);
                //sheet页,从第几行开始写数据,数据内容
                service.putData(sheet, 1, excelList);
                //设置格式
                response.setContentType("application/vnd.ms-excel");
                //编码
                response.setCharacterEncoding("utf-8");
                //设置文件格式
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + "Excel" + ExcelTypeEnum.XLSX.getValue());
                workbook.write(response.getOutputStream());
            } catch (Exception e) {
                e.printStackTrace();
                log.info("生产单报表查询失败", e);
            }finally {
                //判断
                if(workbook != null){
                    try {
                        //关闭
                        workbook.close();
                    }catch (Exception e){
                        //异常
                        e.printStackTrace();
                    }
                }
                //判断
                if(inputStream != null){
                    try {
                        //关闭
                        inputStream.close();
                    }catch (Exception e){
                        //异常
                        e.printStackTrace();
                    }
                }
                //判断
                if(response.getOutputStream() != null){
                    try {
                        //关闭
                        response.getOutputStream().close();
                    }catch (Exception e){
                        //异常
                        e.printStackTrace();
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
            log.error("导出查询失败 {}", e.getMessage());
        }
    }

写表体数据方法

    public void putData(SXSSFSheet sheet, int start, List<Object> dataList) {
        // 循环处理
        for (int i = 0; i < dataList.size(); i++) {
            // 获取当前数据
            Object obj = dataList.get(i);
            // 创建
            Row row = sheet.createRow(i + start);
            // 列坐标
            int col = 0;
            // id
            Cell getIdCell = row.createCell(col++, CellType.STRING);
            // 数据
            getIdCell .setCellValue(obj.getId());
            // 名称
            Cell getNameCell = row.createCell(col++, CellType.STRING);
            // 数据
            getNameCell .setCellValue(obj.getName());
            // 年龄
            Cell getAgeCell = row.createCell(col++, CellType.STRING);
            // 数据
            getAgeCell.setCellValue(obj.getAge());
        }
    }

这样也可以导出。

下面给大家放上POI根据RGB来修改单元格颜色的代码

        // 创建Excel
        SXSSFWorkbook wb = new SXSSFWorkbook(100);
        // 创建Sheet页
        Sheet sheet = wb.createSheet();

        // 获取单元格的对象,去设置他的格式
        XSSFCellStyle groupFieldStyle =(XSSFCellStyle) wb.createCellStyle();
        groupFieldStyle.setBorderBottom(BorderStyle.THIN);//下边框样式
        groupFieldStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());//下边框颜色
        groupFieldStyle.setBorderLeft(BorderStyle.THIN);//左边框
        groupFieldStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());//左边框颜色
        groupFieldStyle.setBorderTop(BorderStyle.THIN);//上边框
        groupFieldStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());//上边框颜色
        groupFieldStyle.setBorderRight(BorderStyle.THIN);//右边框
        groupFieldStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());//右边框颜色
        groupFieldStyle.setAlignment(HorizontalAlignment.CENTER); // 设置单元格水平方向对其方式为居中
        groupFieldStyle.setVerticalAlignment(VerticalAlignment.CENTER);//设置单元格垂直方向对其方式为居中
        // 设置单元格RGB颜色
        groupFieldStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(248, 203, 173), new DefaultIndexedColorMap()));
        groupFieldStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        // 创建行,i表示第几行
        Row row = sheet.createRow(i);
        // 获取该行中的第几个单元格
        Cell cell = row.createCell(j);
        // 给单元格添加样式
        cell.setCellStyle(groupFieldStyle);

最后放上EasyExcel的文章连接,希望能够解决小伙伴们导出的问题。如果还有小伙伴们有问题 可以私信问我,日常在线哦

EasyExcel的导出与导入

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值