diff --git a/pom.xml b/pom.xml index 831caff0..641dd476 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.2.6 + 2.2.7 jar easyexcel diff --git a/src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java b/src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java index 0bc70d16..be9d2ad6 100644 --- a/src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java +++ b/src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java @@ -34,6 +34,8 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.poi.ss.format.CellFormat; +import org.apache.poi.ss.format.CellFormatResult; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; import org.apache.poi.ss.usermodel.FractionFormat; @@ -168,22 +170,58 @@ public class DataFormatter { this.decimalSymbols = DecimalFormatSymbols.getInstance(this.locale); } - private Format getFormat(Integer dataFormat, String dataFormatString) { + private Format getFormat(Double data,Integer dataFormat, String dataFormatString) { + + // Might be better to separate out the n p and z formats, falling back to p when n and z are not set. + // That however would require other code to be re factored. + // String[] formatBits = formatStrIn.split(";"); + // int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; + // String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; + String formatStr = dataFormatString; + + // Excel supports 2+ part conditional data formats, eg positive/negative/zero, + // or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds + // of different formats for different ranges, just +ve/-ve, we need to + // handle these ourselves in a special way. + // For now, if we detect 2+ parts, we call out to CellFormat to handle it + // TODO Going forward, we should really merge the logic between the two classes + if (formatStr.contains(";") && + (formatStr.indexOf(';') != formatStr.lastIndexOf(';') + || rangeConditionalPattern.matcher(formatStr).matches() + ) ) { + try { + // Ask CellFormat to get a formatter for it + CellFormat cfmt = CellFormat.getInstance(locale, formatStr); + // CellFormat requires callers to identify date vs not, so do so + Object cellValueO = data; + if (DateUtil.isADateFormat(dataFormat, formatStr) && + // don't try to handle Date value 0, let a 3 or 4-part format take care of it + data.doubleValue() != 0.0) { + cellValueO = DateUtil.getJavaDate(data, use1904windowing); + } + // Wrap and return (non-cachable - CellFormat does that) + return new CellFormatResultWrapper( cfmt.apply(cellValueO) ); + } catch (Exception e) { + LOGGER.warn("Formatting failed for format {}, falling back",formatStr, e); + } + } + // See if we already have it cached - Format format = formats.get(dataFormatString); + Format format = formats.get(formatStr); if (format != null) { return format; } + // Is it one of the special built in types, General or @? - if ("General".equalsIgnoreCase(dataFormatString) || "@".equals(dataFormatString)) { + if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) { format = getDefaultFormat(); - addFormat(dataFormatString, format); + addFormat(formatStr, format); return format; } // Build a formatter, and cache it - format = createFormat(dataFormat, dataFormatString); - addFormat(dataFormatString, format); + format = createFormat(dataFormat, formatStr); + addFormat(formatStr, format); return format; } @@ -530,7 +568,7 @@ public class DataFormatter { try { return new InternalDecimalFormatWithScale(format, symbols); } catch (IllegalArgumentException iae) { - LOGGER.debug("Formatting failed for format {}, falling back", formatStr, iae); + LOGGER.error("Formatting failed for format {}, falling back", formatStr, iae); // the pattern could not be parsed correctly, // so fall back to the default number format return getDefaultFormat(); @@ -570,7 +608,7 @@ public class DataFormatter { * @return Formatted value */ private String getFormattedDateString(Double data, Integer dataFormat, String dataFormatString) { - Format dateFormat = getFormat(dataFormat, dataFormatString); + Format dateFormat = getFormat(data, dataFormat, dataFormatString); if (dateFormat instanceof ExcelStyleDateFormatter) { // Hint about the raw excel value ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(data); @@ -593,7 +631,7 @@ public class DataFormatter { * @return a formatted number string */ private String getFormattedNumberString(Double data, Integer dataFormat, String dataFormatString) { - Format numberFormat = getFormat(dataFormat, dataFormatString); + Format numberFormat = getFormat(data, dataFormat, dataFormatString); String formatted = numberFormat.format(data); return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation } @@ -794,4 +832,26 @@ public class DataFormatter { } } + /** + * Workaround until we merge {@link org.apache.poi.ss.usermodel.DataFormatter} with {@link CellFormat}. Constant, non-cachable wrapper around a + * {@link CellFormatResult} + */ + private final class CellFormatResultWrapper extends Format { + private final CellFormatResult result; + + private CellFormatResultWrapper(CellFormatResult result) { + this.result = result; + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(result.text.trim()); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return null; // Not supported + } + } + } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java index 0dcef53c..938e031b 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java @@ -33,9 +33,10 @@ public class Lock2Test { @Test public void test() throws Exception { - File file = TestFileUtil.readUserHomeFile("test/test6.xls"); +// File file = TestFileUtil.readUserHomeFile("test/test6.xls"); + File file = new File("D:\\test\\T85_税金入库表202010.xlsx"); - List list = EasyExcel.read(file).sheet(1).headRowNumber(0).doReadSync(); + List list = EasyExcel.read(file).sheet(0).headRowNumber(0).doReadSync(); LOGGER.info("数据:{}", list.size()); for (Object data : list) { LOGGER.info("返回数据:{}", JSON.toJSONString(data)); diff --git a/update.md b/update.md index 0e377b7d..d7a96f7c 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,6 @@ +# 2.2.7 +* 修改07在特殊情况下用`String`接收数字会丢小数位的bug + # 2.2.6 * 修改跳着读取03版本空指针bug