北屋教程网

专注编程知识分享,从入门到精通的编程学习平台

深入探索 Apache POI:复杂表格模板的生成与数据处理

在互联网软件开发领域,处理 Excel 文档是家常便饭。而通过编码自定义生成复杂表格模板,供用户下载填写后再导入数据,更是很多开发人员会碰到的场景。今天,我们就聚焦 Apache POI,详细说说如何通过编码实现这一系列操作。

Apache POI 基础认知

Apache POI 是一款开源的 Java 类库,专门用于处理 Microsoft Office 系列文件。对于 Excel 文件,它能轻松应对.xls 和.xlsx 等格式,提供了创建、读取、修改等全方位的操作 API。对于咱们开发人员来说,有了它,就能摆脱手动处理 Excel 的繁琐,用代码高效完成各种复杂的表格操作。

编码生成复杂表格模板

通过编码生成复杂表格模板,关键在于构建出符合需求的表头结构、设置好表格样式等。下面就以一个包含多层表头的项目信息统计模板为例,看看具体该如何实现。

首先,我们要创建一个工作簿和工作表,这是生成表格的基础。然后,根据模板的复杂程度,逐步构建表头。假设我们的表头有三层,包含项目基本信息、负责人信息和进度信息等类别,每层又有多个细分项。示例代码如下:

// 创建工作簿和工作表
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("项目信息统计模板");

// 构建第一层表头(合并单元格)
XSSFRow row0 = sheet.createRow(0);
XSSFCell cell0 = row0.createCell(0);
cell0.setCellValue("项目基本信息");
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));

XSSFCell cell1 = row0.createCell(4);
cell1.setCellValue("负责人信息");
sheet.addMergedRegion(new CellRangeAddress(0, 0, 4, 6));

// 构建第二层表头
XSSFRow row1 = sheet.createRow(1);
row1.createCell(0).setCellValue("项目名称");
row1.createCell(1).setCellValue("项目编号");
row1.createCell(2).setCellValue("项目启动时间");
row1.createCell(3).setCellValue("项目预计结束时间");
row1.createCell(4).setCellValue("负责人姓名");
row1.createCell(5).setCellValue("负责人联系方式");
row1.createCell(6).setCellValue("负责人邮箱");

// 构建第三层表头(部分单元格合并)
XSSFRow row2 = sheet.createRow(2);
row2.createCell(0).setCellValue(" "); // 与上层对应单元格对齐
row2.createCell(1).setCellValue(" ");
row2.createCell(2).setCellValue(" ");
row2.createCell(3).setCellValue(" ");
row2.createCell(4).setCellValue(" ");
row2.createCell(5).setCellValue(" ");
row2.createCell(6).setCellValue(" ");
XSSFCell cell2 = row2.createCell(7);
cell2.setCellValue("进度信息");
sheet.addMergedRegion(new CellRangeAddress(2, 2, 7, 9));
row2.createCell(7).setCellValue("当前进度");
row2.createCell(8).setCellValue("已完成任务数");
row2.createCell(9).setCellValue("未完成任务数");

// 设置列宽
for (int i = 0; i <= 9; i++) {
    sheet.setColumnWidth(i, 20 * 256); // 调整列宽,20为字符数
}

在这段代码中,我们通过createRow和createCell方法创建行和单元格,利用addMergedRegion方法实现单元格合并,以此构建出多层复杂表头。同时,通过setColumnWidth方法设置列宽,让表头内容能完整显示。

除了表头,我们还可以为模板设置一些默认样式,比如表头文字居中、添加边框等,让模板更规范、美观。示例代码如下:

// 创建表头样式
XSSFCellStyle headerStyle = workbook.createCellStyle();
// 设置水平和垂直居中
headerStyle.setAlignment(HorizontalAlignment.CENTER);
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 添加边框
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
// 设置字体
XSSFFont font = workbook.createFont();
font.setBold(true);
headerStyle.setFont(font);

// 为表头单元格应用样式
for (int i = 0; i <= 2; i++) {
    XSSFRow row = sheet.getRow(i);
    for (int j = 0; j < row.getLastCellNum(); j++) {
        XSSFCell cell = row.getCell(j);
        cell.setCellStyle(headerStyle);
    }
}

这样,一个包含复杂表头和美观样式的表格模板就通过编码生成了。接下来,我们可以将这个模板下载到本地。

下载生成的模板

生成模板后,我们需要将其下载到用户本地,方便用户填写数据。在 Web 项目中,通常可以通过输出流的方式实现下载功能。示例代码如下:

// 设置响应头,告诉浏览器下载文件
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename=项目信息统计模板.xlsx");

