解决easyExcel读取EXCEL用String去接收数字,出现小数点BUG
easyexcel
快速、简洁、解决大文件内存溢出的java处理Excel工具
项目地址:https://gitcode.com/gh_mirrors/ea/easyexcel
免费下载资源
·
起因
目前项目中需要使用easyExcel 读取Excel文件,因为后端使用mongodb存储格式,数据格式不确定。因此读取文件时,未传递.class对象(指用方法一调用),使用String 接收Number 类型时,出现 .0情况。
本文依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.0.0-beta6</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
官方文档分析
easyExcel 官方文档描述如下, 如果传递了 .class 对象接收,则可以使用官方的NumberFormat.format()方式处理。
如果没有传递 接受对象那该如何处理呢?
源代码分析
easyExcel 都是通过各种 转换器(Converter) 实现的,因此我们可以找到对应 StringNumberConverter 转换器,其源代码如下:
/**
* String and number converter
*
* @author Jiaju Zhuang
*/
public class StringNumberConverter implements Converter<String> {
@Override
public Class supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
// 如果传递了 .class 接收,则 contentProperty 不为空
// If there are "DateTimeFormat", read as date,
// 获取 contentProperty 对象上是否有加日期格式注解
if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) {
return DateUtils.format(
HSSFDateUtil.getJavaDate(cellData.getDoubleValue(),
contentProperty.getDateTimeFormatProperty().getUse1904windowing(), null),
contentProperty.getDateTimeFormatProperty().getFormat());
}
// If there are "NumberFormat", read as number
// 获取 contentProperty 对象上是否有加数字格式注解
if (contentProperty != null && contentProperty.getNumberFormatProperty() != null) {
return NumberUtils.format(cellData.getDoubleValue(), contentProperty);
}
// Excel defines formatting
// 如果没有格式注解
// 注意: 如果 Excel 为Number 类型,则 cellData.getDataFormat() = 0!!!
if (cellData.getDataFormat() != null) {
// 判断是否为日期格式
if (DateUtil.isADateFormat(cellData.getDataFormat(), cellData.getDataFormatString())) {
return DateUtils.format(HSSFDateUtil.getJavaDate(cellData.getDoubleValue(),
globalConfiguration.getUse1904windowing(), null));
} else {
// 如果不是日期格式就直接调用这个方法, 该方法会 保留 .0的情况。可以进行拓展
return NumberUtils.format(cellData.getDoubleValue(), contentProperty);
}
}
// Default conversion number
return NumberUtils.format(cellData.getDoubleValue(), contentProperty);
}
@Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(Double.valueOf(value));
}
}
解决方案
自定义转换器,使用时再注册进去
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.NumberUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.util.NumberToTextConverter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.regex.Pattern;
/**
* todo:
*
* @author : zhoulin.zhu
* @date : 2020/4/28 10:17
*/
public class CustomStringNumberConverter implements Converter<String> {
@Override
public Class supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
// If there are "DateTimeFormat", read as date
if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) {
return com.alibaba.excel.util.DateUtils.format(
HSSFDateUtil.getJavaDate(cellData.getDoubleValue(),
contentProperty.getDateTimeFormatProperty().getUse1904windowing(), null),
contentProperty.getDateTimeFormatProperty().getFormat());
}
// If there are "NumberFormat", read as number
if (contentProperty != null && contentProperty.getNumberFormatProperty() != null) {
return NumberUtils.format(cellData.getDoubleValue(), contentProperty);
}
// Excel defines formatting
if (cellData.getDataFormat() != null) {
if (DateUtil.isADateFormat(cellData.getDataFormat(), cellData.getDataFormatString())) {
if(cellData.getDataFormatString().contains(":")){
return DateUtils.format(HSSFDateUtil.getJavaDate(cellData.getDoubleValue(),
globalConfiguration.getUse1904windowing(), null));
} else {
return DateUtils.format(HSSFDateUtil.getJavaDate(cellData.getDoubleValue(),
globalConfiguration.getUse1904windowing(), null), "yyyy-MM-dd");
}
} else if(contentProperty == null) {
try{
// 百分比
if(cellData.getDataFormatString() != null && cellData.getDataFormatString().contains("%")){
return new BigDecimal(cellData.getDoubleValue().toString()).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString() + "%";
} else if(cellData.getDataFormatString() != null && cellData.getDataFormatString().equals("General")){
//解决easyExcel 解析无 CLASS 对象时,Number to string 用String去接收数字,出现小数点等情况 方法一 会出现 数字位数失真的情况 ,即 excel 用公式计算数值后,只保留3位小数, 读取时 可能出现 直接去取保留前的N为小数的情况 建议使用方法二
// 方法一 NumberFormat numberFormat = NumberFormat.getInstance();
// numberFormat.setMaximumFractionDigits(20);
// numberFormat.setGroupingUsed(false);
// return numberFormat.format(cellData.getDoubleValue());
// 方法二
return NumberToTextConverter.toText(cellData.getDoubleValue());
} else {
return NumberToTextConverter.toText(cellData.getDoubleValue());
// return cellData.getDoubleValue().toString();
}
} catch (Exception e) {
// 建议 统一使用以下方法,可以解决数值格式问题
return NumberToTextConverter.toText(cellData.getDoubleValue());
// return NumberUtils.format(cellData.getDoubleValue(), contentProperty);
}
} else {
return NumberToTextConverter.toText(cellData.getDoubleValue());
// return NumberUtils.format(cellData.getDoubleValue(), contentProperty);
}
}
// Default conversion number
// NumberFormat numberFormat = NumberFormat.getInstance();
// numberFormat.setMaximumFractionDigits(20);
// numberFormat.setGroupingUsed(false);
// return numberFormat.format(cellData.getDoubleValue());
// 方法二
return NumberToTextConverter.toText(cellData.getDoubleValue());
// return NumberUtils.format(cellData.getDoubleValue(), contentProperty);
}
@Override
public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(Double.valueOf(value));
}
}
使用方法
InputStream inputStream = file.getInputStream();
// 可以是自己的监听器
SalaryExcelListener excelListener = new SalaryExcelListener();
EasyExcel.read(inputStream, excelListener).registerConverter(new CustomStringNumberConverter()).sheet().doRead();
使用效果对比
excel 数据:
使用前
{0=202003.0, 1=11.0, 2=XX, 3=2000.0, 4=1000, 5=7.5}
{0=202003.0, 1=90.0, 2=XX, 3=2000.0, 4=1000.0, 5=7.5}
使用后
{0=202003, 1=632511, 2=XX, 3=2000, 4=1000, 5=7.5}
{0=202003, 1=624190, 2=XX, 3=2000, 4=1000, 5=7.5}
GitHub 加速计划 / ea / easyexcel
31.64 K
7.47 K
下载
快速、简洁、解决大文件内存溢出的java处理Excel工具
最近提交(Master分支:3 个月前 )
c42183df
Bugfix 3 个月前
efa7dff6 * 重新加回 `commons-io`
3 个月前
更多推荐
已为社区贡献3条内容
所有评论(0)