EasyExcel读写Excel文件的格式问题

9 次阅读

EasyExcel在Java项目中读写Excel文件时,数据本身能够正常导入或导出,并不意味着Excel格式一定没有问题。实际开发中,经常会遇到日期显示异常、数字精度丢失、前导零消失、身份证号码变成科学计数法、百分比格式不正确以及单元格样式发生变化等情况。

这些问题通常不是EasyExcel无法处理Excel,而是Java数据类型、Excel单元格类型和显示格式之间存在差异。理解这三者之间的关系,是解决EasyExcel格式问题的关键。

一、EasyExcel读写Excel时常见的格式问题

Excel文件中的单元格不仅保存数据,还可能包含数字格式、日期格式、字体、边框、对齐方式等信息。EasyExcel在进行对象映射时,主要关注数据内容,而Excel最终显示效果还受到单元格格式的影响。

常见问题主要包括以下几类:

  • 日期读取后变成数字或格式不符合预期

  • Excel中的长数字显示为科学计数法

  • 身份证号、订单号前面的0丢失

  • BigDecimal金额出现精度或显示格式问题

  • 百分比读取后变成小数

  • 导出Excel后日期显示为英文或数字

  • 导出后数字没有千分位、保留位数不符合要求

  • 自定义单元格格式没有生效

  • 导出数据正常,但打开Excel后样式异常

  • Excel中空单元格、字符串和数字混用导致类型转换失败

其中,最容易被忽略的是“数据值”和“显示格式”并不是同一个概念。

例如Excel中显示:

001234

实际存储的内容可能是数字:

1234

也可能是字符串:

001234

还可能是数字1234,但通过单元格格式显示成001234。三种情况在视觉上类似,但使用EasyExcel读取时得到的结果可能完全不同。

二、Excel日期格式与Java日期类型的处理

日期是EasyExcel读写过程中最常见的格式问题之一。

例如Java实体类中使用:

private LocalDateTime createTime;

Excel中可能显示:

2026-09-30 12:30:00

如果没有明确指定日期格式,导出后的显示效果可能与预期不同。

可以通过@ExcelProperty配合日期格式注解处理:

@ExcelProperty("创建时间")
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;

如果只需要日期,可以使用:

@ExcelProperty("日期")
@DateTimeFormat("yyyy-MM-dd")
private LocalDate createDate;

这种方式适合实体字段与Excel格式固定的业务场景。

需要注意的是,Excel日期底层并不是简单的字符串。Excel通常使用数值表示日期和时间,再通过单元格格式将数值显示成日期。因此,不建议简单地把所有日期字段都定义成String,否则后续排序、计算和格式处理都会变得麻烦。

三、数字被读取成科学计数法怎么办

订单编号、手机号、银行卡号、身份证号码等字段虽然看起来是数字,但业务上通常并不需要进行数学运算。

例如Excel中存在:

202609300001234567

如果将其作为数字处理,Excel可能显示为:

2.02609E+17

更严重的是,Excel对超长数字存在精度限制,部分数字即使经过格式调整,也可能已经发生精度变化。

对于订单号、身份证号、编码等数据,推荐直接使用String:

@ExcelProperty("订单编号")
private String orderNo;

如果业务数据本质上是编码,就不要为了“看起来像数字”而定义成Long或其他数字类型。

尤其是身份证号码、商品编码、物流单号等字段,字符串通常更加合适。

四、Excel中的前导零为什么会消失

例如Excel中存在:

00012345

如果单元格类型是数字,Excel实际保存的可能只是:

12345

这时使用EasyExcel读取,已经无法从数字12345推断原始数据是否包含三个前导零。

如果要求保留前导零,应确保Excel中的数据以文本形式保存,或者通过Excel单元格格式实现固定长度显示。

对于导出的Excel,可以将这类字段直接作为字符串写入:

@ExcelProperty("商品编码")
private String productCode;

如果导出的业务数据本身是固定长度编码,也可以通过单元格样式设置文本格式。

需要特别注意:单纯在Java代码中把数字转换成字符串,并不能自动恢复Excel中已经丢失的前导零。数据在进入程序之前如果已经发生变化,就需要从数据源重新获取正确内容。

五、BigDecimal处理金额数据更可靠

金额字段不建议使用double直接处理。

例如:

private Double amount;

浮点数在二进制中的表示可能产生精度误差。涉及金额、税率、单价等数据时,更推荐:

private BigDecimal amount;

例如:

@ExcelProperty("金额")
private BigDecimal amount;

如果希望导出的Excel统一显示两位小数,可以进一步配置单元格数字格式。

例如:

100.00
1250.50

而不是:

100
1250.5

需要区分两个概念:BigDecimal决定Java中的数值精度,而Excel单元格格式决定用户看到的显示效果。即使Java中的值是100.00,Excel未必一定按照两位小数显示,最终还需要结合单元格样式进行控制。

六、百分比格式容易出现“100倍”问题

Excel中的百分比也是比较典型的格式陷阱。

例如业务系统中的:

0.85

如果Excel单元格采用百分比格式,会显示:

85%

但如果Java代码已经将数据处理成:

85

然后再设置Excel百分比格式,Excel可能显示成:

8500%

因此需要先明确系统中的数据定义。

如果业务数据采用:

0.85

表示85%,那么Excel使用百分比格式即可。

如果数据库中保存的是:

85

表示85%,则不能直接套用Excel百分比格式,通常需要在导出前进行转换:

BigDecimal percent = value.divide(new BigDecimal("100"));

然后再按照百分比格式输出。

七、EasyExcel导出时如何控制数字格式

