POI实现Excel多行复杂表头导出

POI实现Excel多行复杂表头导出

1. pom文件添加POI相关依赖

XML 复制代码
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.10-FINAL</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.10-FINAL</version>
</dependency>

2. 代码实现

1. 定义表头标题

java 复制代码
/**
 * home.php?mod=space&uid=686208 vvirster@163.com
 * home.php?mod=space&uid=686237 2022-11-24 15:28
 * @description 复杂表格表头单元格
 **/
public class CellModel {
    /**
     * 表头列名称
     */
    private String cellName;
    /**
     * 起始行
     */
    private Integer startRow;
    /**
     * 结束行
     */
    private Integer endRow;
    /**
     * 起始列
     */
    private Integer startColumn;

    /**
     * 结束列
     */
    private Integer endColumn;
    /**
     * 设置单元格宽度
     */
    private Integer width;

    // setter getter省略。。
 }

2. 编写导出/生成Excel工具类

java 复制代码
/**
 * @author vvirster@163.com
 * @date 2022-11-24 15:29
 * @description POI导出Excel工具类
 **/
public class ExportExcelUtil {
        private static final Logger logger = LoggerFactory.getLogger(ExportExcelUtil.class);

      /**
     * 生成表格(用于生成复杂表头)
     *
     * home.php?mod=space&uid=952169 sheetName   sheet名称
     * @param wb          表对象
     * @param cellListMap 表头数据 {key=cellRowNum}
     * @param cellRowNum  表头总占用行数
     * @param exportData  行数据
     * home.php?mod=space&uid=155549 HSSFWorkbook 数据表对象
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static Workbook createCSVUtil(String sheetName, Workbook wb,
                                         Map<String, List<CellModel>> cellListMap,
                                         Integer cellRowNum, List<LinkedHashMap> exportData) throws Exception {
        //设置表格名称
        Sheet sheet = wb.createSheet(sheetName);
        // 设置打印参数
        PrintSetup printSetup = sheet.getPrintSetup();
        // 纸张大小
        printSetup.setPaperSize(PrintSetup.A4_PAPERSIZE);
        sheet.setDisplayGridlines(false);
        sheet.setPrintGridlines(false);
        // 上边距
        sheet.setMargin(Sheet.TopMargin, 0.5);
        // 下边距
        sheet.setMargin(Sheet.BottomMargin, 0.5);
        // 左边距
        sheet.setMargin(Sheet.LeftMargin, 0.5);
        // 右边距
        sheet.setMargin(Sheet.RightMargin, 0.5);
        sheet.setHorizontallyCenter(true);

        sheet.autoSizeColumn(1, true);
        // 定义title列cell样式
        CellStyle cellStyle = wb.createCellStyle();
        //设置单元格内容水平对齐
        // 文字居中
        cellStyle.setAlignment(CellStyle.ALIGN_CENTER);
        //设置单元格内容垂直对齐
        cellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        //设置自动换行
        cellStyle.setWrapText(true);
        cellStyle.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        //cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);//背景色
        cellStyle.setBorderBottom(CellStyle.BORDER_THIN);
        cellStyle.setBorderLeft(CellStyle.BORDER_THIN);
        cellStyle.setBorderRight(CellStyle.BORDER_THIN);
        cellStyle.setBorderTop(CellStyle.BORDER_THIN);
        // 定义title列cell字体
        Font font = wb.createFont();
        // font.setColor(HSSFColor.VIOLET.index);//字体颜色
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(Font.BOLDWEIGHT_BOLD);
        cellStyle.setFont(font);

        // 定义数据内容单元格样式
        CellStyle cellDataStyle = wb.createCellStyle();
        //设置单元格内容水平对齐
        // 文字居中
        cellDataStyle.setAlignment(CellStyle.ALIGN_CENTER);
        //设置单元格内容垂直对齐
        cellDataStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
        //设置自动换行
        cellDataStyle.setWrapText(true);
        cellDataStyle.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
        cellDataStyle.setBorderBottom(CellStyle.BORDER_THIN);
        cellDataStyle.setBorderLeft(CellStyle.BORDER_THIN);
        cellDataStyle.setBorderRight(CellStyle.BORDER_THIN);
        cellDataStyle.setBorderTop(CellStyle.BORDER_THIN);

        for (int t = 0; t < cellRowNum; t++) {
            Row row = sheet.createRow(t);
            List<CellModel> cellNameList = cellListMap.get(String.valueOf(t));

            for (CellModel cellModel : cellNameList) {
                // 遍历插入表头
                if (cellModel.getStartColumn() != null) {
                    Cell cell = row.createCell(cellModel.getStartColumn());
                    cell.setCellValue(cellModel.getCellName());
                    cell.setCellStyle(cellStyle);
                }
            }
            // 解决合并单元格后出现部分单元格没有边框的问题
            if (t != 0) {
                int lastCellNum = sheet.getRow(0).getLastCellNum();
                for (int cellIndex = 0; cellIndex < lastCellNum; cellIndex++) {
                    Cell cell = sheet.getRow(t).getCell(cellIndex);
                    if (cell == null) {
                        cell = sheet.getRow(t).createCell(cellIndex);
                        cell.setCellValue("");
                    }
                    cell.setCellStyle(cellStyle);
                }
            }
            // 合并单元格
            for (CellModel cellModel : cellNameList) {
                logger.info("cellModelInfo,{}", JSON.toJSONString(cellModel));
                if (cellModel.getStartRow() != null) {
                    //合并单元格
                    CellRangeAddress region = new CellRangeAddress(cellModel.getStartRow(),
                            cellModel.getEndRow(), cellModel.getStartColumn(), cellModel.getEndColumn());
                    //给定要合并的单元格范围
                    sheet.addMergedRegion(region);
                }
                // 根据标题设置单元格宽度
                if (cellModel.getWidth() != null) {
                    sheet.setColumnWidth(cellModel.getStartColumn(), cellModel.getWidth() * 256);
                } else {
                    sheet.setColumnWidth(cellModel.getStartColumn(), cellModel.getCellName().getBytes().length * 256);
                }
            }

        }
        // 导出具体的数据
        for (LinkedHashMap hashMap : exportData) {
            Row rowValue = sheet.createRow(cellRowNum);
            for (Map.Entry entryRow : (Iterable<Map.Entry>) hashMap.entrySet()) {
                int key = Integer.parseInt(entryRow.getKey().toString());
                String value = "";
                if (entryRow.getValue() != null) {
                    value = entryRow.getValue().toString();
                } else {
                    value = "";
                }
                Cell cellValue = rowValue.createCell(key);
                cellValue.setCellValue(value);
                cellValue.setCellStyle(cellDataStyle);
            }
            cellRowNum++;
        }
        return wb;
    }

     /**
     * 通过HTTP请求下载Excel
     * @param cellListMap    表格标题
     * @param exportData     需要导出的数据
     * @param sheetName      表格名称
     * @param exportFileName 导出文件名称
     * @param response       servletResponse
     */
    public static void downloadExcel(Map<String, List<CellModel>> cellListMap, List<LinkedHashMap> exportData,
                                     String sheetName, String exportFileName, HttpServletResponse response) throws Exception {
        OutputStream out = null;
         String fileType = ".xlsx";
        try {
            Workbook wb = createCSVUtil(sheetName, new HSSFWorkbook(), cellListMap, cellListMap.size(), exportData);

            String s_attachment = "attachment; filename=" + exportFileName + fileType;

            // 设置字符编码的格式
            s_attachment = new String(s_attachment.getBytes("gb2312"), "ISO8859-1");
            // 设定输出文件头
            response.setHeader("Content-disposition", s_attachment);
            // 定义输出类型
            response.setContentType("application/vnd.ms-excel");
            response.setContentType("text/plain;charset=UTF-8");
            out = response.getOutputStream();
            wb.write(out);
            out.flush();
        } catch (Exception e) {
            throw new RuntimeException("导出Excel失败!");
        } finally {
            if (out != null) {
                out.close();
            }
        }

    }

}

