在互联网软件开发领域,处理 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 解决问题。
如果大家在使用过程中还有其他疑问或更好的技巧,欢迎在评论区交流分享。