diff --git a/README.md b/README.md
index fd5c5a2f..1251ebd2 100644
--- a/README.md
+++ b/README.md
@@ -62,16 +62,19 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java)
```java
/**
- * 文件下载
+ * 文件下载(失败了会返回一个有部分数据的Excel)
*
1. 创建excel对应的实体对象 参照{@link DownloadData}
*
2. 设置返回的 参数
*
3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
+ // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
- response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
+ // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
+ String fileName = URLEncoder.encode("测试", "UTF-8");
+ response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}
@@ -84,7 +87,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
- EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener()).sheet().doRead();
+ EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
return "success";
}
```
diff --git a/src/main/java/com/alibaba/excel/ExcelReader.java b/src/main/java/com/alibaba/excel/ExcelReader.java
index 0887e325..07a373b7 100644
--- a/src/main/java/com/alibaba/excel/ExcelReader.java
+++ b/src/main/java/com/alibaba/excel/ExcelReader.java
@@ -14,7 +14,6 @@ import com.alibaba.excel.analysis.ExcelReadExecutor;
import com.alibaba.excel.cache.MapCache;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
-import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.parameter.AnalysisParam;
import com.alibaba.excel.read.listener.ReadListener;
@@ -35,8 +34,6 @@ public class ExcelReader {
*/
private ExcelAnalyser excelAnalyser;
- private boolean finished = false;
-
/**
* Create new reader
*
@@ -160,7 +157,6 @@ public class ExcelReader {
* Parse all sheet content by default
*/
public void readAll() {
- checkFinished();
excelAnalyser.analysis(null, Boolean.TRUE);
}
@@ -181,7 +177,6 @@ public class ExcelReader {
* @return
*/
public ExcelReader read(List readSheetList) {
- checkFinished();
excelAnalyser.analysis(readSheetList, Boolean.FALSE);
return this;
}
@@ -231,7 +226,6 @@ public class ExcelReader {
* @return
*/
public AnalysisContext analysisContext() {
- checkFinished();
return excelAnalyser.analysisContext();
}
@@ -241,7 +235,6 @@ public class ExcelReader {
* @return
*/
public ExcelReadExecutor excelExecutor() {
- checkFinished();
return excelAnalyser.excelExecutor();
}
@@ -281,10 +274,6 @@ public class ExcelReader {
* Complete the entire read file.Release the cache and close stream.
*/
public void finish() {
- if (finished) {
- return;
- }
- finished = true;
excelAnalyser.finish();
}
@@ -294,19 +283,11 @@ public class ExcelReader {
*/
@Override
protected void finalize() {
- if (finished) {
- return;
- }
try {
- excelAnalyser.finish();
+ finish();
} catch (Throwable e) {
LOGGER.warn("Destroy object failed", e);
}
}
- private void checkFinished() {
- if (finished) {
- throw new ExcelAnalysisException("Can not use a finished reader.");
- }
- }
}
diff --git a/src/main/java/com/alibaba/excel/ExcelWriter.java b/src/main/java/com/alibaba/excel/ExcelWriter.java
index 65a99fe5..a0b4795b 100644
--- a/src/main/java/com/alibaba/excel/ExcelWriter.java
+++ b/src/main/java/com/alibaba/excel/ExcelWriter.java
@@ -5,6 +5,9 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
@@ -31,6 +34,8 @@ import com.alibaba.excel.write.metadata.fill.FillConfig;
* @author jipengfei
*/
public class ExcelWriter {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ExcelWriter.class);
+
private ExcelBuilder excelBuilder;
/**
@@ -320,7 +325,20 @@ public class ExcelWriter {
* Close IO
*/
public void finish() {
- excelBuilder.finish();
+ excelBuilder.finish(false);
+ }
+
+ /**
+ * Prevents calls to {@link #finish} from freeing the cache
+ *
+ */
+ @Override
+ protected void finalize() {
+ try {
+ finish();
+ } catch (Throwable e) {
+ LOGGER.warn("Destroy object failed", e);
+ }
}
/**
diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
index 4002b843..f3ef9505 100644
--- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
+++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
@@ -34,6 +34,10 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
private AnalysisContext analysisContext;
private ExcelReadExecutor excelReadExecutor;
+ /**
+ * Prevent multiple shutdowns
+ */
+ private boolean finished = false;
public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {
try {
@@ -121,6 +125,10 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
@Override
public void finish() {
+ if (finished) {
+ return;
+ }
+ finished = true;
if (analysisContext == null || analysisContext.readWorkbookHolder() == null) {
return;
}
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 a489ccec..76a869ae 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
@@ -121,7 +121,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
private void init() {
lastRowNumber = 0;
lastColumnNumber = 0;
- records = new TreeMap();
+ records = new LinkedHashMap();
buildXlsRecordHandlers();
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
index 3a862942..083edbc7 100644
--- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
@@ -73,7 +73,7 @@ public class BofRecordHandler extends AbstractXlsRecordHandler {
readSheet = SheetUtils.match(readSheet, readSheetList, readAll,
context.readWorkbookHolder().getGlobalConfiguration());
if (readSheet != null) {
- if (readSheet.getSheetNo() != 0) {
+ if (readSheet.getSheetNo() != 0 && context.readSheetHolder() != null) {
// Prompt for the end of the previous form read
context.readSheetHolder().notifyAfterAllAnalysed(context);
}
diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
index 002999d6..e0b9c413 100644
--- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
+++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
@@ -12,7 +12,6 @@ import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
-import java.util.TreeMap;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.xssf.model.StylesTable;
@@ -55,7 +54,7 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder
@Override
public void clearResult() {
- curRowContent = new TreeMap();
+ curRowContent = new LinkedHashMap();
}
@Override
diff --git a/src/main/java/com/alibaba/excel/context/WriteContext.java b/src/main/java/com/alibaba/excel/context/WriteContext.java
index c6e85c94..0a59e1d0 100644
--- a/src/main/java/com/alibaba/excel/context/WriteContext.java
+++ b/src/main/java/com/alibaba/excel/context/WriteContext.java
@@ -66,9 +66,10 @@ public interface WriteContext {
/**
* close
+ *
+ * @param onException
*/
- void finish();
-
+ void finish(boolean onException);
/**
* Current sheet
diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
index ec49ea3e..3f2b51a4 100644
--- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
+++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
@@ -65,6 +65,10 @@ public class WriteContextImpl implements WriteContext {
* Configuration of currently operated cell
*/
private WriteHolder currentWriteHolder;
+ /**
+ * Prevent multiple shutdowns
+ */
+ private boolean finished = false;
public WriteContextImpl(WriteWorkbook writeWorkbook) {
if (writeWorkbook == null) {
@@ -249,23 +253,36 @@ public class WriteContextImpl implements WriteContext {
}
@Override
- public void finish() {
+ public void finish(boolean onException) {
+ if (finished) {
+ return;
+ }
+ finished = true;
WriteHandlerUtils.afterWorkbookDispose(this);
if (writeWorkbookHolder == null) {
return;
}
Throwable throwable = null;
-
boolean isOutputStreamEncrypt = false;
- try {
- isOutputStreamEncrypt = doOutputStreamEncrypt07();
- } catch (Throwable t) {
- throwable = t;
+ // Determine if you need to write excel
+ boolean writeExcel = !onException;
+ if (writeWorkbookHolder.getWriteExcelOnException()) {
+ writeExcel = Boolean.TRUE;
+ }
+ // No data is written if an exception is thrown
+ if (writeExcel) {
+ try {
+ isOutputStreamEncrypt = doOutputStreamEncrypt07();
+ } catch (Throwable t) {
+ throwable = t;
+ }
}
if (!isOutputStreamEncrypt) {
try {
- writeWorkbookHolder.getWorkbook().write(writeWorkbookHolder.getOutputStream());
+ if (writeExcel) {
+ writeWorkbookHolder.getWorkbook().write(writeWorkbookHolder.getOutputStream());
+ }
writeWorkbookHolder.getWorkbook().close();
} catch (Throwable t) {
throwable = t;
@@ -289,7 +306,7 @@ public class WriteContextImpl implements WriteContext {
throwable = t;
}
- if (!isOutputStreamEncrypt) {
+ if (writeExcel && !isOutputStreamEncrypt) {
try {
doFileEncrypt07();
} catch (Throwable t) {
diff --git a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
index e53c1f85..77e8b592 100644
--- a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
+++ b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
@@ -37,6 +37,7 @@ import com.alibaba.excel.converters.string.StringBooleanConverter;
import com.alibaba.excel.converters.string.StringErrorConverter;
import com.alibaba.excel.converters.string.StringNumberConverter;
import com.alibaba.excel.converters.string.StringStringConverter;
+import com.alibaba.excel.converters.url.UrlImageConverter;
/**
* Load default handler
@@ -71,6 +72,7 @@ public class DefaultConverterLoader {
putWriteConverter(new InputStreamImageConverter());
putWriteConverter(new ByteArrayImageConverter());
putWriteConverter(new BoxingByteArrayImageConverter());
+ putWriteConverter(new UrlImageConverter());
return defaultWriteConverter;
}
diff --git a/src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java b/src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java
new file mode 100644
index 00000000..b622d66d
--- /dev/null
+++ b/src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java
@@ -0,0 +1,52 @@
+package com.alibaba.excel.converters.url;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+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.IoUtils;
+
+/**
+ * Url and image converter
+ *
+ * @since 2.1.1
+ * @author Jiaju Zhuang
+ */
+public class UrlImageConverter implements Converter {
+ @Override
+ public Class supportJavaTypeKey() {
+ return URL.class;
+ }
+
+ @Override
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return CellDataTypeEnum.IMAGE;
+ }
+
+ @Override
+ public URL convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
+ GlobalConfiguration globalConfiguration) {
+ throw new UnsupportedOperationException("Cannot convert images to url.");
+ }
+
+ @Override
+ public CellData convertToExcelData(URL value, ExcelContentProperty contentProperty,
+ GlobalConfiguration globalConfiguration) throws IOException {
+ InputStream inputStream = null;
+ try {
+ inputStream = value.openStream();
+ byte[] bytes = IoUtils.toByteArray(inputStream);
+ return new CellData(bytes);
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
index af3b05e1..d494e233 100644
--- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
+++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
@@ -166,7 +166,7 @@ public class ExcelReaderSheetBuilder {
*
* @return
*/
- public List