3. 测试

java 复制代码
public class ExcelUtilTest {
        /**
        * 生成Excel表头
        **/
        public static Map<String, List<CellModel>> genExcelTitleCel() {
            //表头数据
            Map<String, List<CellModel>> cellTitleMap = new HashMap<String, List<CellModel>>();
            // 第一行表头数据
            List<CellModel> firstRow = new ArrayList<CellModel>();
            CellModel first_cellModel1 = new CellModel();
            first_cellModel1.setCellName("项目名称");
            first_cellModel1.setStartRow(0);
            first_cellModel1.setWidth(20);
            first_cellModel1.setEndRow(1);
            first_cellModel1.setStartColumn(0);
            first_cellModel1.setEndColumn(0);

            CellModel first_cellModel2 = new CellModel();
            first_cellModel2.setCellName("计划类别");
            first_cellModel2.setStartRow(0);
            first_cellModel2.setEndRow(1);
            first_cellModel2.setStartColumn(1);
            first_cellModel2.setEndColumn(1);

            CellModel first_cellModel3 = new CellModel();
            first_cellModel3.setCellName("项目负责人");
            first_cellModel3.setStartRow(0);
            first_cellModel3.setEndRow(1);
            first_cellModel3.setStartColumn(2);
            first_cellModel3.setEndColumn(2);

            CellModel first_cellModel4 = new CellModel();
            first_cellModel4.setCellName("项目编号");
            first_cellModel4.setStartRow(0);
            first_cellModel4.setEndRow(1);
            first_cellModel4.setStartColumn(3);
            first_cellModel4.setEndColumn(3);

            CellModel first_cellModel5 = new CellModel();
            first_cellModel5.setCellName("2022年度发表受本项目资助的论文(篇)");
            first_cellModel5.setStartRow(0);
            first_cellModel5.setEndRow(0);
            first_cellModel5.setStartColumn(4);
            first_cellModel5.setEndColumn(10);

            CellModel first_cellModel6 = new CellModel();
            first_cellModel6.setCellName("2022年专著出版(册)");
            first_cellModel6.setWidth(100);
            first_cellModel6.setStartRow(0);
            first_cellModel6.setEndRow(0);
            first_cellModel6.setStartColumn(11);
            first_cellModel6.setEndColumn(12);

            CellModel first_cellModel7 = new CellModel();
            first_cellModel7.setCellName("2022年申请专利(项)");
            first_cellModel7.setStartRow(0);
            first_cellModel7.setEndRow(0);
            first_cellModel7.setStartColumn(13);
            first_cellModel7.setEndColumn(14);

            CellModel first_cellModel8 = new CellModel();
            first_cellModel8.setCellName("2022年授权专利(项)");
            first_cellModel8.setStartRow(0);
            first_cellModel8.setEndRow(0);
            first_cellModel8.setStartColumn(15);
            first_cellModel8.setEndColumn(16);

            CellModel first_cellModel9 = new CellModel();
            first_cellModel9.setCellName("2022年学术交流(次)");
            first_cellModel9.setStartRow(0);
            first_cellModel9.setEndRow(0);
            first_cellModel9.setStartColumn(17);
            first_cellModel9.setEndColumn(18);

            CellModel first_cellModel10 = new CellModel();
            first_cellModel10.setCellName("2022年人才培养(人)");
            first_cellModel10.setStartRow(0);
            first_cellModel10.setEndRow(0);
            first_cellModel10.setStartColumn(19);
            first_cellModel10.setEndColumn(20);

            CellModel first_cellModel11 = new CellModel();
            first_cellModel11.setCellName("2022年培育新立项纵向项目(项)");
            first_cellModel11.setStartRow(0);
            first_cellModel11.setEndRow(1);
            first_cellModel11.setStartColumn(21);
            first_cellModel11.setEndColumn(21);

            CellModel first_cellModel12 = new CellModel();
            first_cellModel12.setCellName("2022年获得省部级及以上科技奖励(项)");
            first_cellModel12.setStartRow(0);
            first_cellModel12.setEndRow(1);
            first_cellModel12.setStartColumn(22);
            first_cellModel12.setEndColumn(22);

            firstRow.add(first_cellModel1);
            firstRow.add(first_cellModel2);
            firstRow.add(first_cellModel3);
            firstRow.add(first_cellModel4);
            firstRow.add(first_cellModel5);
            firstRow.add(first_cellModel6);
            firstRow.add(first_cellModel7);
            firstRow.add(first_cellModel8);
            firstRow.add(first_cellModel9);
            firstRow.add(first_cellModel10);
            firstRow.add(first_cellModel11);
            firstRow.add(first_cellModel12);
            //第二行表头数据
            List<CellModel> secondRow = new ArrayList<CellModel>();
            CellModel second_cellModel1 = new CellModel();
            second_cellModel1.setCellName("发表学术论文总计");
            second_cellModel1.setStartRow(1);
            second_cellModel1.setEndRow(1);
            second_cellModel1.setStartColumn(4);
            second_cellModel1.setEndColumn(4);

            CellModel second_cellModel2 = new CellModel();
            second_cellModel2.setCellName("英文论文");
            second_cellModel2.setStartRow(1);
            second_cellModel2.setEndRow(1);
            second_cellModel2.setStartColumn(5);
            second_cellModel2.setEndColumn(5);

            CellModel second_cellModel3 = new CellModel();
            second_cellModel3.setCellName("SCI");
            second_cellModel3.setStartRow(1);
            second_cellModel3.setWidth(10);
            second_cellModel3.setEndRow(1);
            second_cellModel3.setStartColumn(6);
            second_cellModel3.setEndColumn(6);

            CellModel second_cellModel4 = new CellModel();
            second_cellModel4.setCellName("EI");
            second_cellModel4.setStartRow(1);
            second_cellModel4.setEndRow(1);
            second_cellModel4.setWidth(10);
            second_cellModel4.setStartColumn(7);
            second_cellModel4.setEndColumn(7);

            CellModel second_cellModel5 = new CellModel();
            second_cellModel5.setCellName("国内核心");
            second_cellModel5.setStartRow(1);
            second_cellModel5.setEndRow(1);
            second_cellModel5.setStartColumn(8);
            second_cellModel5.setEndColumn(8);

            CellModel second_cellModel6 = new CellModel();
            second_cellModel6.setCellName("国外学术期刊");
            second_cellModel6.setStartRow(1);
            second_cellModel6.setEndRow(1);
            second_cellModel6.setStartColumn(9);
            second_cellModel6.setEndColumn(9);

            CellModel second_cellModel7 = new CellModel();
            second_cellModel7.setCellName("其他");
            second_cellModel7.setStartRow(1);
            second_cellModel7.setEndRow(1);
            second_cellModel7.setStartColumn(10);
            second_cellModel7.setEndColumn(10);

            CellModel second_cellModel8 = new CellModel();
            second_cellModel8.setCellName("主编");
            second_cellModel8.setStartRow(1);
            second_cellModel8.setEndRow(1);
            second_cellModel8.setStartColumn(11);
            second_cellModel8.setEndColumn(11);

            CellModel second_cellModel9 = new CellModel();
            second_cellModel9.setCellName("参编");
            second_cellModel9.setStartRow(1);
            second_cellModel9.setEndRow(1);
            second_cellModel9.setStartColumn(12);
            second_cellModel9.setEndColumn(12);

            CellModel second_cellModel10 = new CellModel();
            second_cellModel10.setCellName("发明专利");
            second_cellModel10.setStartRow(1);
            second_cellModel10.setEndRow(1);
            second_cellModel10.setStartColumn(13);
            second_cellModel10.setEndColumn(13);

            CellModel second_cellModel11 = new CellModel();
            second_cellModel11.setCellName("其他专利");
            second_cellModel11.setStartRow(1);
            second_cellModel11.setEndRow(1);
            second_cellModel11.setStartColumn(14);
            second_cellModel11.setEndColumn(14);

            CellModel second_cellModel12 = new CellModel();
            second_cellModel12.setCellName("发明专利");
            second_cellModel12.setStartRow(1);
            second_cellModel12.setEndRow(1);
            second_cellModel12.setStartColumn(15);
            second_cellModel12.setEndColumn(15);

            CellModel second_cellModel13 = new CellModel();
            second_cellModel13.setCellName("其他专利");
            second_cellModel13.setStartRow(1);
            second_cellModel13.setEndRow(1);
            second_cellModel13.setStartColumn(16);
            second_cellModel13.setEndColumn(16);

            CellModel second_cellModel14 = new CellModel();
            second_cellModel14.setCellName("举办学术会议");
            second_cellModel14.setStartRow(1);
            second_cellModel14.setEndRow(1);
            second_cellModel14.setStartColumn(17);
            second_cellModel14.setEndColumn(17);

            CellModel second_cellModel15 = new CellModel();
            second_cellModel15.setCellName("参加学术会议");
            second_cellModel15.setStartRow(1);
            second_cellModel15.setEndRow(1);
            second_cellModel15.setStartColumn(18);
            second_cellModel15.setEndColumn(18);

            CellModel second_cellModel16 = new CellModel();
            second_cellModel16.setCellName("博士");
            second_cellModel16.setStartRow(1);
            second_cellModel16.setEndRow(1);
            second_cellModel16.setStartColumn(19);
            second_cellModel16.setEndColumn(19);

            CellModel second_cellModel17 = new CellModel();
            second_cellModel17.setCellName("硕士");
            second_cellModel17.setStartRow(1);
            second_cellModel17.setEndRow(1);
            second_cellModel17.setStartColumn(20);
            second_cellModel17.setEndColumn(20);

            secondRow.add(second_cellModel1);
            secondRow.add(second_cellModel2);
            secondRow.add(second_cellModel3);
            secondRow.add(second_cellModel4);
            secondRow.add(second_cellModel5);
            secondRow.add(second_cellModel6);
            secondRow.add(second_cellModel7);
            secondRow.add(second_cellModel8);
            secondRow.add(second_cellModel9);
            secondRow.add(second_cellModel10);
            secondRow.add(second_cellModel11);
            secondRow.add(second_cellModel12);
            secondRow.add(second_cellModel13);
            secondRow.add(second_cellModel14);
            secondRow.add(second_cellModel15);
            secondRow.add(second_cellModel16);
            secondRow.add(second_cellModel17);

            // 组装第一行表头标题
            cellTitleMap.put("0", firstRow);
            // 组装第二行表头标题
            cellTitleMap.put("1", secondRow);
            return cellTitleMap;
        }

