Browse Source

修改同步读取返回对象支持泛型

2.1.x
Jiaju Zhuang 5 years ago
parent
commit
2205ade4be
  1. 9
      README.md
  2. 21
      src/main/java/com/alibaba/excel/ExcelReader.java
  3. 20
      src/main/java/com/alibaba/excel/ExcelWriter.java
  4. 8
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  5. 2
      src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
  6. 2
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
  7. 3
      src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
  8. 5
      src/main/java/com/alibaba/excel/context/WriteContext.java
  9. 23
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  10. 2
      src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
  11. 52
      src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java
  12. 4
      src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java
  13. 3
      src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java
  14. 11
      src/main/java/com/alibaba/excel/util/ConverterUtils.java
  15. 3
      src/main/java/com/alibaba/excel/util/DateUtils.java
  16. 5
      src/main/java/com/alibaba/excel/write/ExcelBuilder.java
  17. 24
      src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
  18. 8
      src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java
  19. 12
      src/main/java/com/alibaba/excel/write/metadata/WriteWorkbook.java
  20. 22
      src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java
  21. 11
      src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java
  22. 15
      src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDAO.java
  23. 34
      src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java
  24. 10
      src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java
  25. 20
      src/test/java/com/alibaba/easyexcel/test/demo/web/UploadDAO.java
  26. 38
      src/test/java/com/alibaba/easyexcel/test/demo/web/UploadDataListener.java
  27. 43
      src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java
  28. 7
      src/test/java/com/alibaba/easyexcel/test/demo/write/ImageData.java
  29. 5
      src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java
  30. 42
      src/test/java/com/alibaba/easyexcel/test/temp/read/HDListener.java
  31. 18
      src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java
  32. 25
      src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java
  33. 9
      update.md

