- 问题
由于业务的迭代和各种数据订正等等场景。excel解析的场景越来越多,但是现成的工具类其实还是不够自动化,我们需要一个只关注解析对象的工具,其他的东西尽量做到封装。
可以把excel表格看成RDB的表一样,一行就代表一条记录,对应代码一个entity。根据不同的需求我们只需要编写列与entity字段的映射关系即可,其他的兼容性与实现细节不关心。
- 实现方式
/**
* 将表格的数据转换成目标对象
* @param inputStream 文件流
* @param fileName 判断是否是xlsx或则xls的依据
* @param cellElementMapper 回调函数, 映射元素属性与行的值
* @param <TARGET> 需要转换成的行 model
* @return
*/
public static <TARGET> List<TARGET> parseToList(InputStream inputStream, String fileName, Function<ArrayList<String>, TARGET> cellElementMapper) {
Workbook workbook = null;
try {
workbook = isXlsxFile(fileName) ? new XSSFWorkbook(inputStream) : new HSSFWorkbook(inputStream);
Sheet sheetAt = workbook.getSheetAt(0);
Iterator<Row> rowIterator = sheetAt.rowIterator();
List<TARGET> targetList = Lists.newArrayList();
while (rowIterator.hasNext()) {
Row next = rowIterator.next();
ArrayList<String> rowStringList = Lists.newArrayList();
Iterator<Cell> cellIterator = next.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
cell.setCellType(Cell.CELL_TYPE_STRING);
String val = cell.getStringCellValue().trim();
if (StringUtils.isNotEmpty(val)) {
rowStringList.add(cell.getStringCellValue().trim());
}
}
if (! rowStringList.isEmpty()) {
targetList.add(cellElementMapper.apply(rowStringList));
}
}
return targetList;
} catch (IOException e) {
log.error("parse execel error", e);
} finally {
if (Objects.nonNull(workbook)) {
try {
workbook.close();
} catch (IOException e) {
log.error("work close error ", e);
}
}
}
return null;
}
/**
* 判断是否是xlxs
* @param originFileName
* @return
*/
private static boolean isXlsxFile(String originFileName) {
if (originFileName.contains("xlsx")) {
return true;
}
return false;
}
测试excel表格
使用方式
- 总结
整个实现的思路就是尽量想着去封装不关心的逻辑,封装的方式很多,只要尽可能的遵循几大原则就好,这里用函数编程回调的方式把一个大的逻辑里的小的逻辑开放出来,这很像设计模式里的模板方法,也很像策略模式,但是却更加灵活不用实现或则继承更轻量。