// 将工作簿写入响应输出流
ServletOutputStream out = response.getOutputStream();
workbook.write(out);
// 关闭资源
out.close();
workbook.close();

通过上述代码,用户就能在前端点击下载按钮后,将我们编码生成的复杂表格模板保存到本地了。

导入填写数据后的模板

用户下载模板并填写好数据后,我们需要将模板导入到系统中,读取其中的数据进行处理。读取数据的过程,就是按照表格的结构,逐行逐单元格地获取内容。

假设用户填写数据从第四行开始(前三行为表头),我们可以这样读取数据:

// 读取上传的模板文件
InputStream in = file.getInputStream(); // file为上传的文件对象
XSSFWorkbook workbook = new XSSFWorkbook(in);
XSSFSheet sheet = workbook.getSheetAt(0);

// 遍历行读取数据,从第四行开始(索引为3)
for (int i = 3; i <= sheet.getLastRowNum(); i++) {
    XSSFRow row = sheet.getRow(i);
    if (row == null) {
        continue;
    }
    // 读取各单元格数据
    String projectName = getCellValue(row.getCell(0));
    String projectNum = getCellValue(row.getCell(1));
    String startDate = getCellValue(row.getCell(2));
    // ... 读取其他单元格数据
    
    // 将读取到的数据封装到实体类或进行其他处理
    ProjectInfo projectInfo = new ProjectInfo();
    projectInfo.setProjectName(projectName);
    projectInfo.setProjectNum(projectNum);
    projectInfo.setStartDate(startDate);
    // ... 设置其他属性
}

// 关闭资源
in.close();
workbook.close();

// 自定义方法获取单元格值,处理不同数据类型
private String getCellValue(XSSFCell cell) {
    if (cell == null) {
        return "";
    }
    String value = "";
    switch (cell.getCellType()) {
        case STRING:
            value = cell.getStringCellValue();
            break;
        case NUMERIC:
            if (DateUtil.isCellDateFormatted(cell)) {
                value = new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue());
            } else {
                value = String.valueOf(cell.getNumericCellValue());
            }
            break;
        // 处理其他数据类型...
        default:
            value = "";
    }
    return value;
}

在读取数据时,需要注意不同单元格可能存在的数据类型(字符串、数字、日期等),通过自定义的getCellValue方法进行统一处理,确保获取到正确的数据。

生成模板时的进阶设置

为了让生成的模板更易用、更符合业务需求,我们还可以进行一些进阶设置。比如设置数据有效性,限制用户输入的数据格式;或者添加批注,提示用户如何填写。

设置数据有效性,以限制 “当前进度” 列只能输入 0-100 的数字为例:

// 创建数据验证助手
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
// 设置验证约束,只能输入0-100的数字
XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint) dvHelper.createNumericConstraint(
        DataValidationConstraint.ValidationType.INTEGER,
        DataValidationConstraint.OperatorType.BETWEEN,
        "0", "100");
// 设置应用范围,“当前进度”在第8列(索引为7),从第四行到第100行
CellRangeAddressList addressList = new CellRangeAddressList(3, 100, 7, 7);
// 创建数据验证并添加到工作表
XSSFDataValidation validation = (XSSFDataValidation) dvHelper.createValidation(dvConstraint, addressList);
sheet.addValidationData(validation);

添加批注,提示用户 “项目编号” 的填写规则:

// 创建绘图对象
XSSFDrawing drawing = sheet.createDrawingPatriarch();
// 创建批注位置
XSSFClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
anchor.setRow1(1); // 批注显示在第二行
anchor.setCol1(1); // 批注显示在第二列
// 创建批注
XSSFComment comment = drawing.createCellComment(anchor);
XSSFRichTextString text = new XSSFRichTextString("项目编号格式为:XM+年份+6位数字,例如XM2025000001");
comment.setString(text);
// 将批注添加到单元格
row1.getCell(1).setCellComment(comment); // row1为第二层表头行

这些进阶设置能让模板更规范,减少用户填写错误,提高数据导入的准确性。

总结

通过 Apache POI,我们能轻松实现通过编码生成复杂表格模板、下载模板以及导入填写后的数据这一完整流程。在生成模板时,要注重表头结构的构建和样式的设置;下载模板则是通过输出流将工作簿传递给用户;导入数据时,需妥善处理不同类型的单元格数据。

合理运用这些功能,能极大地提升我们处理 Excel 相关业务的效率,为用户带来更流畅的体验。希望今天的内容能帮到各位开发同仁,在实际项目中更好地运用 Apache POI 解决问题。

如果大家在使用过程中还有其他疑问或更好的技巧,欢迎在评论区交流分享。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言