序言
工作中遇到了导入导出问题,并且出现了导入或导出Excel时间格式变为数字的问题。通过学习解决实现了这些功能,记录总结分享给大家。本文将详细介绍如何使用 Java 编程语言和 Apache POI 库来实现这些功能。我们将通过一个示例项目演示如何从数据库中读取数据并将其导出为 Excel 文件,然后再从 Excel 文件中读取数据并导入回数据库。
问题
导入或导出 Excel 时,时间格式变为数字的问题通常是由于 Excel 在处理日期时间时的内部表示方式所致。Excel会将日期时间数据存储为一个数字,该数字代表自 1900 年 1 月 1 日以来的天数(对于日期部分)或天数加上小数表示的时间部分。因此,如果不正确处理这些日期时间数据,Excel 可能会显示为日期时间的数字格式,而不是人类可读的日期时间格式。
例:这是数据库时间
导入之后
准备工作
在开始之前,确保你已经准备好以下环境和工具:
- Java 开发环境(JDK11)
- Maven 项目管理工具 (3.6.1)
- IDE(例如 IntelliJ IDEA 或 Eclipse)
- Apache POI 库
- Mybatis-Plus / Mybatis
1. 创建 Maven 项目并导入依赖
首先,创建一个 Maven 项目并在 pom.xml
文件中添加 Apache POI 的依赖:
<!-- Apache POI -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version> <!-- 版本号根据实际情况调整 -->
</dependency>
2.实体类和数据库如下
@Data
@TableName("excel")
public class DataEntity {
private Long id;
private String name;
private int age;
private String email;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@TableField(value = "birthday")
private LocalDate birthday;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "currenttime")
private LocalDateTime currentTime;
}
3.yml配置连接数据库,用Mybatis-Plus / Mybatis 写Mapper,Service,Impl此处不再赘述
导出功能实现
1.编写导出功能的 Controller
创建一个 Spring MVC 的 Controller 类,实现数据导出到 Excel 的功能:
@RestController
@RequestMapping("/execl")
public class ExeclController {
@Resource
private DataService dataService;
@GetMapping("/export")
public ResponseEntity<byte[]> exportDataToExcel() throws IOException {
//读取数据库全部数据
List<DataEntity> dataList = dataService.list();
// 创建一个工作簿
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Data");
// 创建表头
Row headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("ID");
headerRow.createCell(1).setCellValue("Name");
headerRow.createCell(2).setCellValue("Age");
headerRow.createCell(3).setCellValue("Email");
headerRow.createCell(4).setCellValue("Birthday");
headerRow.createCell(5).setCellValue("CurrentTime");
// 日期和时间格式化器
// 将 LocalDate 和 LocalDateTime 转换为字符串格式
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 创建日期单元格样式
//CreationHelper 是 Apache POI 提供的一个帮助类,用于创建各种格式和样式。
CreationHelper creationHelper = workbook.getCreationHelper();
//CellStyle 是用于定义单元格样式的类。
//workbook.createCellStyle() 方法用于创建一个新的单元格样式对象。
//dateStyle.setDataFormat(...) 方法用于设置单元格的数据格式。
//creationHelper.createDataFormat().getFormat("yyyy-MM-dd") 方法用于获取日期格式的代码,"yyyy-MM-dd" 是我们想要的日期格式。
CellStyle dateStyle = workbook.createCellStyle();
dateStyle.setDataFormat(creationHelper.createDataFormat().getFormat("yyyy-MM-dd"));
CellStyle dateTimeStyle = workbook.createCellStyle();
dateTimeStyle.setDataFormat(creationHelper.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
// 填充数据行
int rowNum = 1;
for (DataEntity data : dataList) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(data.getId());
row.createCell(1).setCellValue(data.getName());
row.createCell(2).setCellValue(data.getAge());
row.createCell(3).setCellValue(data.getEmail());
// 格式化并设置日期,单元格样式
Cell birthdayCell = row.createCell(4);
birthdayCell.setCellValue(data.getBirthday().format(dateFormatter));
birthdayCell.setCellStyle(dateStyle);
// 格式化并设置日期,单元格样式
Cell currentTimeCell = row.createCell(5);
currentTimeCell.setCellValue(data.getCurrentTime().format(dateTimeFormatter));
currentTimeCell.setCellStyle(dateTimeStyle);
}
// 调整列宽以适应内容
for (int i = 0; i < 6; i++) {
sheet.autoSizeColumn(i);
}
// 将工作簿写入字节数组输出流
ByteArrayOutputStream
outputStream = new ByteArrayOutputStream();
//这个方法用于将工作簿(通常是Excel文件)的内容写入到一个OutputStream中
workbook.write(outputStream);
workbook.close();
// 将字节数组输出流转换为字节数组
byte[] bytes = outputStream.toByteArray();
// 设置响应头
//HttpHeaders 类:这个类是 Spring 提供的一个方便的 HTTP 头部管理工具类,可以用来设置各种 HTTP 头部字段。
HttpHeaders headers = new HttpHeaders();
//设置响应的内容类型(Content-Type)
//application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 是 Excel 文件的 MIME 类型,表示返回的是一个 Excel 文件。
//MediaType.parseMediaType 方法:这个方法用来解析 MIME 类型字符串并返回一个 MediaType 对象。
headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
//设置响应的内容处置方式(Content-Disposition),告诉浏览器如何处理响应的内容。
//Content-Disposition 头部:这个头部字段有助于控制浏览器对于响应内容的处理方式。它常用于提示浏览器下载文件,而不是直接在浏览器中显示内容。
//attachment:表示响应的内容是一个附件,应该提示用户下载
//data.xlsx":表示下载文件的默认名称为 data.xlsx
headers.setContentDispositionFormData("attachment", "data.xlsx");
// 返回 Excel 文件作为 ResponseEntity
return ResponseEntity.ok()
.headers(headers)
.body(bytes);
}
2.浏览器测试,输入http://localhost:你的端口号/execl/export即可下载
导入功能实现
1. 实现数据导入的 Controller
创建另一个 Controller 类,实现从 Excel 文件导入数据并存入数据库的功能:
@PostMapping("/import")
public ResponseEntity<String> importDataFromExcel(@RequestParam("file") MultipartFile file) throws IOException {
// 检查文件是否为空
if (file.isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("文件为空");
}
// 用于存储解析后的数据
List<DataEntity> dataList = new ArrayList<>();
// 使用try-with-resources自动关闭资源
try (InputStream inputStream = file.getInputStream();
Workbook workbook = new XSSFWorkbook(inputStream)) {
// 获取第一个工作表
Sheet sheet = workbook.getSheetAt(0);
int rowNum = 1; // 行号计数器
for (Row row : sheet) {
// 跳过表头行
if (rowNum == 1) {
rowNum++;
continue;
}
// 创建并填充数据实体
DataEntity data = new DataEntity();
data.setId((long) row.getCell(0).getNumericCellValue());
data.setName(row.getCell(1).getStringCellValue());
data.setAge((int) row.getCell(2).getNumericCellValue());
data.setEmail(row.getCell(3).getStringCellValue());
//将字符串转换回 LocalDate 类型
String birthdayString = row.getCell(4).getStringCellValue();
LocalDate birthday = LocalDate.parse(birthdayString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
data.setBirthday(birthday);
//将字符串转换为 LocalDateTime 类型
String currentTimeString = row.getCell(5).getStringCellValue();
LocalDateTime currentTime = LocalDateTime.parse(currentTimeString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
data.setCurrentTime(currentTime);
// 添加到数据列表
dataList.add(data);
}
}
// 将数据保存到数据库
dataService.saveBatch(dataList);
// 返回成功响应
return ResponseEntity.ok("数据导入成功");
}
2.Postman测试
Excel数据
数据库导入成功