Skip to content

Commit

Permalink
修复xls无法获取sheetList的bug #621
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuangjiaju committed Sep 24, 2019
1 parent bcb86ed commit 791f0ca
Show file tree
Hide file tree
Showing 20 changed files with 354 additions and 43 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.0.1</version>
<version>2.0.2</version>
<packaging>jar</packaging>
<name>easyexcel</name>

Expand Down
79 changes: 65 additions & 14 deletions quickstart.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# easyexcel核心功能
## 目录
### 前言
#### 关于@Data
读写的对象都用到了[Lombok](https://www.projectlombok.org/),他会自动生成`get`,`set` ,如果不需要自己创建对象并生成`get`,`set`
#### 以下功能目前不支持
* 单个文件的并发写入、读取
* 读取图片
*
* csv读取(这个后续可能会考虑)
#### 常见问题
* 关于@Data,读写的对象都用到了[Lombok](https://www.projectlombok.org/),他会自动生成`get`,`set` ,如果不需要的话,自己创建对象并生成`get`,`set`
* 如果在读的时候`Listener`里面需要使用spring的`@Autowired`,给`Listener`创建成员变量,然后在构造方法里面传进去。而别必须不让spring管理`Listener`,每次读取都要`new`一个。
* 如果用`String`去接收数字,出现小数点等情况,这个是BUG,但是很难修复,后续版本会修复这个问题。目前请使用`@NumberFormat`直接,里面的参数就是调用了java自带的`NumberFormat.format`方法,不知道怎么入参的可以自己网上查询。
#### 详细参数介绍
有些参数不知道怎么用,或者有些功能不知道用什么参数,参照:[详细参数介绍](/docs/API.md)
#### 开源项目不容易,如果觉得本项目对您的工作还是有帮助的话,请在右上角帮忙点个★Star。
Expand All @@ -28,7 +30,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
* [最简单的写](#simpleWrite)
* [指定写入的列](#indexWrite)
* [复杂头写入](#complexHeadWrite)
* [重复多次写入](#repeatedWrite)
* [重复多次写入(包括不同sheet)](#repeatedWrite)
* [日期、数字或者自定义格式转换](#converterWrite)
* [图片导出](#imageWrite)
* [根据模板写入](#templateWrite)
Expand Down Expand Up @@ -165,12 +167,16 @@ public class IndexOrNameData {
```java
/**
* 读多个sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>3. 直接读即可
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void repeatedRead() {
// 方法1 如果 sheet1 sheet2 都是同一数据 监听器和头 都写到最外层
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
ReadSheet readSheet1 = EasyExcel.readSheet(0).build();
Expand All @@ -179,6 +185,17 @@ public class IndexOrNameData {
excelReader.read(readSheet2);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();

// 方法2 如果 sheet1 sheet2 数据不一致的话
fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
excelReader = EasyExcel.read(fileName).build();
// 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
readSheet1 = EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
readSheet2 = EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
excelReader.read(readSheet1);
excelReader.read(readSheet2);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
}
```

Expand Down Expand Up @@ -572,7 +589,7 @@ public class ComplexHeadData {
参照:[对象](#simpleWriteObject)
##### 代码
```java
/**
/**
* 重复多次写入
* <p>
* 1. 创建excel对应的实体对象 参照{@link ComplexHeadData}
Expand All @@ -583,6 +600,7 @@ public class ComplexHeadData {
*/
@Test
public void repeatedWrite() {
// 方法1 如果写到同一个sheet
String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去读
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
Expand All @@ -596,6 +614,36 @@ public class ComplexHeadData {
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();

// 方法2 如果写到不同的sheet 同一个对象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 指定文件
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo
writeSheet = EasyExcel.writerSheet(i, "模板").build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();

// 方法3 如果写到不同的sheet 不同的对象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 指定文件
excelWriter = EasyExcel.write(fileName).build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变
writeSheet = EasyExcel.writerSheet(i, "模板").head(DemoData.class).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
```

Expand Down Expand Up @@ -867,18 +915,19 @@ public class WidthAndHeightData {
* <p>
* 思路是这样子的,先创建List<String>头格式的sheet仅仅写入头,然后通过table 不写入头的方式 去写入数据
*
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 然后写入table即可
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 然后写入table即可
*/
@Test
public void dynamicHeadWrite() {
String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";
// write的时候 不传入 class 在table的时候传入
EasyExcel.write(fileName)
// 这里放入动态头
.head(head()).sheet("模板")
// table的时候 传入class 并且设置needHead =false
.table().head(DemoData.class).needHead(Boolean.FALSE).doWrite(data());
// 当然这里数据也可以用 List<List<String>> 去传入
.doWrite(data());
}

private List<List<String>> head() {
Expand Down Expand Up @@ -1056,10 +1105,12 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应下载的文件名不对。这个时候 请别使用swagger 他会影像
// 这里注意 有同学反应下载的文件名不对。这个时候 请别使用swagger 他会有影响
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());
}
```
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/alibaba/excel/ExcelWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.ArrayList;
import java.util.List;

import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.parameter.GenerateParam;
Expand Down Expand Up @@ -297,4 +298,12 @@ public void finish() {
excelBuilder.finish();
}

/**
* The context of the entire writing process
*
* @return
*/
public WriteContext writeContext() {
return excelBuilder.writeContext();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.alibaba.excel.analysis.v03;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.read.metadata.ReadSheet;

/**
* In some cases, you need to know the number of sheets in advance and only read the file once in advance.
*
* @author Jiaju Zhuang
*/
public class XlsListSheetListener implements HSSFListener {
private POIFSFileSystem poifsFileSystem;
private List<ReadSheet> sheetList;
private XlsRecordHandler bofRecordHandler;

public XlsListSheetListener(AnalysisContext analysisContext, POIFSFileSystem poifsFileSystem) {
this.poifsFileSystem = poifsFileSystem;
sheetList = new ArrayList<ReadSheet>();
bofRecordHandler = new BofRecordHandler(analysisContext, sheetList, false);
bofRecordHandler.init();
}

@Override
public void processRecord(Record record) {
bofRecordHandler.processRecord(record);
}

public List<ReadSheet> getSheetList() {
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
HSSFListener formatListener = new FormatTrackingHSSFListener(listener);
HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest();
EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener =
new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
request.addListenerForAllRecords(workbookBuildingListener);

try {
factory.processWorkbookEvents(request, poifsFileSystem);
} catch (IOException e) {
throw new ExcelAnalysisException(e);
}
return sheetList;
}
}
26 changes: 19 additions & 7 deletions src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand All @@ -19,6 +20,8 @@
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.excel.analysis.ExcelExecutor;
import com.alibaba.excel.analysis.v03.handlers.BlankOrErrorRecordHandler;
Expand Down Expand Up @@ -55,6 +58,8 @@
* @author jipengfei
*/
public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class);

private boolean outputFormulaValues = true;
private POIFSFileSystem poifsFileSystem;
private int lastRowNumber;
Expand All @@ -66,12 +71,12 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor {
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
private FormatTrackingHSSFListener formatListener;
private Map<Integer, CellData> records;
private List<ReadSheet> sheets = new ArrayList<ReadSheet>();
private List<ReadSheet> sheets;
private HSSFWorkbook stubWorkbook;
private List<XlsRecordHandler> recordHandlers = new ArrayList<XlsRecordHandler>();
private AnalysisContext analysisContext;

public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) throws IOException {
public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) {
this.analysisContext = context;
this.records = new TreeMap<Integer, CellData>();
this.poifsFileSystem = poifsFileSystem;
Expand All @@ -80,6 +85,11 @@ public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem)

@Override
public List<ReadSheet> sheetList() {
if (sheets == null) {
LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice.");
XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(analysisContext, poifsFileSystem);
sheets = xlsListSheetListener.getSheetList();
}
return sheets;
}

Expand All @@ -92,17 +102,14 @@ public void execute() {
if (workbookBuildingListener != null && stubWorkbook == null) {
stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
}

init();

HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest();
if (outputFormulaValues) {
request.addListenerForAllRecords(formatListener);
} else {
request.addListenerForAllRecords(workbookBuildingListener);
}

try {
factory.processWorkbookEvents(request, poifsFileSystem);
} catch (IOException e) {
Expand All @@ -118,7 +125,6 @@ private void init() {
lastRowNumber = 0;
lastColumnNumber = 0;
records = new TreeMap<Integer, CellData>();
sheets = new ArrayList<ReadSheet>();
buildXlsRecordHandlers();
}

Expand Down Expand Up @@ -199,7 +205,13 @@ private void endRow() {
private void buildXlsRecordHandlers() {
if (CollectionUtils.isEmpty(recordHandlers)) {
recordHandlers.add(new BlankOrErrorRecordHandler());
recordHandlers.add(new BofRecordHandler(workbookBuildingListener, analysisContext, sheets));
// The table has been counted and there are no duplicate statistics
if (sheets == null) {
sheets = new ArrayList<ReadSheet>();
recordHandlers.add(new BofRecordHandler(analysisContext, sheets, false));
} else {
recordHandlers.add(new BofRecordHandler(analysisContext, sheets, true));
}
recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener));
recordHandlers.add(new LabelRecordHandler());
recordHandlers.add(new NoteRecordHandler());
Expand Down
Loading

0 comments on commit 791f0ca

Please sign in to comment.