
本文详解如何使用 apache poi 读取 excel(.xlsx)文件,针对单元格内逗号分隔的多值字段(如“class§ion”“subject_name”),自动解析并生成符合嵌套结构要求的 jsonarray,支持类型识别、字符串切分与 json 对象动态构建。
本文详解如何使用 apache poi 读取 excel(.xlsx)文件,针对单元格内逗号分隔的多值字段(如“class§ion”“subject_name”),自动解析并生成符合嵌套结构要求的 jsonarray,支持类型识别、字符串切分与 json 对象动态构建。
在实际教育系统或教务数据导入场景中,Excel 常以紧凑格式存储一对多关系:例如一个教师对应多个班级-年级组合(如 "6-A,7-B,8-A")或多个科目(如 "Tamil,English,Maths")。直接将整列字符串转为 JSON 数组无法满足业务所需的结构化嵌套(如 {"class": "6", "section": "A"}),需在 Java 层完成智能解析。以下提供一套健壮、可维护的实现方案。
✅ 核心思路
- 使用 Apache POI(XSSFWorkbook)安全读取 .xlsx 文件;
- 动态读取首行作为字段名(teacher, class&Section, subject_name);
- 遍历数据行,对每个单元格按类型(STRING / NUMERIC)提取原始值;
- 对含逗号的字符串字段,依据语义规则进一步拆分:
- 若字段名含 "class" 或类似标识 → 按 - 拆分为 class 和 section 字段;
- 若字段名含 "subject" → 视为独立 subject 字段;
- 每行生成一个 JSONObject,多值字段统一存为 JSONArray,最终聚合为顶层 JSONArray。
✅ 完整可运行代码(含异常处理与资源管理)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.alibaba.fastjson.JSON; // 推荐使用 fastjson 或 org.json(注意版本兼容性)
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;
public class ExcelToJSONArray {
public static void main(String[] args) throws Exception {
String excelPath = "C:/Users/HP/Downloads/school.xlsx";
try (InputStream in = Files.newInputStream(Paths.get(excelPath));
Workbook workbook = new XSSFWorkbook(in)) {
Sheet sheet = workbook.getSheetAt(0);
if (sheet == null) throw new IllegalArgumentException("Sheet is empty or invalid");
// 读取表头(第一行)
Row headerRow = sheet.getRow(sheet.getFirstRowNum());
List<String> headers = new ArrayList<>();
for (int j = headerRow.getFirstCellNum(); j < headerRow.getLastCellNum(); j++) {
Cell cell = headerRow.getCell(j);
headers.add(cell != null && cell.getCellType() == CellType.STRING
? cell.getStringCellValue().trim()
: "col_" + j);
}
List<JSONObject> result = new ArrayList<>();
// 遍历数据行(跳过表头)
for (int i = sheet.getFirstRowNum() + 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null) continue;
JSONObject record = new JSONObject();
for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
Cell cell = row.getCell(j);
if (cell == null) continue;
String header = headers.get(j);
JSONObject valueObj = null;
JSONArray valueArray = new JSONArray();
switch (cell.getCellType()) {
case STRING:
String rawStr = cell.getStringCellValue().trim();
if (rawStr.isEmpty()) break;
// 按字段语义区分解析逻辑
if (header.toLowerCase().contains("class") && rawStr.contains("-")) {
// 如 "6-A,7-B,8-A" → [{"class":"6","section":"A"}, ...]
for (String part : rawStr.split(",")) {
String[] cs = part.trim().split("-", 2);
if (cs.length == 2) {
JSONObject item = new JSONObject();
item.put("class", cs[0].trim());
item.put("section", cs[1].trim());
valueArray.add(item);
}
}
} else if (header.toLowerCase().contains("subject")) {
// 如 "Tamil,English,Maths" → [{"subject":"Tamil"}, ...]
for (String subj : rawStr.split(",")) {
JSONObject item = new JSONObject();
item.put("subject", subj.trim());
valueArray.add(item);
}
} else {
// 默认:纯字符串数组
valueArray.addAll(Arrays.stream(rawStr.split(","))
.map(String::trim)
.map(JSONObject::new)
.collect(Collectors.toList()));
}
record.put(header, valueArray);
break;
case NUMERIC:
NumberFormat nf = NumberFormat.getInstance();
nf.setGroupingUsed(false);
String numStr = nf.format(cell.getNumericCellValue());
// 教师编号等数字字段直接存为字符串(避免科学计数法)
record.put(header, numStr);
break;
default:
record.put(header, "");
}
}
result.add(record);
}
// 输出标准 JSON 格式(缩进美化可选)
System.out.println(JSON.toJSONString(result, true));
}
}
}⚠️ 关键注意事项
-
依赖配置:确保 pom.xml 中引入:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.4</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> <!-- 或升级至 fastjson2 --> </dependency> - 空单元格/空行防护:代码中已添加 row == null 和 cell == null 判空,生产环境建议补充日志告警;
- 数字精度问题:Excel 中数字可能被识别为科学计数法(如 2.34566E7),通过 NumberFormat 统一转为字符串可规避;
- 字段命名适配:当前逻辑通过 header.toLowerCase().contains(...) 匹配字段语义;若实际列名不一致(如 "Class & Section"),请调整匹配条件或建立映射表;
- JSON 库选择:示例使用 fastjson(输出更简洁),若用 org.json,需替换 JSON.toJSONString(...) 为 new JSONArray(result).toString(2)。
✅ 总结
本方案摒弃了简单扁平化遍历的思维定式,转而以字段语义驱动解析逻辑,兼顾可读性与扩展性。通过将 Excel 单元格中的逗号分隔值动态构造成嵌套 JSON 对象,完美匹配教务系统常见的“一对多”数据建模需求。开发者只需微调字段匹配规则与对象键名,即可复用于课程排表、学生选课、教师任课等各类场景。










