From 8a2cb69be90511a56db8b4916480ef14ac52b2a5 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Fri, 11 Oct 2019 18:32:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=BB=E5=8F=96=E5=85=A8?= =?UTF-8?q?=E9=83=A8sheet=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + quickstart.md | 33 ++++++-- .../excel/analysis/v03/XlsSaxAnalyser.java | 1 - .../exception/ExcelDataConvertException.java | 57 +++++++++++++ .../metadata/property/ExcelHeadProperty.java | 8 ++ .../listener/ModelBuildEventListener.java | 34 ++++++-- .../alibaba/excel/util/ConverterUtils.java | 22 +++-- .../write/builder/ExcelWriterBuilder.java | 11 +++ .../builder/ExcelWriterSheetBuilder.java | 11 +++ .../builder/ExcelWriterTableBuilder.java | 11 +++ .../handler/DefaultWriteHandlerLoader.java | 20 +++-- .../write/metadata/WriteBasicParameter.java | 12 +++ .../metadata/holder/AbstractWriteHolder.java | 25 +++++- .../test/core/annotation/AnnotationData.java | 2 + .../core/annotation/AnnotationDataTest.java | 1 + .../core/exception/ExceptionDataListener.java | 2 +- .../read/CellDataDemoHeadDataListener.java | 50 +++++++++++ .../test/demo/read/CellDataReadDemoData.java | 22 +++++ .../test/demo/read/DemoDataListener.java | 1 + .../test/demo/read/DemoExceptionListener.java | 80 ++++++++++++++++++ .../test/demo/read/DemoHeadDataListener.java | 8 +- .../test/demo/read/ExceptionDemoData.java | 18 ++++ .../easyexcel/test/demo/read/ReadTest.java | 22 ++++- .../easyexcel/test/demo/web/WebTest.java | 2 +- .../alibaba/easyexcel/test/temp/LockTest.java | 11 +++ .../easyexcel/test/temp/poi/PoiWriteTest.java | 39 +++++++-- src/test/resources/demo/cellDataDemo.xlsx | Bin 0 -> 10323 bytes update.md | 4 + 28 files changed, 464 insertions(+), 44 deletions(-) create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataDemoHeadDataListener.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataReadDemoData.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExceptionListener.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/ExceptionDemoData.java create mode 100644 src/test/resources/demo/cellDataDemo.xlsx diff --git a/README.md b/README.md index 583cc4b..bf9871a 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ easyexcel [![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) [QQ群:662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80) +[钉钉群:21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11) # JAVA解析Excel工具easyexcel Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 diff --git a/quickstart.md b/quickstart.md index 728f373..ffb1f4b 100644 --- a/quickstart.md +++ b/quickstart.md @@ -70,6 +70,7 @@ public class DemoData { ``` ##### 监听器 ```java +// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 public class DemoDataListener extends AnalysisEventListener { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); /** @@ -113,6 +114,7 @@ public class DemoDataListener extends AnalysisEventListener { */ @Test public void simpleRead() { + // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 // 写法1: String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 @@ -410,12 +412,20 @@ public class CustomStringStringConverter implements Converter { ##### excel示例 参照:[excel示例](#simpleReadExcel) ##### 对象 -参照:[对象](#simpleReadObject) +```java +@Data +public class ExceptionDemoData { + /** + * 用日期去接字符串 肯定报错 + */ + private Date date; +} +``` ##### 监听器 参照:[监听器](#simpleReadListener) 里面多了一个方法,只要重写onException方法即可 ```java - /** + /** * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。 * * @param exception @@ -424,7 +434,14 @@ public class CustomStringStringConverter implements Converter { */ @Override public void onException(Exception exception, AnalysisContext context) { - LOGGER.error("解析失败,但是继续解析下一行", exception); + LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage()); + // 如果是某一个单元格的转换异常 能获取到具体行号 + // 如果要获取头的信息 配合invokeHeadMap使用 + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; + LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), + excelDataConvertException.getColumnIndex()); + } } ``` ##### 代码 @@ -433,17 +450,17 @@ public class CustomStringStringConverter implements Converter { * 数据转换等异常处理 * *

- * 1. 创建excel对应的实体对象 参照{@link DemoData} + * 1. 创建excel对应的实体对象 参照{@link ExceptionDemoData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} + * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExceptionListener} *

