java导出excel常见的两个问题,一个是日期格式转换,另一个是Long型长数字导出变成了科学计数法导致失去精度。本文记录了这两个问题的解决方案,以及将主键等关键字段设置为隐藏列的处理方式。
1.基本excel导出和数据类型处理
public void exportData(String tableName,List<Map<String, Object>> dataList,String outPath) {
Workbook wb = new SXSSFWorkbook(500);
Sheet sheet = wb.createSheet();
wb.setSheetName(0, tableName);
//查询所有属性
List<String> titleKeyList = commonTableService.selectTableColumn(tableName);
//构建表头
Row titleRow = sheet.createRow(0);
sheet.setDefaultColumnWidth(30);
titleRow.setHeightInPoints(30);
for (int i = 0; i < titleKeyList.size(); i++) {
Cell titleCell = titleRow.createCell(i);
titleCell.setCellValue(titleKeyList.get(i));
}
//构建数据体
for (int i = 0; i < dataList.size(); i++) {
Row row = sheet.createRow(i + 1);
int num = 0;
Map<String, Object> map = dataList.get(i);
for (String key : titleKeyList) {
Cell cell = row.createCell(num);
Object param = map.get(key);
if (param == null) {
cell.setCellValue("");
} else if (param instanceof Integer) {
Integer value = (Integer) param;
cell.setCellValue(value);
} else if (param instanceof Long) {
Long value = (Long) param;
cell.setCellValue(value);
} else if (param instanceof Double) {
Double value = (Double) param;
cell.setCellValue(value);
} else if (param instanceof Float) {
Float value = (Float) param;
cell.setCellValue(value);
} else if (param instanceof Boolean) {
Boolean value = (Boolean) param;
cell.setCellValue(value ? 1 : 0);
} else if (param instanceof LocalDateTime) {
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = ((LocalDateTime) param).atZone(zoneId);
Instant instant = zonedDateTime.toInstant();
Date value = Date.from(instant);
cell.setCellValue(value);
} else {
String value = param.toString();
cell.setCellValue(value);
}
num++;
}
}
//输出文件
Path exportPath = Paths.get(outPath, tableName + ".xlsx");
try (FileOutputStream outputStream = new FileOutputStream(exportPath.toFile())) {
wb.write(outputStream);
log.info("导出项目数据表============================={}",exportPath.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面代码导出的数据文件如下图所示,其中Long型id因为超过了excel默认数字显示长度,转换成了科学计数法,导致失去精度,并且,日期也不是常见的可读格式。需要通过设置单元格的样式,转换日期和Long型字段的格式,以达到期望效果。
2.日期格式化
//定义日期格式
CellStyle cellStyle = wb.createCellStyle();
CreationHelper creationHelper = wb.getCreationHelper();
cellStyle.setDataFormat(creationHelper.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
cell.setCellStyle(cellStyle);
注意:样式只声明一遍,写在循环外,否则数据量大会报错单元格样式超出限制,一个excel最多可定义64000个样式。The maximum number of Cell Styles was exceeded. You can define up to 64000 style in a .xlsx Workbook.
3.Long型格式化
对于Long型的处理,不做数据类型转换,直接以字符串形式作为文本导出即可。
String value = param.toString();//Long型长数字转字符串,避免变成科学计数法失去精度
cell.setCellValue(value);
4.处理隐藏字段
为了更好的用户体验,像id这类字段通常不展示给用户,但作为标识字段又常常被用到,可以通过设置隐藏列的方式实现,导入时隐藏列正常读取即可,不需要做特殊处理。
for (int i = 0; i < titleKeyList.size(); i++) {
Cell titleCell = titleRow.createCell(i);
titleCell.setCellValue(englishChineseTitleKey.get(titleKeyList.get(i)));
if(projectId != null){
if("id".equals(titleKeyList.get(i)) || "data_lib_version".equals(titleKeyList.get(i))){
sheet.setColumnHidden(i,true);
}
}
}
至此,问题解决。
以上为个人观点,仅供学习记录,欢迎交流讨论。