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)
```java
/**
* 文件下载
* 文件下载(失败了会返回一个有部分数据的Excel)
* <p>1. 创建excel对应的实体对象 参照{@link DownloadData}
* <p>2. 设置返回的 参数
* <p>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";
}
```

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.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<ReadSheet> 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.");
}
}
}

20
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);
}
}
/**

8
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;
}

2
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<Integer, CellData>();
records = new LinkedHashMap<Integer, CellData>();
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,
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);
}

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.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<Integer, CellData>();
curRowContent = new LinkedHashMap<Integer, CellData>();
}
@Override

5
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

23
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;
// 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 {
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) {

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.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;
}

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
*/
public List<Object> doReadSync() {
public <T> List<T> doReadSync() {
if (excelReader == null) {
throw new ExcelAnalysisException("Must use 'EasyExcelFactory.read().sheet()' to call this method");
}
@ -174,7 +174,7 @@ public class ExcelReaderSheetBuilder {
registerReadListener(syncReadListener);
excelReader.read(build());
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();
String headName = headNameList.get(headNameList.size() - 1);
for (Map.Entry<Integer, String> stringEntry : dataMap.entrySet()) {
if (stringEntry == null) {
continue;
}
String headString = stringEntry.getValue();
Integer stringKey = stringEntry.getKey();
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) {
Map<Integer, String> stringMap = new HashMap<Integer, String>(cellDataMap.size() * 4 / 3 + 1);
int index = 0;
for (Map.Entry<Integer, CellData> entry : cellDataMap.entrySet()) {
Integer key = entry.getKey();
CellData cellData = entry.getValue();
while (index < key) {
stringMap.put(index, null);
index++;
}
index++;
if (cellData.getType() == CellDataTypeEnum.EMPTY) {
stringMap.put(entry.getKey(), null);
stringMap.put(key, null);
continue;
}
Converter converter =
@ -46,7 +53,7 @@ public class ConverterUtils {
"Converter not found, convert " + cellData.getType() + " to String");
}
try {
stringMap.put(entry.getKey(),
stringMap.put(key,
(String)(converter.convertToJavaData(cellData, null, readHolder.globalConfiguration())));
} catch (Exception 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
**/
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_17 = "yyyyMMdd 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;
case 14:
return DATE_FORMAT_14;
case 10:
return DATE_FORMAT_10;
default:
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
*
* @param onException
*/
void finish();
void finish(boolean onException);
/**
* add password
*
* @param data
* @param writeSheet
* @param writeTable

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

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

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

@ -146,6 +146,14 @@ public class ExcelWriterBuilder {
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
* 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.
*/
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.
* <p>
@ -169,4 +173,12 @@ public class WriteWorkbook extends WriteBasicParameter {
public void setInMemory(Boolean 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.
*/
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) {
super(writeWorkbook, null, writeWorkbook.getConvertAllFiled());
@ -128,7 +132,10 @@ public class WriteWorkbookHolder extends AbstractWriteHolder {
throw new ExcelGenerateException("Copy template failure.", e);
}
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;
} else {
this.excelType = ExcelTypeEnum.XLSX;
@ -148,6 +155,11 @@ public class WriteWorkbookHolder extends AbstractWriteHolder {
} else {
this.inMemory = writeWorkbook.getInMemory();
}
if (writeWorkbook.getWriteExcelOnException() == null) {
this.writeExcelOnException = Boolean.FALSE;
} else {
this.writeExcelOnException = writeWorkbook.getWriteExcelOnException();
}
}
private void copyTemplate() throws IOException {
@ -281,6 +293,14 @@ public class WriteWorkbookHolder extends AbstractWriteHolder {
this.inMemory = inMemory;
}
public Boolean getWriteExcelOnException() {
return writeExcelOnException;
}
public void setWriteExcelOnException(Boolean writeExcelOnException) {
this.writeExcelOnException = writeExcelOnException;
}
@Override
public HolderEnum holderType() {
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
*/
@Ignore
public class FillTest {
/**
* 最简单的填充
*
* @since 2.1.1
*/
@Test
public void simpleFill() {
@ -51,6 +54,8 @@ public class FillTest {
/**
* 填充列表
*
* @since 2.1.1
*/
@Test
public void listFill() {
@ -76,6 +81,8 @@ public class FillTest {
/**
* 复杂的填充
*
* @since 2.1.1
*/
@Test
public void complexFill() {
@ -105,6 +112,8 @@ public class FillTest {
* 数据量大的复杂填充
* <p>
* 这里的解决方案是 确保模板list为最后一行然后再拼接table.还有03版没救只能刚正面加内存
*
* @since 2.1.1
*/
@Test
public void complexFillWithTable() {
@ -145,6 +154,8 @@ public class FillTest {
/**
* 横向的填充
*
* @since 2.1.1
*/
@Test
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;
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
public void invoke(DemoData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
LOGGER.info("所有数据解析完成!");
}
@ -45,6 +78,7 @@ public class DemoDataListener extends AnalysisEventListener<DemoData> {
*/
private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
demoDAO.save(list);
LOGGER.info("存储数据库成功!");
}
}

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

@ -202,17 +202,15 @@ public class ReadTest {
public void synchronousRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish
List<Object> list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync();
for (Object obj : list) {
DemoData data = (DemoData)obj;
List<DemoData> list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync();
for (DemoData data : list) {
LOGGER.info("读取到数据:{}", JSON.toJSONString(data));
}
// 这里 也可以不指定class,返回一个list,然后读取第一个sheet 同步读取会自动finish
list = EasyExcel.read(fileName).sheet().doReadSync();
for (Object obj : list) {
List<Map<Integer, String>> listMap = EasyExcel.read(fileName).sheet().doReadSync();
for (Map<Integer, String> data : listMap) {
// 返回每条数据的键值对 表示所在的列 和所在列的值
Map<Integer, String> data = (Map<Integer, String>)obj;
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
*/
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
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 方便内存回收
*/
private static final int BATCH_COUNT = 5;
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
public void invoke(UploadData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
LOGGER.info("所有数据解析完成!");
}
@ -44,6 +79,7 @@ public class UploadDataListener extends AnalysisEventListener<UploadData> {
*/
private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
uploadDAO.save(list);
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.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
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 com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
/**
* web读写案例
@ -25,8 +27,12 @@ import com.alibaba.excel.EasyExcel;
**/
@Controller
public class WebTest {
@Autowired
private UploadDAO uploadDAO;
/**
* 文件下载
* 文件下载失败了会返回一个有部分数据的Excel
* <p>
* 1. 创建excel对应的实体对象 参照{@link DownloadData}
* <p>
@ -45,6 +51,35 @@ public class WebTest {
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>
@ -57,7 +92,7 @@ public class WebTest {
@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";
}

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.InputStream;
import java.net.URL;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
@ -27,4 +28,10 @@ public class ImageData {
@ExcelProperty(converter = StringImageConverter.class)
private String string;
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.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
@ -215,12 +216,14 @@ public class WriteTest {
ImageData imageData = new ImageData();
list.add(imageData);
String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg";
// 放入种类型的图片 实际使用只要选一种即可
// 放入种类型的图片 实际使用只要选一种即可
imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
imageData.setFile(new File(imagePath));
imageData.setString(imagePath);
inputStream = FileUtils.openInputStream(new File(imagePath));
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);
} finally {
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
* 修改同步读取返回对象支持泛型
* 修复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
* 修改最长匹配策略会空指针的bug [Issue #747](https://github.com/alibaba/easyexcel/issues/747)

Loading…
Cancel
Save