Java程序使用POI手写代码导出横转纵数据到Excel

在某些框架中,导出功能会根据内置的POI依赖编写自己的Excel工具类,能满足基本的数据导出,一般只是局限于正常表单的、固定表头的导出形式,不满足于灵活展示的数据表导出,所以还是需要使用原始的手写workbook+字符流的方式导出特殊的数据表。
本次举例横表转纵表展示的表单进行数据导出Excel。

实现思路:

  1. 先查询数据,确定数据展示形式;
  2. 规范导出Excel之后的样式,以便设置style;
  3. 根据数据,循环将数据写入到cell中;
  4. 将workbook写入字符流中,再将字符流写入到响应中;

具体代码如下:

第一部分:
   // 先查询产线名称 作为页面展示的横表字段
        List<TimsA021Vo> mtrlList = this.timsA021Service.queryIronBlastStatisticalMtrlList(timsA021QueryVo);
        List<Map<String, Object>> timsA021VoMapList = this.timsA021Service.queryIronBlastStatisticalMtrlDataList(timsA021QueryVo, mtrlList);
        List<String> headers = new ArrayList<>();
        headers.add("账务日期");
        headers.add("产线");
        headers.add("班别");
        if (ListUtils.isNotEmpty(mtrlList)) {
            for (TimsA021Vo a021Vo : mtrlList) {
                headers.add(a021Vo.getMtrlname());
            }
        } else {
            return;
        }
第二部分:
			Workbook workbook = new HSSFWorkbook();
            // 生成一个表格
            Sheet sheet = workbook.createSheet();
            workbook.setSheetName(0, "");
            // 设置表格默认列宽度为20个字节
            sheet.setDefaultColumnWidth((short) 20);
            // 生成一个样式
            CellStyle cellStyle = workbook.createCellStyle();
            // 设置这些样式
            cellStyle.setFillForegroundColor(HSSFColor.PALE_BLUE.index);
            cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
            cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
            cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
            cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            // 生成一个字体
            Font font = workbook.createFont();
            font.setColor(HSSFColor.BLACK.index);
            font.setFontHeightInPoints((short) 12);
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
            // 把字体应用到当前的样式
            cellStyle.setFont(font);
            // 指定当单元格内容显示不下时自动换行
            cellStyle.setWrapText(true);
            // 产生表格标题行
            Row headerRow = sheet.createRow(0);
            int rowNum = 0;
            for (String header : headers) {
                Cell cell = headerRow.createCell(rowNum++);
                cell.setCellValue(header);
                cell.setCellStyle(cellStyle);
            }
第三部分:
			// 遍历集合数据,产生数据行
            if (ListUtils.isNotEmpty(timsA021VoMapList)) {
                for (int i = 0; i < timsA021VoMapList.size(); i++) {
                    // 一共多少行数据
                    Row row = sheet.createRow(i + 1);
                    // 第一列
                    Cell cell1 = row.createCell(0);
                    if (Objects.nonNull(timsA021VoMapList.get(i).get("ACCOUNTDATE"))) {
                        cell1.setCellValue(timsA021VoMapList.get(i).get("ACCOUNTDATE").toString());
                    } else {
                        cell1.setCellValue("");
                    }
                    // 第二列
                    Cell cell2 = row.createCell(1);
                    if (Objects.nonNull(timsA021VoMapList.get(i).get("EQUIPNO"))) {
                        String label = DictUtils.getDictLabel("IRON_PLAN_LINE_NO", timsA021VoMapList.get(i).get("EQUIPNO").toString(), "");
                        cell2.setCellValue(label);
                    } else {
                        cell2.setCellValue("");
                    }
                    // 第三列
                    Cell cell3 = row.createCell(2);
                    if (Objects.nonNull(timsA021VoMapList.get(i).get("PRODUCTSHIFT"))) {
                        String label = DictUtils.getDictLabel("product_shift_1500", timsA021VoMapList.get(i).get("PRODUCTSHIFT").toString(), "");
                        cell3.setCellValue(label);
                    } else {
                        cell3.setCellValue("");
                    }
                    // 一共多少列表头
                    // 第三至第N列
                    for (int k = 0; k < mtrlList.size(); k++) {
                        Cell cell4 = row.createCell(k + 3);
                        // 根据产线的数量 获取对应数据
                        if (Objects.isNull(timsA021VoMapList.get(i).get("E"+mtrlList.get(k).getMtrlno()))) {
                            cell4.setCellValue("0.00");
                        } else {
                            cell4.setCellValue(timsA021VoMapList.get(i).get("E"+mtrlList.get(k).getMtrlno()).toString());
                        }
                    }
                }
            }
            // 增加合计行
            int createRow = sheet.getLastRowNum() + 1;
            Row row = sheet.createRow(createRow);
            Cell cell1 = row.createCell(0);
            cell1.setCellValue("合计");
            cell1.setCellStyle(cellStyle);
            CellRangeAddress cellRangeAddress = new CellRangeAddress(createRow, createRow, 0, 2);
            sheet.addMergedRegion(cellRangeAddress);
            int flag = 3;
            for (TimsA021Vo cell : mtrlList) {
                row.createCell(flag).setCellValue(cell.getNetwgt().toString());
                flag++;
            }
第四部分:
 String fileName = "-";
            fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
            // 将工作簿写入输出流中
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            workbook.write(byteArrayOutputStream);
            byte[] bytes = byteArrayOutputStream.toByteArray();
            // 设置响应头,指定文件名和文件类型
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename="+fileName+"-"+ DateUtils.getDate("yyyyMMddHHmmss")+".xls");
            response.setContentLength(bytes.length);
            // 关闭输出流和工作簿对象
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
            outputStream.close();

总结:该问题主要难度在于写清活动列将要展示在Excel的位置,循环时要注意,有空值的时候要做好判断。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值