解决easyExcel读取EXCEL用String去接收数字,出现小数点BUG

起因

目前项目中需要使用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}
在这里插入图片描述

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
easyexcel是一款基于Java的开源Excel操作工具库,它可以方便地读取和处理Excel文件。你可以使用以下步骤来读取Excel文件: 1. 导入easyexcel库的依赖包,例如通过Maven添加以下依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.3.0</version> </dependency> ``` 2. 创建一个类,例如`ExcelReader`,并使用`@ExcelProperty`注解来映射Excel文件的列与类的字段。 3. 使用`EasyExcel.read()`方法创建一个`ExcelReader`对象,并设置要读取Excel文件路径。 4. 使用`excelReader.read()`方法读取Excel文件,并通过`excelListener`来处理读取到的数据。 下面是一个简单的示例代码,展示了如何使用easyexcel读取Excel文件: ```java import com.alibaba.excel.EasyExcel; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import java.util.ArrayList; import java.util.List; public class ExcelReader { public static void main(String[] args) { String filePath = "path/to/your/excel/file.xlsx"; // 替换为你的Excel文件路径 // 创建 Excel 读取监听器 AnalysisEventListener<DataRow> excelListener = new AnalysisEventListener<DataRow>() { List<DataRow> dataList = new ArrayList<>(); @Override public void invoke(DataRow data, AnalysisContext context) { dataList.add(data); } @Override public void doAfterAllAnalysed(AnalysisContext context) { // 处理读取到的数据 for (DataRow data : dataList) { System.out.println(data); } } }; // 读取 Excel 文件 EasyExcel.read(filePath, DataRow.class, excelListener).sheet().doRead(); } // 定义数据行类,用于映射 Excel 的行数据 public static class DataRow { @ExcelProperty("姓名") private String name; @ExcelProperty("年龄") private int age; @Override public String toString() { return "DataRow{" + "name='" + name + '\'' + ", age=" + age + '}'; } } } ``` 你需要将示例代码中的`filePath`替换为你的Excel文件的路径,并根据实际情况修改`DataRow`类的字段和Excel文件中的列名。然后运行程序,就可以读取并处理Excel文件中的数据了。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风中思絮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值