EasyExcel支持通过单元格样式对Excel显示效果进行控制。

例如需要设置数字格式,可以使用WriteCellStyle:

WriteCellStyle style = new WriteCellStyle();
style.setDataFormatData(
    new DataFormatData()
);

在实际项目中,如果只需要简单的字段格式控制,优先考虑EasyExcel提供的注解方式;如果需要统一控制多个字段,或者根据业务动态设置格式,则可以使用WriteHandler进行处理。

格式控制的核心原则是:

Java数据类型
        ↓
Excel单元格数据
        ↓
Excel显示格式

不要将三个概念混在一起。

八、使用自定义Converter解决类型转换问题

当Excel中的数据格式比较复杂时,可以使用EasyExcel的Converter完成数据转换。

例如Excel中的日期是字符串:

2026/09/30

而Java实体需要:

LocalDate

可以通过自定义Converter实现字符串和日期对象之间的转换。

基本思路是:

public class CustomDateConverter implements Converter {

    @Override
    public Class> supportJavaTypeKey() {
        return LocalDate.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    // 根据实际EasyExcel版本实现转换方法
}

Converter适合处理“数据转换规则”,而不是单纯的视觉样式。

例如:

  • Excel字符串转Java日期

  • 特定编码转枚举

  • Excel中的Y/N转Boolean

  • 状态码转换为业务描述

如果只是设置字体、背景、边框或数字显示格式,则应该使用样式相关功能。

九、读取Excel时不要只依赖Java字段类型

读取Excel时,经常有人认为:

private Long id;

就可以保证Excel中的内容一定按照Long处理。

实际上,Excel文件中的单元格类型可能是字符串、数字、日期等,最终能否正常转换还与Excel实际数据有关。

例如:

10001
10002
10003

可以比较自然地映射到数字类型。

但如果数据变成:

0010001
A10001
10001-

那么就不再适合简单映射为Long。

对于业务编码,优先使用:

private String code;

而对于真正需要计算的数量、金额等字段,再选择Integer、Long或BigDecimal。

十、Excel样式问题与数据格式问题要分开处理

Excel格式问题并不全部属于数据类型问题。

例如导出的数据完全正确:

张三
1000.50
2026-09-30

但用户打开文件后发现:

  • 表头没有背景色

  • 日期显示不统一

  • 金额没有保留两位小数

  • 列宽太窄

  • 内容没有自动换行

这些属于Excel样式问题。

EasyExcel可以通过WriteCellStyle、HorizontalAlignmentEnum、VerticalAlignmentEnum以及各种Handler对这些内容进行控制。

例如设置水平居中:

WriteCellStyle style = new WriteCellStyle();
style.setHorizontalAlignment(HorizontalAlignmentEnum.CENTER);

对于复杂的Excel模板,还可以通过模板填充和自定义Handler实现更加精细的格式控制。

十一、读写Excel时常见的错误做法

1. 所有字段都使用String

String确实能够减少部分类型转换异常,但并不是所有字段都应该使用String。

例如:

private String amount;
private String quantity;
private String createTime;

虽然读取看起来方便,但后续计算、排序和日期处理都会增加转换成本。

正确方式应该根据业务语义选择类型。

2. 所有数字都使用Long

Long无法解决身份证号、订单号等长数字精度和业务编码问题。

对于不参与数学计算的数据,应优先使用String。

3. 只修改Excel显示格式,不处理真实数据

例如原始数据已经是:

12345

仅仅把Excel格式设置成:

00000000

虽然显示时可以得到:

00012345

但程序读取时仍然可能得到数字12345。

如果业务要求数据本身就是固定长度编码,就应该从数据模型层面明确其含义。

4. 认为Excel看到的内容就是实际存储值

这是排查格式问题时最容易产生的误区。

Excel显示:

001234

并不代表底层一定存储了字符串001234。

排查问题时应该同时关注:

  • 单元格真实类型

  • 单元格实际值

  • 单元格格式

  • EasyExcel映射字段类型

  • 自定义Converter

  • 导出时使用的样式

十二、EasyExcel格式问题的排查思路

遇到Excel读写格式异常时,可以按照以下顺序排查。

首先检查Excel原文件,确认问题是在Excel源文件中就存在,还是经过EasyExcel读取、处理、导出后才出现。

其次检查Java实体字段类型:

String
Integer
Long
BigDecimal
LocalDate
LocalDateTime

是否与业务数据含义匹配。

然后检查Excel单元格类型。如果Excel中的编码被保存成数字,那么即使Java字段使用String,也不能保证恢复原始前导零。

接下来检查EasyExcel的Converter和Handler,看是否存在自定义转换逻辑。

最后检查导出文件的单元格格式。如果数据本身正确,只是Excel中的显示效果异常,那么重点应该放在WriteCellStyle、数字格式和日期格式上,而不是修改业务数据。

十三、推荐的字段类型设计方式

实际项目中可以按照以下思路设计Excel实体:

数据类型推荐Java类型常见场景
姓名String普通文本
商品编码String编号、编码
订单号String长数字编号
身份证号String身份标识
数量Integer/Long数量统计
金额BigDecimal金额、价格
日期LocalDate年月日
时间LocalDateTime日期+时间
百分比BigDecimal税率、折扣率

这种设计可以减少大量格式转换问题。

十四、读写Excel格式问题的核心原则

EasyExcel本身并不是传统意义上的Excel编辑器,它主要负责Java对象与Excel数据之间的转换。真正复杂的格式问题往往来自三个层面:

业务数据定义
      ↓
Java数据类型
      ↓
              
文章标签