* 3. 直接读即可 */ @Test public void exceptionRead() { String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; - // 这里 需要指定读用哪个class去读,然后读取第一个sheet - EasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead(); + // 这里 需要指定读用哪个class去读,然后读取第一个sheet + EasyExcel.read(fileName, ExceptionDemoData.class, new DemoExceptionListener()).sheet().doRead(); } ``` @@ -1123,7 +1140,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja */ @GetMapping("download") public void download(HttpServletResponse response) throws IOException { - // 这里注意 有同学反应下载的文件名不对。这个时候 请别使用swagger 他会有影响 + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index 7134e6f..129b74e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -92,7 +92,6 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { @Override public void execute() { - analysisContext.readSheetHolder().getSheetNo(); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); formatListener = new FormatTrackingHSSFListener(listener); workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); diff --git a/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java b/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java index 74630f0..4af2569 100644 --- a/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java +++ b/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java @@ -1,16 +1,49 @@ package com.alibaba.excel.exception; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.write.builder.ExcelWriterBuilder; + /** * Data convert exception * * @author Jiaju Zhuang */ public class ExcelDataConvertException extends RuntimeException { + /** + * NotNull. + */ + private Integer rowIndex; + /** + * NotNull. + */ + private Integer columnIndex; + /** + * Nullable.Only when the header is configured and when the class header is used is not null. + * + * @see {@link ExcelWriterBuilder#head(Class)} + */ + private ExcelContentProperty excelContentProperty; public ExcelDataConvertException(String message) { super(message); } + public ExcelDataConvertException(Integer rowIndex, Integer columnIndex, ExcelContentProperty excelContentProperty, + String message) { + super(message); + this.rowIndex = rowIndex; + this.columnIndex = columnIndex; + this.excelContentProperty = excelContentProperty; + } + + public ExcelDataConvertException(Integer rowIndex, Integer columnIndex, ExcelContentProperty excelContentProperty, + String message, Throwable cause) { + super(message, cause); + this.rowIndex = rowIndex; + this.columnIndex = columnIndex; + this.excelContentProperty = excelContentProperty; + } + public ExcelDataConvertException(String message, Throwable cause) { super(message, cause); } @@ -18,4 +51,28 @@ public class ExcelDataConvertException extends RuntimeException { public ExcelDataConvertException(Throwable cause) { super(cause); } + + public Integer getRowIndex() { + return rowIndex; + } + + public void setRowIndex(Integer rowIndex) { + this.rowIndex = rowIndex; + } + + public Integer getColumnIndex() { + return columnIndex; + } + + public void setColumnIndex(Integer columnIndex) { + this.columnIndex = columnIndex; + } + + public ExcelContentProperty getExcelContentProperty() { + return excelContentProperty; + } + + public void setExcelContentProperty(ExcelContentProperty excelContentProperty) { + this.excelContentProperty = excelContentProperty; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java index 09d5560..4bffce6 100644 --- a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java +++ b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java @@ -1,6 +1,7 @@ package com.alibaba.excel.metadata.property; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -133,6 +134,13 @@ public class ExcelHeadProperty { ignoreMap.put(field.getName(), field); continue; } + boolean isStaticFinalOrTransient = + (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) + || Modifier.isTransient(field.getModifiers()); + if (excelProperty == null && isStaticFinalOrTransient) { + ignoreMap.put(field.getName(), field); + continue; + } if (excelProperty == null || excelProperty.index() < 0) { defaultFieldList.add(field); continue; diff --git a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java index 6bea593..a368024 100644 --- a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java +++ b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java @@ -33,7 +33,8 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener public void invoke(Map cellDataMap, AnalysisContext context) { ReadHolder currentReadHolder = context.currentReadHolder(); if (HeadKindEnum.CLASS.equals(currentReadHolder.excelReadHeadProperty().getHeadKind())) { - context.readRowHolder().setCurrentRowAnalysisResult(buildUserModel(cellDataMap, currentReadHolder)); + context.readRowHolder() + .setCurrentRowAnalysisResult(buildUserModel(cellDataMap, currentReadHolder, context)); return; } context.readRowHolder().setCurrentRowAnalysisResult(buildStringList(cellDataMap, currentReadHolder, context)); @@ -41,35 +42,51 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener private Object buildStringList(Map cellDataMap, ReadHolder currentReadHolder, AnalysisContext context) { + int index = 0; if (context.readWorkbookHolder().getDefaultReturnMap()) { Map map = new HashMap(cellDataMap.size() * 4 / 3 + 1); for (Map.Entry entry : cellDataMap.entrySet()) { + Integer key = entry.getKey(); CellData cellData = entry.getValue(); + while (index < key) { + map.put(index, null); + index++; + } + index++; if (cellData.getType() == CellDataTypeEnum.EMPTY) { - map.put(entry.getKey(), null); + map.put(key, null); continue; } - map.put(entry.getKey(), (String)ConverterUtils.convertToJavaObject(cellData, null, null, - currentReadHolder.converterMap(), currentReadHolder.globalConfiguration())); + map.put(key, + (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), + currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); } return map; } else { // Compatible with the old code the old code returns a list List list = new ArrayList(); for (Map.Entry entry : cellDataMap.entrySet()) { + Integer key = entry.getKey(); CellData cellData = entry.getValue(); + while (index < key) { + list.add(null); + index++; + } + index++; if (cellData.getType() == CellDataTypeEnum.EMPTY) { list.add(null); continue; } - list.add((String)ConverterUtils.convertToJavaObject(cellData, null, null, - currentReadHolder.converterMap(), currentReadHolder.globalConfiguration())); + list.add( + (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), + currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); } return list; } } - private Object buildUserModel(Map cellDataMap, ReadHolder currentReadHolder) { + private Object buildUserModel(Map cellDataMap, ReadHolder currentReadHolder, + AnalysisContext context) { ExcelReadHeadProperty excelReadHeadProperty = currentReadHolder.excelReadHeadProperty(); Object resultModel; try { @@ -92,7 +109,8 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener } ExcelContentProperty excelContentProperty = contentPropertyMap.get(index); Object value = ConverterUtils.convertToJavaObject(cellData, excelContentProperty.getField(), - excelContentProperty, currentReadHolder.converterMap(), currentReadHolder.globalConfiguration()); + excelContentProperty, currentReadHolder.converterMap(), currentReadHolder.globalConfiguration(), + context.readRowHolder().getRowIndex(), index); if (value != null) { map.put(excelContentProperty.getField().getName(), value); } diff --git a/src/main/java/com/alibaba/excel/util/ConverterUtils.java b/src/main/java/com/alibaba/excel/util/ConverterUtils.java index 1a1e70a..b6244c2 100644 --- a/src/main/java/com/alibaba/excel/util/ConverterUtils.java +++ b/src/main/java/com/alibaba/excel/util/ConverterUtils.java @@ -63,10 +63,13 @@ public class ConverterUtils { * @param contentProperty * @param converterMap * @param globalConfiguration + * @param rowIndex + * @param columnIndex * @return */ public static Object convertToJavaObject(CellData cellData, Field field, ExcelContentProperty contentProperty, - Map converterMap, GlobalConfiguration globalConfiguration) { + Map converterMap, GlobalConfiguration globalConfiguration, Integer rowIndex, + Integer columnIndex) { Class clazz; if (field == null) { clazz = String.class; @@ -83,11 +86,12 @@ public class ConverterUtils { classGeneric = String.class; } CellData cellDataReturn = new CellData(cellData); - cellDataReturn.setData( - doConvertToJavaObject(cellData, classGeneric, contentProperty, converterMap, globalConfiguration)); + cellDataReturn.setData(doConvertToJavaObject(cellData, classGeneric, contentProperty, converterMap, + globalConfiguration, rowIndex, columnIndex)); return cellDataReturn; } - return doConvertToJavaObject(cellData, clazz, contentProperty, converterMap, globalConfiguration); + return doConvertToJavaObject(cellData, clazz, contentProperty, converterMap, globalConfiguration, rowIndex, + columnIndex); } /** @@ -97,10 +101,13 @@ public class ConverterUtils { * @param contentProperty * @param converterMap * @param globalConfiguration + * @param rowIndex + * @param columnIndex * @return */ private static Object doConvertToJavaObject(CellData cellData, Class clazz, ExcelContentProperty contentProperty, - Map converterMap, GlobalConfiguration globalConfiguration) { + Map converterMap, GlobalConfiguration globalConfiguration, Integer rowIndex, + Integer columnIndex) { Converter converter = null; if (contentProperty != null) { converter = contentProperty.getConverter(); @@ -109,13 +116,14 @@ public class ConverterUtils { converter = converterMap.get(ConverterKeyBuild.buildKey(clazz, cellData.getType())); } if (converter == null) { - throw new ExcelDataConvertException( + throw new ExcelDataConvertException(rowIndex, columnIndex, contentProperty, "Converter not found, convert " + cellData.getType() + " to " + clazz.getName()); } try { return converter.convertToJavaData(cellData, contentProperty, globalConfiguration); } catch (Exception e) { - throw new ExcelDataConvertException("Convert data " + cellData + " to " + clazz + " error ", e); + throw new ExcelDataConvertException(rowIndex, columnIndex, contentProperty, + "Convert data " + cellData + " to " + clazz + " error ", e); } } } diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java index 5e699c3..3faad69 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java @@ -79,6 +79,17 @@ public class ExcelWriterBuilder { return this; } + /** + * Use the default style.Default is true. + * + * @param useDefaultStyle + * @return + */ + public ExcelWriterBuilder useDefaultStyle(Boolean useDefaultStyle) { + writeWorkbook.setUseDefaultStyle(useDefaultStyle); + return this; + } + /** * The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a * field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed. diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java index 8a9e0c6..26acff5 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java @@ -74,6 +74,17 @@ public class ExcelWriterSheetBuilder { return this; } + /** + * Use the default style.Default is true. + * + * @param useDefaultStyle + * @return + */ + public ExcelWriterSheetBuilder useDefaultStyle(Boolean useDefaultStyle) { + writeSheet.setUseDefaultStyle(useDefaultStyle); + return this; + } + /** * Custom type conversions override the default. * diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java index 14f755a..eca1fe0 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java @@ -78,6 +78,17 @@ public class ExcelWriterTableBuilder { return this; } + /** + * Use the default style.Default is true. + * + * @param useDefaultStyle + * @return + */ + public ExcelWriterTableBuilder useDefaultStyle(Boolean useDefaultStyle) { + writeTable.setUseDefaultStyle(useDefaultStyle); + return this; + } + /** * Custom type conversions override the default. * diff --git a/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java index f52af6b..dff84d7 100644 --- a/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java +++ b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java @@ -21,16 +21,18 @@ public class DefaultWriteHandlerLoader { * * @return */ - public static List loadDefaultHandler() { + public static List loadDefaultHandler(Boolean useDefaultStyle) { List handlerList = new ArrayList(); - WriteCellStyle headWriteCellStyle = new WriteCellStyle(); - headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); - WriteFont headWriteFont = new WriteFont(); - headWriteFont.setFontName("宋体"); - headWriteFont.setFontHeightInPoints((short)14); - headWriteFont.setBold(true); - headWriteCellStyle.setWriteFont(headWriteFont); - handlerList.add(new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList())); + if (useDefaultStyle) { + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontName("宋体"); + headWriteFont.setFontHeightInPoints((short)14); + headWriteFont.setBold(true); + headWriteCellStyle.setWriteFont(headWriteFont); + handlerList.add(new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList())); + } return handlerList; } diff --git a/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java b/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java index 3a43ff6..2689cd9 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java +++ b/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java @@ -24,6 +24,10 @@ public class WriteBasicParameter extends BasicParameter { * Custom type handler override the default */ private List customWriteHandlerList = new ArrayList(); + /** + * Use the default style.Default is true. + */ + private Boolean useDefaultStyle; public Integer getRelativeHeadRowIndex() { return relativeHeadRowIndex; @@ -48,4 +52,12 @@ public class WriteBasicParameter extends BasicParameter { public void setCustomWriteHandlerList(List customWriteHandlerList) { this.customWriteHandlerList = customWriteHandlerList; } + + public Boolean getUseDefaultStyle() { + return useDefaultStyle; + } + + public void setUseDefaultStyle(Boolean useDefaultStyle) { + this.useDefaultStyle = useDefaultStyle; + } } diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java index 80d3e7b..72f5f9b 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java @@ -61,6 +61,10 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ * Write handler for workbook */ private Map, List> writeHandlerMap; + /** + * Use the default style.Default is true. + */ + private Boolean useDefaultStyle; public AbstractWriteHolder(WriteBasicParameter writeBasicParameter, AbstractWriteHolder parentAbstractWriteHolder, Boolean convertAllFiled) { @@ -96,6 +100,16 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ this.relativeHeadRowIndex = writeBasicParameter.getRelativeHeadRowIndex(); } + if (writeBasicParameter.getUseDefaultStyle() == null) { + if (parentAbstractWriteHolder == null) { + this.useDefaultStyle = Boolean.TRUE; + } else { + this.useDefaultStyle = parentAbstractWriteHolder.getUseDefaultStyle(); + } + } else { + this.useDefaultStyle = writeBasicParameter.getUseDefaultStyle(); + } + // Initialization property this.excelWriteHeadProperty = new ExcelWriteHeadProperty(getClazz(), getHead(), convertAllFiled); @@ -117,7 +131,7 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ if (parentAbstractWriteHolder != null) { parentWriteHandlerMap = parentAbstractWriteHolder.getWriteHandlerMap(); } else { - handlerList.addAll(DefaultWriteHandlerLoader.loadDefaultHandler()); + handlerList.addAll(DefaultWriteHandlerLoader.loadDefaultHandler(useDefaultStyle)); } this.writeHandlerMap = sortAndClearUpHandler(handlerList, parentWriteHandlerMap); @@ -134,6 +148,7 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ getConverterMap().put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); } } + } /** @@ -360,6 +375,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ this.relativeHeadRowIndex = relativeHeadRowIndex; } + public Boolean getUseDefaultStyle() { + return useDefaultStyle; + } + + public void setUseDefaultStyle(Boolean useDefaultStyle) { + this.useDefaultStyle = useDefaultStyle; + } + @Override public ExcelWriteHeadProperty excelWriteHeadProperty() { return getExcelWriteHeadProperty(); diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java index 2a028f3..f1e9119 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java @@ -29,4 +29,6 @@ public class AnnotationData { private Double number; @ExcelIgnore private String ignore; + private static final String staticFinal = "test"; + private transient String transientString; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataTest.java index 5acd5db..4489f1c 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataTest.java @@ -48,6 +48,7 @@ public class AnnotationDataTest { data.setDate(DateUtils.parseDate("2020-01-01 01:01:01")); data.setNumber(99.99); data.setIgnore("忽略"); + data.setTransientString("忽略"); list.add(data); return list; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataListener.java index ffad838..d9c26e2 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataListener.java @@ -20,7 +20,7 @@ public class ExceptionDataListener extends AnalysisEventListener @Override public void onException(Exception exception, AnalysisContext context) { - LOGGER.info("抛出异常,忽略:{}", exception.getMessage()); + LOGGER.info("抛出异常,忽略:{}", exception.getMessage(), exception); } @Override diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataDemoHeadDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataDemoHeadDataListener.java new file mode 100644 index 0000000..896cea6 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataDemoHeadDataListener.java @@ -0,0 +1,50 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.fastjson.JSON; + +/** + * 读取头 + * + * @author Jiaju Zhuang + */ +public class CellDataDemoHeadDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(CellDataDemoHeadDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(CellDataReadDemoData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataReadDemoData.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataReadDemoData.java new file mode 100644 index 0000000..f5d01e0 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/CellDataReadDemoData.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.Date; + +import com.alibaba.excel.metadata.CellData; + +import lombok.Data; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class CellDataReadDemoData { + private CellData string; + // 这里注意 虽然是日期 但是 类型 存储的是number 因为excel 存储的就是number + private CellData date; + private CellData doubleData; + // 这里并不一定能完美的获取 有些公式是依赖性的 可能会读不到 这个问题后续会修复 + private CellData formulaValue; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java index bf4dd63..434af3b 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java @@ -15,6 +15,7 @@ import com.alibaba.fastjson.JSON; * * @author Jiaju Zhuang */ +// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 public class DemoDataListener extends AnalysisEventListener { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); /** diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExceptionListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExceptionListener.java new file mode 100644 index 0000000..0f00719 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExceptionListener.java @@ -0,0 +1,80 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.fastjson.JSON; + +/** + * 读取转换异常 + * + * @author Jiaju Zhuang + */ +public class DemoExceptionListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoExceptionListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + /** + * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。 + * + * @param exception + * @param context + * @throws Exception + */ + @Override + public void onException(Exception exception, AnalysisContext context) { + LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage()); + // 如果是某一个单元格的转换异常 能获取到具体行号 + // 如果要获取头的信息 配合invokeHeadMap使用 + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; + LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), + excelDataConvertException.getColumnIndex()); + } + } + + /** + * 这里会一行行的返回头 + * + * @param headMap + * @param context + */ + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap)); + } + + @Override + public void invoke(ExceptionDemoData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoHeadDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoHeadDataListener.java index bc55052..184409a 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoHeadDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoHeadDataListener.java @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.fastjson.JSON; /** @@ -34,7 +35,12 @@ public class DemoHeadDataListener extends AnalysisEventListener { */ @Override public void onException(Exception exception, AnalysisContext context) { - LOGGER.error("解析失败,但是继续解析下一行", exception); + LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage()); + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; + LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), + excelDataConvertException.getColumnIndex()); + } } /** diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ExceptionDemoData.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ExceptionDemoData.java new file mode 100644 index 0000000..8040728 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ExceptionDemoData.java @@ -0,0 +1,18 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.Date; + +import lombok.Data; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class ExceptionDemoData { + /** + * 用日期去接字符串 肯定报错 + */ + private Date date; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java index 06ca4b6..3fb514c 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java @@ -39,6 +39,7 @@ public class ReadTest { */ @Test public void simpleRead() { + // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 // 写法1: String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 @@ -164,7 +165,7 @@ public class ReadTest { } /** - * 数据转换等异常处理 + * 读取公式和单元格类型 * *

* 1. 创建excel对应的实体对象 参照{@link DemoData} @@ -174,10 +175,27 @@ public class ReadTest { * 3. 直接读即可 */ @Test + public void cellDataRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "cellDataDemo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet + EasyExcel.read(fileName, CellDataReadDemoData.class, new CellDataDemoHeadDataListener()).sheet().doRead(); + } + + /** + * 数据转换等异常处理 + * + *

+ * 1. 创建excel对应的实体对象 参照{@link ExceptionDemoData} + *

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExceptionListener} + *

+ * 3. 直接读即可 + */ + @Test public void exceptionRead() { String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet - EasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead(); + EasyExcel.read(fileName, ExceptionDemoData.class, new DemoExceptionListener()).sheet().doRead(); } /** diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java index 8fff02c..cc52562 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java @@ -36,7 +36,7 @@ public class WebTest { */ @GetMapping("download") public void download(HttpServletResponse response) throws IOException { - // 这里注意 有同学反应下载的文件名不对。这个时候 请别使用swagger 他会有影响 + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java index 2e8931c..fb39de1 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java @@ -3,6 +3,7 @@ package com.alibaba.easyexcel.test.temp; import java.io.File; import java.io.FileInputStream; import java.util.List; +import java.util.Map; import org.junit.Ignore; import org.junit.Test; @@ -35,4 +36,14 @@ public class LockTest { } } + @Test + public void test2() throws Exception { + List list = + EasyExcel.read(new FileInputStream("D:\\test\\null.xlsx")).sheet().headRowNumber(0).doReadSync(); + for (Object data : list) { + LOGGER.info("返回数据:{}", ((Map)data).size()); + LOGGER.info("返回数据:{}", JSON.toJSONString(data)); + } + } + } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java index 5c1620e..3a70d0d 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java @@ -18,6 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.metadata.CellData; +import com.alibaba.fastjson.JSON; import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; @@ -30,21 +31,49 @@ import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; public class PoiWriteTest { private static final Logger LOGGER = LoggerFactory.getLogger(PoiWriteTest.class); + @Test + public void write0() throws IOException { + FileOutputStream fileOutputStream = + new FileOutputStream("D://test//tt132" + System.currentTimeMillis() + ".xlsx"); + SXSSFWorkbook sxxsFWorkbook = new SXSSFWorkbook(); + SXSSFSheet sheet = sxxsFWorkbook.createSheet("t1"); + SXSSFRow row = sheet.createRow(0); + SXSSFCell cell1 = row.createCell(0); + cell1.setCellValue(999999999999999L); + SXSSFCell cell2 = row.createCell(1); + cell2.setCellValue(1000000000000001L); + sxxsFWorkbook.write(fileOutputStream); + } + @Test public void write() throws IOException { - FileOutputStream fileOutputStream = new FileOutputStream("D://test//tt12.xlsx"); + FileOutputStream fileOutputStream = + new FileOutputStream("D://test//tt132" + System.currentTimeMillis() + ".xlsx"); SXSSFWorkbook sxxsFWorkbook = new SXSSFWorkbook(); SXSSFSheet sheet = sxxsFWorkbook.createSheet("t1"); SXSSFRow row = sheet.createRow(0); SXSSFCell cell1 = row.createCell(0); - cell1.setCellValue(1); + cell1.setCellValue(Long.toString(999999999999999L)); SXSSFCell cell2 = row.createCell(1); - cell2.setCellValue(1); - SXSSFCell cell3 = row.createCell(2); - cell3.setCellFormula("=A1+B1"); + cell2.setCellValue(Long.toString(1000000000000001L)); sxxsFWorkbook.write(fileOutputStream); } + @Test + public void write1() throws IOException { + System.out.println(JSON.toJSONString(long2Bytes(-999999999999999L))); + System.out.println(JSON.toJSONString(long2Bytes(-9999999999999999L))); + } + + public static byte[] long2Bytes(long num) { + byte[] byteNum = new byte[8]; + for (int ix = 0; ix < 8; ++ix) { + int offset = 64 - (ix + 1) * 8; + byteNum[ix] = (byte)((num >> offset) & 0xff); + } + return byteNum; + } + private static final Pattern FILL_PATTERN = Pattern.compile("^.*?\\$\\{[^}]+}.*?$"); @Test diff --git a/src/test/resources/demo/cellDataDemo.xlsx b/src/test/resources/demo/cellDataDemo.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..947229c70e166e5b65a9f19b27fe3af85cf4a026 GIT binary patch literal 10323 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 literal 0 HcmV?d00001 diff --git a/update.md b/update.md index b4dde63..04eec04 100644 --- a/update.md +++ b/update.md @@ -2,6 +2,10 @@ * 新增支持导入、导出支持公式 * 新增支持读取单元格类型、写入指定单元格类型 * 支持通过模板填充数据 +* 新增写支持 禁用头样式 autoHeadStyle +* 用map读取数据 空的单元格也会有个 null的数据 +* 转换报错 能获取到对应的行号和列号 +* 优化读取全部sheet方案 # 2.0.5 * 优化07版超大文件读取方案