diff --git a/pom.xml b/pom.xml index 514464b1..a6183490 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.1.0-beta3 + 2.1.0-beta4 jar easyexcel @@ -132,11 +132,11 @@ - + org.apache.maven.plugins maven-pmd-plugin - 3.12.0 + 3.8 true true @@ -157,7 +157,6 @@ - pmd-check-verify validate @@ -170,7 +169,7 @@ com.alibaba.p3c p3c-pmd - 2.0.0 + 1.3.6 diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index 6e691fda..fcb276cb 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -1,27 +1,17 @@ package com.alibaba.excel.context; -import com.alibaba.excel.support.ExcelTypeEnum; -import com.alibaba.excel.util.FileUtils; -import com.alibaba.excel.util.StringUtils; - import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.OutputStream; -import java.security.GeneralSecurityException; import java.util.Map; import java.util.UUID; import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageAccess; -import org.apache.poi.poifs.crypt.Decryptor; import org.apache.poi.poifs.crypt.EncryptionInfo; import org.apache.poi.poifs.crypt.EncryptionMode; import org.apache.poi.poifs.crypt.Encryptor; -import org.apache.poi.poifs.filesystem.DocumentOutputStream; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; @@ -36,6 +26,9 @@ import com.alibaba.excel.enums.WriteTypeEnum; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.WorkBookUtil; import com.alibaba.excel.util.WriteHandlerUtils; import com.alibaba.excel.write.metadata.WriteSheet; @@ -179,7 +172,7 @@ public class WriteContextImpl implements WriteContext { Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i); WriteHandlerUtils.afterRowCreate(this, row, relativeRowIndex, Boolean.TRUE); addOneRowOfHeadDataToExcel(row, excelWriteHeadProperty.getHeadMap(), relativeRowIndex); - WriteHandlerUtils.afterRowDispose(this, row, relativeRowIndex, Boolean.FALSE); + WriteHandlerUtils.afterRowDispose(this, row, relativeRowIndex, Boolean.TRUE); } } diff --git a/src/main/java/com/alibaba/excel/metadata/CellData.java b/src/main/java/com/alibaba/excel/metadata/CellData.java index a3a40c61..a6b7af58 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellData.java +++ b/src/main/java/com/alibaba/excel/metadata/CellData.java @@ -202,6 +202,9 @@ public class CellData { * Ensure that the object does not appear null */ public void checkEmpty() { + if (type == null) { + type = CellDataTypeEnum.EMPTY; + } switch (type) { case STRING: case ERROR: @@ -225,6 +228,9 @@ public class CellData { @Override public String toString() { + if (type == null) { + return "empty"; + } switch (type) { case NUMBER: return numberValue.toString(); diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java index a748f32c..1b9fbb9f 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java @@ -158,7 +158,6 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH if (currentheadRowNumber == rowIndex + 1) { buildHead(analysisContext, cellDataMap); } - // Now is header for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { try { @@ -206,8 +205,8 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH tmpContentPropertyMap.put(entry.getKey(), contentPropertyMapData.get(entry.getKey())); continue; } - String headName = headData.getHeadNameList().get(0); - + List headNameList = headData.getHeadNameList(); + String headName = headNameList.get(headNameList.size() - 1); for (Map.Entry stringEntry : dataMap.entrySet()) { String headString = stringEntry.getValue(); Integer stringKey = stringEntry.getKey(); diff --git a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java index 9adcb625..a1746299 100644 --- a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java @@ -31,7 +31,7 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, ExcelContentProperty excelContentProperty) { if (value == null) { - return new CellData(); + return new CellData(CellDataTypeEnum.EMPTY); } if (value instanceof String && currentWriteHolder.globalConfiguration().getAutoTrim()) { value = ((String)value).trim(); @@ -40,6 +40,9 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { if (cellData.getFormula() != null && cellData.getFormula()) { cell.setCellFormula(cellData.getFormulaValue()); } + if (cellData.getType() == null) { + cellData.setType(CellDataTypeEnum.EMPTY); + } switch (cellData.getType()) { case STRING: cell.setCellValue(cellData.getStringValue()); @@ -64,7 +67,7 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { protected CellData convert(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, ExcelContentProperty excelContentProperty) { if (value == null) { - return new CellData(); + return new CellData(CellDataTypeEnum.EMPTY); } // This means that the user has defined the data. if (value instanceof CellData) { diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 75a88105..d7cb6307 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -14,6 +14,7 @@ import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import com.alibaba.excel.context.WriteContext; +import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.WriteDirectionEnum; import com.alibaba.excel.enums.WriteTemplateAnalysisCellTypeEnum; import com.alibaba.excel.exception.ExcelGenerateException; @@ -168,18 +169,21 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { CellData cellData = convert(writeSheetHolder, value == null ? null : value.getClass(), cell, value, fieldNameContentPropertyMap.get(variable)); cellDataList.add(cellData); - switch (cellData.getType()) { - case STRING: - cellValueBuild.append(cellData.getStringValue()); - break; - case BOOLEAN: - cellValueBuild.append(cellData.getBooleanValue()); - break; - case NUMBER: - cellValueBuild.append(cellData.getNumberValue()); - break; - default: - break; + CellDataTypeEnum type = cellData.getType(); + if (type != null) { + switch (type) { + case STRING: + cellValueBuild.append(cellData.getStringValue()); + break; + case BOOLEAN: + cellValueBuild.append(cellData.getBooleanValue()); + break; + case NUMBER: + cellValueBuild.append(cellData.getNumberValue()); + break; + default: + break; + } } } cellValueBuild.append(analysisCell.getPrepareDataList().get(index)); diff --git a/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java index 463fea00..5140ae68 100644 --- a/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java @@ -6,6 +6,7 @@ import java.util.Map; import org.apache.poi.ss.usermodel.Cell; +import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.util.CollectionUtils; @@ -56,7 +57,11 @@ public class LongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthSty return cell.getStringCellValue().getBytes().length; } CellData cellData = cellDataList.get(0); - switch (cellData.getType()) { + CellDataTypeEnum type = cellData.getType(); + if (type == null) { + return -1; + } + switch (type) { case STRING: return cellData.getStringValue().getBytes().length; case BOOLEAN: diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index ff30ae26..f9a69db7 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -50,13 +50,13 @@ public class WriteTest { public void simpleWrite() { // 写法1 String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); // 写法2 fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读 + // 这里 需要指定写用哪个class去写 ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); excelWriter.write(data(), writeSheet); @@ -80,7 +80,7 @@ public class WriteTest { // 根据用户传入字段 假设我们要忽略 date Set excludeColumnFiledNames = new HashSet(); excludeColumnFiledNames.add("date"); - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板") .doWrite(data()); @@ -88,7 +88,7 @@ public class WriteTest { // 根据用户传入字段 假设我们只要导出 date Set includeColumnFiledNames = new HashSet(); includeColumnFiledNames.add("date"); - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("模板") .doWrite(data()); } @@ -105,7 +105,7 @@ public class WriteTest { @Test public void indexWrite() { String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data()); } @@ -121,7 +121,7 @@ public class WriteTest { @Test public void complexHeadWrite() { String fileName = TestFileUtil.getPath() + "complexHeadWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data()); } @@ -138,7 +138,7 @@ public class WriteTest { public void repeatedWrite() { // 方法1 如果写到同一个sheet String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读 + // 这里 需要指定写用哪个class去写 ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); // 这里注意 如果同一个sheet只要创建一次 WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); @@ -194,7 +194,7 @@ public class WriteTest { @Test public void converterWrite() { String fileName = TestFileUtil.getPath() + "converterWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, ConverterData.class).sheet("模板").doWrite(data()); } @@ -236,7 +236,7 @@ public class WriteTest { *

* 2. 使用{@link ExcelProperty}注解指定写入的列 *

- * 3. 使用withTemplate 读取模板 + * 3. 使用withTemplate 写取模板 *

* 4. 直接写即可 */ @@ -244,7 +244,7 @@ public class WriteTest { public void templateWrite() { String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; String fileName = TestFileUtil.getPath() + "templateWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).withTemplate(templateFileName).sheet().doWrite(data()); } @@ -260,7 +260,7 @@ public class WriteTest { @Test public void widthAndHeightWrite() { String fileName = TestFileUtil.getPath() + "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, WidthAndHeightData.class).sheet("模板").doWrite(data()); } @@ -297,7 +297,7 @@ public class WriteTest { HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板") .doWrite(data()); } @@ -316,7 +316,7 @@ public class WriteTest { String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写 LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data()); } @@ -331,7 +331,7 @@ public class WriteTest { public void tableWrite() { String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx"; // 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例 - // 这里 需要指定写用哪个class去读 + // 这里 需要指定写用哪个class去写 ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了 WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build(); @@ -385,7 +385,7 @@ public class WriteTest { public void longestMatchColumnWidthWrite() { String fileName = TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, LongestMatchColumnWidthData.class) .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong()); } @@ -404,7 +404,7 @@ public class WriteTest { @Test public void customHandlerWrite() { String fileName = TestFileUtil.getPath() + "customHandlerWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new CustomSheetWriteHandler()) .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); } @@ -416,7 +416,7 @@ public class WriteTest { public void noModleWrite() { // 写法1 String fileName = TestFileUtil.getPath() + "noModleWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName).head(head()).sheet("模板").doWrite(dataList()); } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java index 698dc063..b19ac81a 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java @@ -1,7 +1,5 @@ package com.alibaba.easyexcel.test.temp.simple; -import java.io.FileInputStream; -import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -13,14 +11,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.easyexcel.test.core.large.LargeData; -import com.alibaba.easyexcel.test.core.simple.SimpleData; import com.alibaba.easyexcel.test.demo.write.DemoData; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; -import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.write.metadata.WriteSheet; -import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy; -import com.alibaba.fastjson.JSON; import net.sf.cglib.beans.BeanMap; @@ -50,8 +43,7 @@ public class Wirte { String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 - EasyExcel.write(fileName, DemoData.class) - .registerWriteHandler(new SimpleRowHeightStyleStrategy((short)150, (short)120)).sheet("模板").doWrite(data()); + EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); } private List> head() { @@ -74,7 +66,7 @@ public class Wirte { DemoData data = new DemoData(); data.setString("字符串" + i); data.setDate(new Date()); - data.setDoubleData(0.56); + data.setDoubleData(null); list.add(data); } return list; diff --git a/update.md b/update.md index 1eb3717e..36b23811 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,8 @@ +# 2.1.0-beta4 +* 修改最长匹配策略会空指针的bug [Issue #747](https://github.com/alibaba/easyexcel/issues/747) +* 修改afterRowDispose错误 [Issue #751](https://github.com/alibaba/easyexcel/issues/751) +* 修复多个头的情况下会读取数据为空 + # 2.1.0-beta3 * 支持强行指定在内存处理,以支持备注、RichTextString等的写入 * 修复关闭流失败,可能会不删除临时文件的问题