private static Map<String, Object> parseRow(Row row, List<String> headers) {
Map<String, Object> rowData = new LinkedHashMap<>();
DataFormatter formatter = new DataFormatter();
for (int i = 0; i < headers.size(); i++) {
String header = headers.get(i);
Cell cell = row.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
// 根据单元格类型处理数据
switch (cell.getCellType()) {
case STRING:
rowData.put(header, cell.getStringCellValue().trim());
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
// 日期类型处理
rowData.put(header, cell.getDateCellValue().toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime());
} else {
// 数值类型处理
double value = cell.getNumericCellValue();
if (value == (int) value) {
rowData.put(header, (int) value);
} else {
rowData.put(header, value);
}
}
break;
case BOOLEAN:
rowData.put(header, cell.getBooleanCellValue());
break;
case FORMULA:
// 公式单元格处理
rowData.put(header, evaluateFormulaCell(cell));
break;
default:
rowData.put(header, formatter.formatCellValue(cell));
}
}
return rowData;
}
/**
* 读取excel文件数据列表
* @param file excel文件
* @return 返回列表数据 List<List<String>>
*/
public List<List<String>> createLists(MultipartFile file) throws Exception {
if (file == null){
log.info("文件对象为空!");
// 返回空集合
return new ArrayList<>();
}
// 存储文件(本地存储),返回文件的绝对路径名称
String filePathName = fileSaveUtils.uploadLocalhost(file);
// 解析文件
// 创建一个文件输入流,用于读取指定路径的Excel文件
FileInputStream fileIn = new FileInputStream(filePathName);
// 获取后缀名(不带.),如:xlsx
// 方法1
// 将文件的绝对路径名称按.进行分割分组
// String[] str = filePathName.split("\\.");
// 获取后缀名,最后分组的内容便是后缀名,如:xlsx
// String extName = str[str.length - 1];
// 方法2
// 利用字符串函数 substring 获取后缀名(不带.),如:xlsx
String extName = filePathName.substring(filePathName.lastIndexOf(".") + 1);
// 获取后缀名(带.),利用字符串函数 substring 获取后缀名(带.),如:.xlsx
// String extName = filePathName.substring(filePathName.lastIndexOf("."));
// 工作簿
Workbook workbook;
// 2003版的excel
if (extName.equals("xls")) {
// 使用文件输入流创建一个HSSFWorkbook对象,该对象代表整个Excel工作簿
workbook = new HSSFWorkbook(fileIn);
}
// 2007版的excel
else if (extName.equals("xlsx")){
// 使用文件输入流创建一个XSSFWorkbook对象,该对象代表整个Excel工作簿
workbook = new XSSFWorkbook(fileIn);
}
// 其他格式的文件
else {
// 抛出异常,退出方法
throw new Exception("不是有效的excel文件,请检查!");
}
// 从工作簿中获取第一个工作表,索引为0
Sheet sheet = workbook.getSheetAt(0);
// 获取数据行数,获取工作表中最后一行的编号,再加1,就是数据行数
int dataRowCount = sheet.getLastRowNum();
if (dataRowCount < 0) {
log.info("文件内容为空!");
// 返回空集合
return new ArrayList<>();
}
dataRowCount = dataRowCount + 1;
// 获取数据列数
// 工作表中的首行(标题行)
Row titleRow = sheet.getRow(0);
/*
// 单元格的类型是数字
if (row.getCell(4).getCellType() == CellType.NUMERIC) {
// 这样处理会遇到单元格内容是整数的话,最终结果会补上.0,如:单元格内容为 1,最终结果为 1.0
sampleItemResult.setResult(String.valueOf(row.getCell(4).getNumericCellValue()));
}
else {
sampleItemResult.setResult(row.getCell(4).getStringCellValue());
}
*/
// 先对单元格进行格式化,再取值,这样最终结果就不会有偏差,a是a,1是1,2.1是2.1,检出是检出,无内容就是无内容
DataFormatter formatter = new DataFormatter();
// 单元格的内容
String cellVal;
// 获取单元格的内容,工作表中的首行(标题行),从左到右遍历,遇到单元格没有内容就停止,该单元格的最左列就是最大列数
int col = 0;
cellVal = formatter.formatCellValue(titleRow.getCell(col));
while (!cellVal.isEmpty()) {
col += 1;
cellVal = formatter.formatCellValue(titleRow.getCell(col));
}
// 数据列数
int dataColCount = col;
// 数据列表,将excel文件中的数据列表转换成数据列表
List<List<String>> dataLists = new ArrayList<>();
// 获取数据,遍历工作表中的所有行
for(int i = 0; i < dataRowCount; i++) {
// 获取指定编号的行
Row row = sheet.getRow(i);
List<String> dataList = new ArrayList<>();
// 如果行不为空,增加信息
if(row != null) {
for(int j = 0; j < dataColCount; j++) {
Cell cell = row.getCell(j);
// 处理日期类型,统一格式化为 yyyy-MM-dd
if (cell != null && cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) {
LocalDateTime dateTimeValue = cell.getLocalDateTimeCellValue();
cellVal = dateTimeValue.format(DATE_FORMATTER);
} else {
cellVal = formatter.formatCellValue(row.getCell(j));
}
dataList.add(cellVal);
}
}
dataLists.add(dataList);
}
// 关闭文件输入流,释放资源
fileIn.close();
// 关闭workbook对象,释放资源
workbook.close();
// 返回列表数据
return dataLists;
}
在Java中读取Excel表中的日期内容,通常使用Apache POI库处理。Excel将日期存储为数值(从1900/1/1或1904/1/1开始的天数),需要特殊处理。以下是详细步骤:
1. 添加Maven依赖
xml
<dependencies> <!-- Apache POI核心库 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <!-- 处理xlsx格式 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> </dependencies>
2. 读取日期内容的代码示例
java
import org.apache.poi.ss.usermodel.*; import java.io.FileInputStream; import java.util.Date; public class ExcelDateReader { public static void main(String[] args) { String filePath = "your_excel_file.xlsx"; // 文件路径 try (FileInputStream fis = new FileInputStream(filePath); Workbook workbook = WorkbookFactory.create(fis)) { Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表 for (Row row : sheet) { for (Cell cell : row) { // 处理日期单元格 if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) { // 方法1:直接获取Date对象 Date dateValue = cell.getDateCellValue(); System.out.println("日期值: " + dateValue); // 方法2:转换为LocalDateTime(Java 8+) // LocalDateTime localDateTime = dateValue.toInstant() // .atZone(ZoneId.systemDefault()) // .toLocalDateTime(); } } } } catch (Exception e) { e.printStackTrace(); } } }
关键说明:
日期判断逻辑:
java
if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell))
DateUtil.isCellDateFormatted()
是关键方法,用于识别日期格式的单元格
获取日期值:
cell.getDateCellValue()
直接返回java.util.Date
对象推荐Java 8+用户转换为
LocalDateTime
处理(示例中已注释)
处理旧版Excel(.xls):
代码兼容
.xls
和.xlsx
格式旧版Excel使用
HSSFWorkbook
,新版用XSSFWorkbook
,但WorkbookFactory
自动处理
常见问题处理:
数值误判为日期:检查Excel单元格的实际格式设置
时区问题:
getDateCellValue()
使用系统默认时区,必要时手动调整自定义日期格式:若日期存储为字符串,需用
cell.getStringCellValue()
配合SimpleDateFormat
解析
日期字符串处理示例:
java
if (cell.getCellType() == CellType.STRING) { String dateString = cell.getStringCellValue(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date date = sdf.parse(dateString); // 按格式解析 }
提示:使用Java 8的
java.time
包(如LocalDate
)可更安全地处理日期,推荐替代java.util.Date
。
通过以上方法,可准确读取Excel中的日期内容。实际应用中请添加异常处理逻辑。