    public static void main(String[] args) {
        //向指定的Excel中写入数据
        OutputStream out = null;
        Workbook wb = null;
        try {
            String tabName = "test生成Excel";
            Map<String, List<CellModel>> excelTitleCel = genExcelTitleCel();

            System.out.println(JSONObject.toJSONString(excelTitleCel));
            List<LinkedHashMap> exportData = new ArrayList<LinkedHashMap>();
            //生成10条行记录
            for (int i = 0; i < 10; i++) {
                LinkedHashMap<String, String> rowPut = new LinkedHashMap<String, String>();
                // 根据实际列数生成数据
                for (int j = 0; j <= 22; j++) {
                    rowPut.put(j + "", "数据11===" + i);
                }
                exportData.add(rowPut);
            }
            System.out.println(JSONObject.toJSONString(exportData));
            // 用于写入文件
            wb = ExportExcelUtil.createCSVUtil("生成Excel测试", new XSSFWorkbook(), excelTitleCel, excelTitleCel.size(),
                    exportData);

            FileOutputStream fos = new FileOutputStream("D:\\tmp\\" + tabName+".xlsx");
            wb.write(fos);
            fos.flush();
            fos.close();

             //在servlet/web环境下测试此方法
            // ExportExcelUtil.downloadExcel(excelTitleCel,exportData,"生成Excel测试","生成Excel测试",response);

        } catch (Exception e) {
            e.printStackTrace();
        }

}
  • 测试结果
相关推荐
星河梦瑾13 分钟前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富16 分钟前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想18 分钟前
JMeter 使用详解
java·jmeter
言、雲20 分钟前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇27 分钟前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
Yvemil71 小时前
《开启微服务之旅:Spring Boot 从入门到实践》(三)
java
Anna。。1 小时前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
计算机学长felix1 小时前
基于SpringBoot的“交流互动系统”的设计与实现(源码+数据库+文档+PPT)
spring boot·毕业设计
.生产的驴1 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
爱上语文1 小时前
宠物管理系统:Dao层
java·开发语言·宠物