9
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) 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 ```java
/** /**
* 文件下载 * 文件下载(失败了会返回一个有部分数据的Excel)
* <p>1. 创建excel对应的实体对象 参照{@link DownloadData} * <p>1. 创建excel对应的实体对象 参照{@link DownloadData}
* <p>2. 设置返回的 参数 * <p>2. 设置返回的 参数
* <p>3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大 * <p>3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/ */
@GetMapping("download") @GetMapping("download")
public void download(HttpServletResponse response) throws IOException { public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel"); response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8"); 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()); 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") @PostMapping("upload")
@ResponseBody @ResponseBody
public String upload(MultipartFile file) throws IOException { 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"; return "success";
} }
``` ```

21
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.cache.MapCache;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.parameter.AnalysisParam; import com.alibaba.excel.parameter.AnalysisParam;
import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.listener.ReadListener;
@ -35,8 +34,6 @@ public class ExcelReader {
*/ */
private ExcelAnalyser excelAnalyser; private ExcelAnalyser excelAnalyser;
private boolean finished = false;
/** /**
* Create new reader * Create new reader
* *
@ -160,7 +157,6 @@ public class ExcelReader {
* Parse all sheet content by default * Parse all sheet content by default
*/ */
public void readAll() { public void readAll() {
checkFinished();
excelAnalyser.analysis(null, Boolean.TRUE); excelAnalyser.analysis(null, Boolean.TRUE);
} }
@ -181,7 +177,6 @@ public class ExcelReader {
* @return * @return
*/ */
public ExcelReader read(List<ReadSheet> readSheetList) { public ExcelReader read(List<ReadSheet> readSheetList) {
checkFinished();
excelAnalyser.analysis(readSheetList, Boolean.FALSE); excelAnalyser.analysis(readSheetList, Boolean.FALSE);
return this; return this;
} }
@ -231,7 +226,6 @@ public class ExcelReader {
* @return * @return
*/ */
public AnalysisContext analysisContext() { public AnalysisContext analysisContext() {
checkFinished();
return excelAnalyser.analysisContext(); return excelAnalyser.analysisContext();
} }
@ -241,7 +235,6 @@ public class ExcelReader {
* @return * @return
*/ */
public ExcelReadExecutor excelExecutor() { public ExcelReadExecutor excelExecutor() {
checkFinished();
return excelAnalyser.excelExecutor(); return excelAnalyser.excelExecutor();
} }
@ -281,10 +274,6 @@ public class ExcelReader {
* Complete the entire read file.Release the cache and close stream. * Complete the entire read file.Release the cache and close stream.
*/ */
public void finish() { public void finish() {
if (finished) {
return;
}
finished = true;
excelAnalyser.finish(); excelAnalyser.finish();
} }
@ -294,19 +283,11 @@ public class ExcelReader {
*/ */
@Override @Override
protected void finalize() { protected void finalize() {
if (finished) {
return;
}
try { try {
excelAnalyser.finish(); finish();
} catch (Throwable e) { } catch (Throwable e) {
LOGGER.warn("Destroy object failed", e); LOGGER.warn("Destroy object failed", e);
} }
} }
private void checkFinished() {
if (finished) {
throw new ExcelAnalysisException("Can not use a finished reader.");
}
}
} }

20
src/main/java/com/alibaba/excel/ExcelWriter.java

@ -5,6 +5,9 @@ import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table; import com.alibaba.excel.metadata.Table;
@ -31,6 +34,8 @@ import com.alibaba.excel.write.metadata.fill.FillConfig;
* @author jipengfei * @author jipengfei
*/ */
public class ExcelWriter { public class ExcelWriter {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelWriter.class);
private ExcelBuilder excelBuilder; private ExcelBuilder excelBuilder;
/** /**
@ -320,7 +325,20 @@ public class ExcelWriter {
* Close IO * Close IO
*/ */
public void finish() { 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);
}
} }
/** /**

8
src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java

@ -34,6 +34,10 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
private AnalysisContext analysisContext; private AnalysisContext analysisContext;
private ExcelReadExecutor excelReadExecutor; private ExcelReadExecutor excelReadExecutor;
/**
* Prevent multiple shutdowns
*/
private boolean finished = false;
public ExcelAnalyserImpl(ReadWorkbook readWorkbook) { public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {
try { try {
@ -121,6 +125,10 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
@Override @Override
public void finish() { public void finish() {
if (finished) {
return;
}
finished = true;
if (analysisContext == null || analysisContext.readWorkbookHolder() == null) { if (analysisContext == null || analysisContext.readWorkbookHolder() == null) {
return; return;
} }

2
src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java

@ -121,7 +121,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
private void init() { private void init() {
lastRowNumber = 0; lastRowNumber = 0;
lastColumnNumber = 0; lastColumnNumber = 0;
records = new TreeMap<Integer, CellData>(); records = new LinkedHashMap<Integer, CellData>();
buildXlsRecordHandlers(); buildXlsRecordHandlers();
} }

2
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, readSheet = SheetUtils.match(readSheet, readSheetList, readAll,
context.readWorkbookHolder().getGlobalConfiguration()); context.readWorkbookHolder().getGlobalConfiguration());
if (readSheet != null) { if (readSheet != null) {
if (readSheet.getSheetNo() != 0) { if (readSheet.getSheetNo() != 0 && context.readSheetHolder() != null) {
// Prompt for the end of the previous form read // Prompt for the end of the previous form read
context.readSheetHolder().notifyAfterAllAnalysed(context); context.readSheetHolder().notifyAfterAllAnalysed(context);
} }

3
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.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import org.apache.poi.ss.usermodel.BuiltinFormats; import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.model.StylesTable;
@ -55,7 +54,7 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder
@Override @Override
public void clearResult() { public void clearResult() {
curRowContent = new TreeMap<Integer, CellData>(); curRowContent = new LinkedHashMap<Integer, CellData>();
} }
@Override @Override

5
src/main/java/com/alibaba/excel/context/WriteContext.java

@ -66,9 +66,10 @@ public interface WriteContext {
/** /**
* close * close
*
* @param onException
*/ */
void finish(); void finish(boolean onException);
/** /**
* Current sheet * Current sheet

23
src/main/java/com/alibaba/excel/context/WriteContextImpl.java

@ -65,6 +65,10 @@ public class WriteContextImpl implements WriteContext {
* Configuration of currently operated cell * Configuration of currently operated cell
*/ */
private WriteHolder currentWriteHolder; private WriteHolder currentWriteHolder;
/**
* Prevent multiple shutdowns
*/
private boolean finished = false;
public WriteContextImpl(WriteWorkbook writeWorkbook) { public WriteContextImpl(WriteWorkbook writeWorkbook) {
if (writeWorkbook == null) { if (writeWorkbook == null) {
@ -249,23 +253,36 @@ public class WriteContextImpl implements WriteContext {
} }
@Override @Override
public void finish() { public void finish(boolean onException) {
if (finished) {
return;
}
finished = true;
WriteHandlerUtils.afterWorkbookDispose(this); WriteHandlerUtils.afterWorkbookDispose(this);
if (writeWorkbookHolder == null) { if (writeWorkbookHolder == null) {
return; return;
} }
Throwable throwable = null; Throwable throwable = null;
boolean isOutputStreamEncrypt = false; boolean isOutputStreamEncrypt = false;
// 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 { try {
isOutputStreamEncrypt = doOutputStreamEncrypt07(); isOutputStreamEncrypt = doOutputStreamEncrypt07();
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;
} }
}
if (!isOutputStreamEncrypt) { if (!isOutputStreamEncrypt) {
try { try {
if (writeExcel) {
writeWorkbookHolder.getWorkbook().write(writeWorkbookHolder.getOutputStream()); writeWorkbookHolder.getWorkbook().write(writeWorkbookHolder.getOutputStream());
}
writeWorkbookHolder.getWorkbook().close(); writeWorkbookHolder.getWorkbook().close();
} catch (Throwable t) { } catch (Throwable t) {
throwable = t; throwable = t;
@ -289,7 +306,7 @@ public class WriteContextImpl implements WriteContext {
throwable = t; throwable = t;
} }
if (!isOutputStreamEncrypt) { if (writeExcel && !isOutputStreamEncrypt) {
try { try {
doFileEncrypt07(); doFileEncrypt07();
} catch (Throwable t) { } catch (Throwable t) {

2
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.StringErrorConverter;
import com.alibaba.excel.converters.string.StringNumberConverter; import com.alibaba.excel.converters.string.StringNumberConverter;
import com.alibaba.excel.converters.string.StringStringConverter; import com.alibaba.excel.converters.string.StringStringConverter;
import com.alibaba.excel.converters.url.UrlImageConverter;
/** /**
* Load default handler * Load default handler
@ -71,6 +72,7 @@ public class DefaultConverterLoader {
putWriteConverter(new InputStreamImageConverter()); putWriteConverter(new InputStreamImageConverter());
putWriteConverter(new ByteArrayImageConverter()); putWriteConverter(new ByteArrayImageConverter());
putWriteConverter(new BoxingByteArrayImageConverter()); putWriteConverter(new BoxingByteArrayImageConverter());
putWriteConverter(new UrlImageConverter());
return defaultWriteConverter; return defaultWriteConverter;
} }

52
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<URL> {
@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();
}
}
}
}

4
src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java

@ -166,7 +166,7 @@ public class ExcelReaderSheetBuilder {
* *
* @return * @return
*/ */
public List<Object> doReadSync() { public <T> List<T> doReadSync() {
if (excelReader == null) { if (excelReader == null) {
throw new ExcelAnalysisException("Must use 'EasyExcelFactory.read().sheet()' to call this method"); throw new ExcelAnalysisException("Must use 'EasyExcelFactory.read().sheet()' to call this method");
} }
@ -174,7 +174,7 @@ public class ExcelReaderSheetBuilder {
registerReadListener(syncReadListener); registerReadListener(syncReadListener);
excelReader.read(build()); excelReader.read(build());
excelReader.finish(); excelReader.finish();
return syncReadListener.getList(); return (List<T>)syncReadListener.getList();
} }
} }

3
src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java

@ -208,6 +208,9 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH
List<String> headNameList = headData.getHeadNameList(); List<String> headNameList = headData.getHeadNameList();
String headName = headNameList.get(headNameList.size() - 1); String headName = headNameList.get(headNameList.size() - 1);
for (Map.Entry<Integer, String> stringEntry : dataMap.entrySet()) { for (Map.Entry<Integer, String> stringEntry : dataMap.entrySet()) {
if (stringEntry == null) {
continue;
}
String headString = stringEntry.getValue(); String headString = stringEntry.getValue();
Integer stringKey = stringEntry.getKey(); Integer stringKey = stringEntry.getKey();
if (StringUtils.isEmpty(headString)) { if (StringUtils.isEmpty(headString)) {

11
src/main/java/com/alibaba/excel/util/ConverterUtils.java

@ -33,10 +33,17 @@ public class ConverterUtils {
*/ */
public static Map<Integer, String> convertToStringMap(Map<Integer, CellData> cellDataMap, ReadHolder readHolder) { public static Map<Integer, String> convertToStringMap(Map<Integer, CellData> cellDataMap, ReadHolder readHolder) {
Map<Integer, String> stringMap = new HashMap<Integer, String>(cellDataMap.size() * 4 / 3 + 1); Map<Integer, String> stringMap = new HashMap<Integer, String>(cellDataMap.size() * 4 / 3 + 1);
int index = 0;
for (Map.Entry<Integer, CellData> entry : cellDataMap.entrySet()) { for (Map.Entry<Integer, CellData> entry : cellDataMap.entrySet()) {
Integer key = entry.getKey();
CellData cellData = entry.getValue(); CellData cellData = entry.getValue();
while (index < key) {
stringMap.put(index, null);
index++;
}
index++;
if (cellData.getType() == CellDataTypeEnum.EMPTY) { if (cellData.getType() == CellDataTypeEnum.EMPTY) {
stringMap.put(entry.getKey(), null); stringMap.put(key, null);
continue; continue;
} }
Converter converter = Converter converter =
@ -46,7 +53,7 @@ public class ConverterUtils {
"Converter not found, convert " + cellData.getType() + " to String"); "Converter not found, convert " + cellData.getType() + " to String");
} }
try { try {
stringMap.put(entry.getKey(), stringMap.put(key,
(String)(converter.convertToJavaData(cellData, null, readHolder.globalConfiguration()))); (String)(converter.convertToJavaData(cellData, null, readHolder.globalConfiguration())));
} catch (Exception e) { } catch (Exception e) {
throw new ExcelDataConvertException("Convert data " + cellData + " to String error ", e); throw new ExcelDataConvertException("Convert data " + cellData + " to String error ", e);

3
src/main/java/com/alibaba/excel/util/DateUtils.java

@ -12,6 +12,7 @@ import com.alibaba.excel.exception.ExcelDataConvertException;
* @author Jiaju Zhuang * @author Jiaju Zhuang
**/ **/
public class DateUtils { public class DateUtils {
public static final String DATE_FORMAT_10 = "yyyy-MM-dd";
public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss"; public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss";
public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss"; public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss";
public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss"; public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss";
@ -65,6 +66,8 @@ public class DateUtils {
return DATE_FORMAT_17; return DATE_FORMAT_17;
case 14: case 14:
return DATE_FORMAT_14; return DATE_FORMAT_14;
case 10:
return DATE_FORMAT_10;
default: default:
throw new ExcelDataConvertException("can not find date format for:" + dateString); throw new ExcelDataConvertException("can not find date format for:" + dateString);
} }

5
src/main/java/com/alibaba/excel/write/ExcelBuilder.java

@ -71,11 +71,14 @@ public interface ExcelBuilder {
/** /**
* Close io * Close io
*
* @param onException
*/ */
void finish(); void finish(boolean onException);
/** /**
* add password * add password
*
* @param data * @param data
* @param writeSheet * @param writeSheet
* @param writeTable * @param writeTable

24
src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java

@ -31,10 +31,10 @@ public class ExcelBuilderImpl implements ExcelBuilder {
FileUtils.createPoiFilesDirectory(); FileUtils.createPoiFilesDirectory();
context = new WriteContextImpl(writeWorkbook); context = new WriteContextImpl(writeWorkbook);
} catch (RuntimeException e) { } catch (RuntimeException e) {
finish(); finishOnException();
throw e; throw e;
} catch (Throwable e) { } catch (Throwable e) {
finish(); finishOnException();
throw new ExcelGenerateException(e); throw new ExcelGenerateException(e);
} }
} }
@ -57,10 +57,10 @@ public class ExcelBuilderImpl implements ExcelBuilder {
} }
excelWriteAddExecutor.add(data); excelWriteAddExecutor.add(data);
} catch (RuntimeException e) { } catch (RuntimeException e) {
finish(); finishOnException();
throw e; throw e;
} catch (Throwable e) { } catch (Throwable e) {
finish(); finishOnException();
throw new ExcelGenerateException(e); throw new ExcelGenerateException(e);
} }
} }
@ -80,18 +80,22 @@ public class ExcelBuilderImpl implements ExcelBuilder {
} }
excelWriteFillExecutor.fill(data, fillConfig); excelWriteFillExecutor.fill(data, fillConfig);
} catch (RuntimeException e) { } catch (RuntimeException e) {
finish(); finishOnException();
throw e; throw e;
} catch (Throwable e) { } catch (Throwable e) {
finish(); finishOnException();
throw new ExcelGenerateException(e); throw new ExcelGenerateException(e);
} }
} }
private void finishOnException() {
finish(true);
}
@Override @Override
public void finish() { public void finish(boolean onException) {
if (context != null) { if (context != null) {
context.finish(); context.finish(onException);
} }
} }
@ -108,10 +112,10 @@ public class ExcelBuilderImpl implements ExcelBuilder {
} }
excelWriteAddExecutor.add(data); excelWriteAddExecutor.add(data);
} catch (RuntimeException e) { } catch (RuntimeException e) {
finish(); finishOnException();
throw e; throw e;
} catch (Throwable e) { } catch (Throwable e) {
finish(); finishOnException();
throw new ExcelGenerateException(e); throw new ExcelGenerateException(e);
} }
} }

8
src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java

@ -146,6 +146,14 @@ public class ExcelWriterBuilder {
return this; return this;
} }
/**
* Excel is also written in the event of an exception being thrown.The default false.
*/
public ExcelWriterBuilder writeExcelOnException(Boolean writeExcelOnException) {
writeWorkbook.setWriteExcelOnException(writeExcelOnException);
return this;
}
/** /**
* The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a * 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. * field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed.

12
src/main/java/com/alibaba/excel/write/metadata/WriteWorkbook.java

@ -63,6 +63,10 @@ public class WriteWorkbook extends WriteBasicParameter {
* Comment and RichTextString are only supported in memory mode. * Comment and RichTextString are only supported in memory mode.
*/ */
private Boolean inMemory; private Boolean inMemory;
/**
* Excel is also written in the event of an exception being thrown.The default false.
*/
private Boolean writeExcelOnException;
/** /**
* The default is all excel objects.Default is true. * The default is all excel objects.Default is true.
* <p> * <p>
@ -169,4 +173,12 @@ public class WriteWorkbook extends WriteBasicParameter {
public void setInMemory(Boolean inMemory) { public void setInMemory(Boolean inMemory) {
this.inMemory = inMemory; this.inMemory = inMemory;
} }
public Boolean getWriteExcelOnException() {
return writeExcelOnException;
}
public void setWriteExcelOnException(Boolean writeExcelOnException) {
this.writeExcelOnException = writeExcelOnException;
}
} }

22
src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java

@ -103,6 +103,10 @@ public class WriteWorkbookHolder extends AbstractWriteHolder {
* Comment and RichTextString are only supported in memory mode. * Comment and RichTextString are only supported in memory mode.
*/ */
private Boolean inMemory; private Boolean inMemory;
/**
* Excel is also written in the event of an exception being thrown.The default false.
*/
private Boolean writeExcelOnException;
public WriteWorkbookHolder(WriteWorkbook writeWorkbook) { public WriteWorkbookHolder(WriteWorkbook writeWorkbook) {
super(writeWorkbook, null, writeWorkbook.getConvertAllFiled()); super(writeWorkbook, null, writeWorkbook.getConvertAllFiled());
@ -128,7 +132,10 @@ public class WriteWorkbookHolder extends AbstractWriteHolder {
throw new ExcelGenerateException("Copy template failure.", e); throw new ExcelGenerateException("Copy template failure.", e);
} }
if (writeWorkbook.getExcelType() == null) { if (writeWorkbook.getExcelType() == null) {
if (file != null && file.getName().endsWith(ExcelTypeEnum.XLS.getValue())) { boolean isXls = (file != null && file.getName().endsWith(ExcelTypeEnum.XLS.getValue()))
|| (writeWorkbook.getTemplateFile() != null
&& writeWorkbook.getTemplateFile().getName().endsWith(ExcelTypeEnum.XLS.getValue()));
if (isXls) {
this.excelType = ExcelTypeEnum.XLS; this.excelType = ExcelTypeEnum.XLS;
} else { } else {
this.excelType = ExcelTypeEnum.XLSX; this.excelType = ExcelTypeEnum.XLSX;
@ -148,6 +155,11 @@ public class WriteWorkbookHolder extends AbstractWriteHolder {
} else { } else {
this.inMemory = writeWorkbook.getInMemory(); this.inMemory = writeWorkbook.getInMemory();
} }
if (writeWorkbook.getWriteExcelOnException() == null) {
this.writeExcelOnException = Boolean.FALSE;
} else {
this.writeExcelOnException = writeWorkbook.getWriteExcelOnException();
}
} }
private void copyTemplate() throws IOException { private void copyTemplate() throws IOException {
@ -281,6 +293,14 @@ public class WriteWorkbookHolder extends AbstractWriteHolder {
this.inMemory = inMemory; this.inMemory = inMemory;
} }
public Boolean getWriteExcelOnException() {
return writeExcelOnException;
}
public void setWriteExcelOnException(Boolean writeExcelOnException) {
this.writeExcelOnException = writeExcelOnException;
}
@Override @Override
public HolderEnum holderType() { public HolderEnum holderType() {
return HolderEnum.WORKBOOK; return HolderEnum.WORKBOOK;

11
src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java

@ -19,12 +19,15 @@ import com.alibaba.excel.write.metadata.fill.FillConfig;
/** /**
* 写的填充写法 * 写的填充写法
* *
* @since 2.1.1
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Ignore @Ignore
public class FillTest { public class FillTest {
/** /**
* 最简单的填充 * 最简单的填充
*
* @since 2.1.1
*/ */
@Test @Test
public void simpleFill() { public void simpleFill() {
@ -51,6 +54,8 @@ public class FillTest {
/** /**
* 填充列表 * 填充列表
*
* @since 2.1.1
*/ */
@Test @Test
public void listFill() { public void listFill() {
@ -76,6 +81,8 @@ public class FillTest {
/** /**
* 复杂的填充 * 复杂的填充
*
* @since 2.1.1
*/ */
@Test @Test
public void complexFill() { public void complexFill() {
@ -105,6 +112,8 @@ public class FillTest {
* 数据量大的复杂填充 * 数据量大的复杂填充
* <p> * <p>
* 这里的解决方案是 确保模板list为最后一行然后再拼接table.还有03版没救只能刚正面加内存 * 这里的解决方案是 确保模板list为最后一行然后再拼接table.还有03版没救只能刚正面加内存
*
* @since 2.1.1
*/ */
@Test @Test
public void complexFillWithTable() { public void complexFillWithTable() {
@ -145,6 +154,8 @@ public class FillTest {
/** /**
* 横向的填充 * 横向的填充
*
* @since 2.1.1
*/ */
@Test @Test
public void horizontalFill() { public void horizontalFill() {

15
src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDAO.java

@ -0,0 +1,15 @@
package com.alibaba.easyexcel.test.demo.read;
import java.util.List;
/**
* 假设这个是你的DAO存储当然还要这个类让spring管理当然你不用需要存储也不需要这个类
*
* @author Jiaju Zhuang
**/
public class DemoDAO {
public void save(List<DemoData> list) {
// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
}
}

34
src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java

@ -23,19 +23,52 @@ public class DemoDataListener extends AnalysisEventListener<DemoData> {
*/ */
private static final int BATCH_COUNT = 5; private static final int BATCH_COUNT = 5;
List<DemoData> list = new ArrayList<DemoData>(); List<DemoData> list = new ArrayList<DemoData>();
/**
* 假设这个是一个DAO当然有业务逻辑这个也可以是一个service当然如果不用存储这个对象没用
*/
private DemoDAO demoDAO;
public DemoDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
demoDAO = new DemoDAO();
}
/**
* 如果使用了spring,请使用这个构造方法每次创建Listener的时候需要把spring管理的类传进来
*
* @param demoDAO
*/
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override @Override
public void invoke(DemoData data, AnalysisContext context) { public void invoke(DemoData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data); list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) { if (list.size() >= BATCH_COUNT) {
saveData(); saveData();
// 存储完成清理 list
list.clear(); list.clear();
} }
} }
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override @Override
public void doAfterAllAnalysed(AnalysisContext context) { public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData(); saveData();
LOGGER.info("所有数据解析完成!"); LOGGER.info("所有数据解析完成!");
} }
@ -45,6 +78,7 @@ public class DemoDataListener extends AnalysisEventListener<DemoData> {
*/ */
private void saveData() { private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size()); LOGGER.info("{}条数据,开始存储数据库!", list.size());
demoDAO.save(list);
LOGGER.info("存储数据库成功!"); LOGGER.info("存储数据库成功!");
} }
} }

10
src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java

@ -202,17 +202,15 @@ public class ReadTest {
public void synchronousRead() { public void synchronousRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish // 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish
List<Object> list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync(); List<DemoData> list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync();
for (Object obj : list) { for (DemoData data : list) {
DemoData data = (DemoData)obj;
LOGGER.info("读取到数据:{}", JSON.toJSONString(data)); LOGGER.info("读取到数据:{}", JSON.toJSONString(data));
} }
// 这里 也可以不指定class,返回一个list,然后读取第一个sheet 同步读取会自动finish // 这里 也可以不指定class,返回一个list,然后读取第一个sheet 同步读取会自动finish
list = EasyExcel.read(fileName).sheet().doReadSync(); List<Map<Integer, String>> listMap = EasyExcel.read(fileName).sheet().doReadSync();
for (Object obj : list) { for (Map<Integer, String> data : listMap) {
// 返回每条数据的键值对 表示所在的列 和所在列的值 // 返回每条数据的键值对 表示所在的列 和所在列的值
Map<Integer, String> data = (Map<Integer, String>)obj;
LOGGER.info("读取到数据:{}", JSON.toJSONString(data)); LOGGER.info("读取到数据:{}", JSON.toJSONString(data));
} }
} }

20
src/test/java/com/alibaba/easyexcel/test/demo/web/UploadDAO.java

@ -0,0 +1,20 @@
package com.alibaba.easyexcel.test.demo.web;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.alibaba.easyexcel.test.demo.read.DemoData;
/**
* 假设这个是你的DAO存储当然还要这个类让spring管理当然你不用需要存储也不需要这个类
*
* @author Jiaju Zhuang
**/
@Repository
public class UploadDAO {
public void save(List<UploadData> list) {
// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
}
}

38
src/test/java/com/alibaba/easyexcel/test/demo/web/UploadDataListener.java

@ -15,26 +15,61 @@ import com.alibaba.fastjson.JSON;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class UploadDataListener extends AnalysisEventListener<UploadData> { public class UploadDataListener extends AnalysisEventListener<UploadData> {
private static final Logger LOGGER = LoggerFactory.getLogger(UploadDataListener.class); private static final Logger LOGGER =
LoggerFactory.getLogger(com.alibaba.easyexcel.test.demo.read.DemoDataListener.class);
/** /**
* 每隔5条存储数据库实际使用中可以3000条然后清理list 方便内存回收 * 每隔5条存储数据库实际使用中可以3000条然后清理list 方便内存回收
*/ */
private static final int BATCH_COUNT = 5; private static final int BATCH_COUNT = 5;
List<UploadData> list = new ArrayList<UploadData>(); List<UploadData> list = new ArrayList<UploadData>();
/**
* 假设这个是一个DAO当然有业务逻辑这个也可以是一个service当然如果不用存储这个对象没用
*/
private UploadDAO uploadDAO;
public UploadDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
uploadDAO = new UploadDAO();
}
/**
* 如果使用了spring,请使用这个构造方法每次创建Listener的时候需要把spring管理的类传进来
*
* @param uploadDAO
*/
public UploadDataListener(UploadDAO uploadDAO) {
this.uploadDAO = uploadDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override @Override
public void invoke(UploadData data, AnalysisContext context) { public void invoke(UploadData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data); list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) { if (list.size() >= BATCH_COUNT) {
saveData(); saveData();
// 存储完成清理 list
list.clear(); list.clear();
} }
} }
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override @Override
public void doAfterAllAnalysed(AnalysisContext context) { public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData(); saveData();
LOGGER.info("所有数据解析完成!"); LOGGER.info("所有数据解析完成!");
} }
@ -44,6 +79,7 @@ public class UploadDataListener extends AnalysisEventListener<UploadData> {
*/ */
private void saveData() { private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size()); LOGGER.info("{}条数据,开始存储数据库!", list.size());
uploadDAO.save(list);
LOGGER.info("存储数据库成功!"); LOGGER.info("存储数据库成功!");
} }
} }

43
src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java

@ -2,14 +2,15 @@ package com.alibaba.easyexcel.test.demo.web;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
/** /**
* web读写案例 * web读写案例
@ -25,8 +27,12 @@ import com.alibaba.excel.EasyExcel;
**/ **/
@Controller @Controller
public class WebTest { public class WebTest {
@Autowired
private UploadDAO uploadDAO;
/** /**
* 文件下载 * 文件下载失败了会返回一个有部分数据的Excel
* <p> * <p>
* 1. 创建excel对应的实体对象 参照{@link DownloadData} * 1. 创建excel对应的实体对象 参照{@link DownloadData}
* <p> * <p>
@ -45,6 +51,35 @@ public class WebTest {
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data()); EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
} }
/**
* 文件下载并且失败的时候返回json默认失败了会返回一个有部分数据的Excel
*
* @since 2.1.1
*/
@GetMapping("downloadFailedUsingJson")
public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
try {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// 这里需要设置不关闭流
EasyExcel.write(response.getOutputStream(), DownloadData.class).autoCloseStream(Boolean.FALSE).sheet("模板")
.doWrite(data());
} catch (Exception e) {
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, String> map = new HashMap<String, String>();
map.put("status", "failure");
map.put("message", "下载文件失败" + e.getMessage());
response.getWriter().println(JSON.toJSONString(map));
}
}
/** /**
* 文件上传 * 文件上传
* <p> * <p>
@ -57,7 +92,7 @@ public class WebTest {
@PostMapping("upload") @PostMapping("upload")
@ResponseBody @ResponseBody
public String upload(MultipartFile file) throws IOException { 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"; return "success";
} }

7
src/test/java/com/alibaba/easyexcel/test/demo/write/ImageData.java

@ -2,6 +2,7 @@ package com.alibaba.easyexcel.test.demo.write;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ColumnWidth;
@ -27,4 +28,10 @@ public class ImageData {
@ExcelProperty(converter = StringImageConverter.class) @ExcelProperty(converter = StringImageConverter.class)
private String string; private String string;
private byte[] byteArray; private byte[] byteArray;
/**
* 根据url导出
*
* @since 2.1.1
*/
private URL url;
} }

5
src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java

@ -2,6 +2,7 @@ package com.alibaba.easyexcel.test.demo.write;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
@ -215,12 +216,14 @@ public class WriteTest {
ImageData imageData = new ImageData(); ImageData imageData = new ImageData();
list.add(imageData); list.add(imageData);
String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg"; String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg";
// 放入种类型的图片 实际使用只要选一种即可 // 放入种类型的图片 实际使用只要选一种即可
imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath))); imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
imageData.setFile(new File(imagePath)); imageData.setFile(new File(imagePath));
imageData.setString(imagePath); imageData.setString(imagePath);
inputStream = FileUtils.openInputStream(new File(imagePath)); inputStream = FileUtils.openInputStream(new File(imagePath));
imageData.setInputStream(inputStream); imageData.setInputStream(inputStream);
imageData.setUrl(new URL(
"https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg"));
EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list); EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);
} finally { } finally {
if (inputStream != null) { if (inputStream != null) {

42
src/test/java/com/alibaba/easyexcel/test/temp/read/HDListener.java

@ -0,0 +1,42 @@
package com.alibaba.easyexcel.test.temp.read;
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 HDListener extends AnalysisEventListener<HeadReadData> {
private static final Logger LOGGER = LoggerFactory.getLogger(HDListener.class);
/**
* 每隔5条存储数据库实际使用中可以3000条然后清理list 方便内存回收
*/
private static final int BATCH_COUNT = 5;
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
LOGGER.info("HEAD:{}", JSON.toJSONString(headMap));
}
@Override
public void invoke(HeadReadData data, AnalysisContext context) {
LOGGER.info("index:{}", context.readRowHolder().getRowIndex());
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
LOGGER.info("所有数据解析完成!");
}
}

18
src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java

@ -0,0 +1,18 @@
package com.alibaba.easyexcel.test.temp.read;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 临时测试
*
* @author Jiaju Zhuang
**/
@Data
public class HeadReadData {
@ExcelProperty("头1")
private String h1;
@ExcelProperty({"头", "头2"})
private String h2;
}

25
src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java

@ -0,0 +1,25 @@
package com.alibaba.easyexcel.test.temp.read;
import java.io.File;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.EasyExcel;
/**
* 临时测试
*
* @author Jiaju Zhuang
**/
public class HeadReadTest {
private static final Logger LOGGER = LoggerFactory.getLogger(HeadReadTest.class);
@Test
public void test() throws Exception {
File file = new File("D:\\test\\headt1.xlsx");
EasyExcel.read(file, HeadReadData.class, new HDListener()).sheet().doRead();
}
}

9
update.md

@ -1,5 +1,12 @@
# 2.1.0-bea5 # 2.1.1
* 发布正式版
* 修改map返回为LinkedHashMap * 修改map返回为LinkedHashMap
* 修改同步读取返回对象支持泛型
* 修复03版不能直接读取第二个sheet的bug [Issue #772](https://github.com/alibaba/easyexcel/issues/772)
* 新增支持图片导出用URL [Issue #774](https://github.com/alibaba/easyexcel/issues/774)
* 加入多次关闭判断,防止多次关闭异常
* 加入根据模板自动识别导出的excel类型
* 修改默认失败后,不再往文件流写入数据。通过参数`writeExcelOnException` 参数设置异常了也要写入前面的数据。
# 2.1.0-beta4 # 2.1.0-beta4
* 修改最长匹配策略会空指针的bug [Issue #747](https://github.com/alibaba/easyexcel/issues/747) * 修改最长匹配策略会空指针的bug [Issue #747](https://github.com/alibaba/easyexcel/issues/747)

Loading…
Cancel
Save