ExcelReader reader = ExcelUtil.getReader(iStream);
设置自定义的类型转换器, 默认的类型转换器在数值型的转换时double强转为long会造成精度的丢失
reader.setCellEditor(new NumberToString());
/** * @Title NumberToString.java* @Package com.baozun.ecs.oms4.dms.manager.diff.ikea* @Description: TODO(用一句话描述该文件做什么)* @author zsh11619* @date 2020年6月17日* @version V1.0 */ package com.baozun.ecs.oms4.dms.manager.diff.ikea;import java.util.List;import org.apache.poi.ss.usermodel.Cell;import org.apache.poi.ss.usermodel.CellStyle;import org.apache.poi.ss.usermodel.CellType;import org.apache.poi.ss.usermodel.FormulaError;import org.apache.poi.ss.usermodel.Sheet;import org.apache.poi.ss.util.CellRangeAddress;import org.apache.poi.ss.util.NumberToTextConverter;import org.apache.poi.ss.util.SheetUtil;import cn.hutool.core.date.DateUtil;import cn.hutool.core.util.StrUtil;import cn.hutool.poi.excel.cell.CellEditor;/*** @ClassName NumberToString* @Package com.baozun.ecs.oms4.dms.manager.diff.ikea* @Description 数值类型精度丢失问题处理* @author zsh11619* @date 2020年6月17日**/public class NumberToString implements CellEditor { @Override public Object edit(Cell cell, Object value) { if (null == cell) { return null; } CellType cellType = cell.getCellTypeEnum(); if(CellType.BLANK == cellType){ // 空白单元格可能为合并单元格 cell = getMergedRegionCell(cell); cellType = cell.getCellTypeEnum(); } switch (cellType) { case NUMERIC: value = getNumericValue(cell); break; case BOOLEAN: value = cell.getBooleanCellValue(); break; case FORMULA: // 遇到公式时查找公式结果类型 break; case BLANK: value = StrUtil.EMPTY; break; case ERROR: final FormulaError error = FormulaError.forInt(cell.getErrorCellValue()); value = (null == error) ? StrUtil.EMPTY : error.getString(); break; default: value = cell.getStringCellValue(); } return value; } private Object getNumericValue(Cell cell) { final double value = cell.getNumericCellValue(); final CellStyle style = cell.getCellStyle(); if (null != style) { final short formatIndex = style.getDataFormat(); // 判断是否为日期 if (isDateType(cell, formatIndex)) { return DateUtil.date(cell.getDateCellValue());// 使用Hutool的DateTime包装 } final String format = style.getDataFormatString(); // 普通数字 if (null != format && format.indexOf(StrUtil.C_DOT) < 0) { return NumberToTextConverter.toText(value); } } // 某些Excel单元格值为double计算结果,可能导致精度问题,通过转换解决精度问题。 return Double.parseDouble(NumberToTextConverter.toText(value)); } /** * 是否为日期格式
* 判断方式: * *
* 1、指定序号
* 2、org.apache.poi.ss.usermodel.DateUtil.isADateFormat方法判定
*
* * @param cell 单元格 * @param formatIndex 格式序号 * @return 是否为日期格式 */ private static boolean isDateType(Cell cell, int formatIndex) { // yyyy-MM-dd----- 14 // yyyy年m月d日---- 31 // yyyy年m月------- 57 // m月d日 ---------- 58 // HH:mm----------- 20 // h时mm分 -------- 32 if (formatIndex == 14 || formatIndex == 31 || formatIndex == 57 || formatIndex == 58 || formatIndex == 20 || formatIndex == 32) { return true; } return org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell); } /** * 获取合并单元格
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格 * * @param cell {@link Cell} * @return 合并单元格 * @since 5.1.5 */ public static Cell getMergedRegionCell(Cell cell) { return getMergedRegionCell(cell.getSheet(), cell.getColumnIndex(), cell.getRowIndex()); } public static Cell getMergedRegionCell(Sheet sheet, int x, int y) { final List addrs = sheet.getMergedRegions(); int firstColumn; int lastColumn; int firstRow; int lastRow; for (CellRangeAddress ca : addrs) { firstColumn = ca.getFirstColumn(); lastColumn = ca.getLastColumn(); firstRow = ca.getFirstRow(); lastRow = ca.getLastRow(); if (y >= firstRow && y <= lastRow) { if (x >= firstColumn && x <= lastColumn) { return SheetUtil.getCell(sheet, firstRow, firstColumn); } } } return SheetUtil.getCell(sheet, y, x); } }