Browse Source

添加对Excel批注的读取

pull/737/head
kaiux 5 years ago
parent
commit
9b782f258d
  1. 38
      src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
  2. 8
      src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java
  3. 26
      src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java
  4. 17
      src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
  5. 5
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java
  6. 5
      src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
  7. 5
      src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java
  8. 32
      src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java
  9. 85
      src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java
  10. 17
      src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java
  11. BIN
      src/test/resources/demo/demo.xlsx

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

@ -3,10 +3,12 @@ package com.alibaba.excel.analysis.v03;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import com.alibaba.excel.util.StringUtils;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
@ -19,6 +21,11 @@ import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -74,11 +81,18 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
private HSSFWorkbook stubWorkbook; private HSSFWorkbook stubWorkbook;
private List<XlsRecordHandler> recordHandlers = new ArrayList<XlsRecordHandler>(); private List<XlsRecordHandler> recordHandlers = new ArrayList<XlsRecordHandler>();
private AnalysisContext analysisContext; private AnalysisContext analysisContext;
private Workbook poiWorkbook;
private Map<Integer, String> rowComments;
public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) { public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) {
this.analysisContext = context; this.analysisContext = context;
this.records = new TreeMap<Integer, CellData>(); this.records = new TreeMap<Integer, CellData>();
this.poifsFileSystem = poifsFileSystem; this.poifsFileSystem = poifsFileSystem;
try {
this.poiWorkbook = WorkbookFactory.create(poifsFileSystem);
} catch (IOException e) {
e.printStackTrace();
}
analysisContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem); analysisContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem);
} }
@ -139,6 +153,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
thisRow = handler.getRow(); thisRow = handler.getRow();
thisColumn = handler.getColumn(); thisColumn = handler.getColumn();
cellData = handler.getCellData(); cellData = handler.getCellData();
handleComments(thisRow, thisColumn);
if (cellData != null) { if (cellData != null) {
cellData.checkEmpty(); cellData.checkEmpty();
if (CellDataTypeEnum.EMPTY != cellData.getType()) { if (CellDataTypeEnum.EMPTY != cellData.getType()) {
@ -170,6 +185,26 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
processLastCellOfRow(record); processLastCellOfRow(record);
} }
public void handleComments(int row, int col) {
if (null == this.poiWorkbook || null == analysisContext.readSheetHolder() || row < 0 || col < 0) {
return;
}
Sheet currentSheet = poiWorkbook.getSheetAt(analysisContext.readSheetHolder().getSheetNo());
Map<CellAddress, ? extends Comment> cellComments = currentSheet.getCellComments();
if (CollectionUtils.isEmpty(cellComments)) {
return;
}
Comment comment = cellComments.get(new CellAddress(row, col));
if (null == comment) {
return;
}
String commentsStr = comment.getString().toString();
if (!StringUtils.isEmpty(commentsStr)) {
rowComments = rowComments == null ? new HashMap<Integer, String>(8) : rowComments;
rowComments.put(col, commentsStr);
}
}
private boolean ignoreRecord(Record record) { private boolean ignoreRecord(Record record) {
return analysisContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid return analysisContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid
&& record.getSid() != BOFRecord.sid; && record.getSid() != BOFRecord.sid;
@ -188,6 +223,9 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
} }
analysisContext.readRowHolder( analysisContext.readRowHolder(
new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration())); new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration()));
if (!CollectionUtils.isEmpty(rowComments)) {
analysisContext.readRowHolder().setRowComments(rowComments);
}
analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext); analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext);
records.clear(); records.clear();
lastColumnNumber = -1; lastColumnNumber = -1;

8
src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java

@ -34,4 +34,12 @@ public interface XlsxCellHandler {
* Tag name * Tag name
*/ */
void endHandle(String name); void endHandle(String name);
/**
* Set the comment of the cell
*
* @param comment
* cell comment
*/
void handleComments(String comment);
} }

26
src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java

@ -2,7 +2,12 @@ package com.alibaba.excel.analysis.v07;
import java.util.List; import java.util.List;
import com.alibaba.excel.constant.ExcelXmlConstants;
import com.alibaba.excel.util.StringUtils;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
@ -17,6 +22,12 @@ public class XlsxRowHandler extends DefaultHandler {
private List<XlsxCellHandler> cellHandlers; private List<XlsxCellHandler> cellHandlers;
private XlsxRowResultHolder rowResultHolder; private XlsxRowResultHolder rowResultHolder;
private CommentsTable commentsTable;
public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable, CommentsTable commentsTable) {
this(analysisContext, stylesTable);
this.commentsTable = commentsTable;
}
public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable) { public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable) {
this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, stylesTable); this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, stylesTable);
@ -33,6 +44,7 @@ public class XlsxRowHandler extends DefaultHandler {
for (XlsxCellHandler cellHandler : cellHandlers) { for (XlsxCellHandler cellHandler : cellHandlers) {
if (cellHandler.support(name)) { if (cellHandler.support(name)) {
cellHandler.startHandle(name, attributes); cellHandler.startHandle(name, attributes);
handleComment(cellHandler, attributes.getValue(ExcelXmlConstants.POSITION));
} }
} }
} }
@ -52,4 +64,18 @@ public class XlsxRowHandler extends DefaultHandler {
rowResultHolder.appendCurrentCellValue(ch, start, length); rowResultHolder.appendCurrentCellValue(ch, start, length);
} }
} }
private void handleComment(XlsxCellHandler cellHandler, String address) {
if (StringUtils.isEmpty(address) || null == commentsTable) {
return;
}
XSSFComment xssfComment = commentsTable.getCellComments().get(new CellAddress(address));
if (null == xssfComment) {
return;
}
String comments = xssfComment.getString().toString();
if (!StringUtils.isEmpty(comments)) {
cellHandler.handleComments(comments);
}
}
} }

17
src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java

@ -17,6 +17,7 @@ import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFRelation; import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
@ -46,6 +47,14 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
private AnalysisContext analysisContext; private AnalysisContext analysisContext;
private List<ReadSheet> sheetList; private List<ReadSheet> sheetList;
private Map<Integer, InputStream> sheetMap; private Map<Integer, InputStream> sheetMap;
/**
* excel comments
* key: sheetNo
* value: CommentsTanle
*/
private Map<Integer, CommentsTable> commentsTableMap;
/** /**
* Current style information * Current style information
*/ */
@ -77,6 +86,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
stylesTable = xssfReader.getStylesTable(); stylesTable = xssfReader.getStylesTable();
sheetList = new ArrayList<ReadSheet>(); sheetList = new ArrayList<ReadSheet>();
sheetMap = new HashMap<Integer, InputStream>(); sheetMap = new HashMap<Integer, InputStream>();
commentsTableMap = new HashMap<Integer, CommentsTable>();
XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData();
int index = 0; int index = 0;
if (!ite.hasNext()) { if (!ite.hasNext()) {
@ -86,6 +96,10 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
InputStream inputStream = ite.next(); InputStream inputStream = ite.next();
sheetList.add(new ReadSheet(index, ite.getSheetName())); sheetList.add(new ReadSheet(index, ite.getSheetName()));
sheetMap.put(index, inputStream); sheetMap.put(index, inputStream);
CommentsTable commentsTable = ite.getSheetComments();
if (null != commentsTable) {
commentsTableMap.put(index, commentsTable);
}
index++; index++;
} }
} }
@ -181,7 +195,8 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
analysisContext.readWorkbookHolder().getGlobalConfiguration()); analysisContext.readWorkbookHolder().getGlobalConfiguration());
if (readSheet != null) { if (readSheet != null) {
analysisContext.currentSheet(readSheet); analysisContext.currentSheet(readSheet);
parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(analysisContext, stylesTable)); Integer sheetNo = readSheet.getSheetNo();
parseXmlSource(sheetMap.get(sheetNo), new XlsxRowHandler(analysisContext, stylesTable, commentsTableMap.get(sheetNo)));
// The last sheet is read // The last sheet is read
analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext); analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
} }

5
src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java

@ -39,4 +39,9 @@ public class CountRowCellHandler implements XlsxCellHandler {
} }
@Override
public void handleComments(String comment) {
}
} }

5
src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java

@ -160,6 +160,11 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder
} }
} }
@Override
public void handleComments(String comment) {
analysisContext.readRowHolder().addComments(curCol, comment);
}
@Override @Override
public void appendCurrentCellValue(char[] ch, int start, int length) { public void appendCurrentCellValue(char[] ch, int start, int length) {
String currentTag = currentTagDeque.peek(); String currentTag = currentTagDeque.peek();

5
src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java

@ -45,4 +45,9 @@ public class ProcessResultCellHandler implements XlsxCellHandler {
rowResultHandler.clearResult(); rowResultHandler.clearResult();
} }
@Override
public void handleComments(String comment) {
}
} }

32
src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java

@ -3,6 +3,10 @@ package com.alibaba.excel.read.metadata.holder;
import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.enums.HolderEnum;
import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.Holder; import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.util.CollectionUtils;
import java.util.HashMap;
import java.util.Map;
/** /**
* sheet holder * sheet holder
@ -24,6 +28,34 @@ public class ReadRowHolder implements Holder {
*/ */
private GlobalConfiguration globalConfiguration; private GlobalConfiguration globalConfiguration;
/**
* Return row comments
* key: col index
* value: comments
*/
private Map<Integer, String> rowComments;
public Map<Integer, String> getRowComments() {
return rowComments;
}
public void setRowComments(Map<Integer, String> rowComments) {
this.rowComments = rowComments;
}
public void addComments(Integer index, String comments) {
this.rowComments = this.rowComments == null ? new HashMap<Integer, String>(8) : this.rowComments;
this.rowComments.put(index, comments);
}
public String getComments(Integer index) {
if (CollectionUtils.isEmpty(rowComments)) {
return null;
} else {
return rowComments.get(index);
}
}
public ReadRowHolder(Integer rowIndex, GlobalConfiguration globalConfiguration) { public ReadRowHolder(Integer rowIndex, GlobalConfiguration globalConfiguration) {
this.rowIndex = rowIndex; this.rowIndex = rowIndex;
this.globalConfiguration = globalConfiguration; this.globalConfiguration = globalConfiguration;

85
src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java

@ -0,0 +1,85 @@
package com.alibaba.easyexcel.test.demo.read;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 读取单元格的批注
*
* @author: kaiux
* @date: 2019-10-23 14:10
**/
public class DemoCellCommentsListener extends AnalysisEventListener<DemoData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoCellCommentsListener.class);
/**
* 每隔5条存储数据库实际使用中可以3000条然后清理list 方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<DemoData> list = new ArrayList<DemoData>();
/**
* 在转换异常 获取其他异常下会调用本接口抛出异常则停止读取如果这里不抛出异常则 继续读取下一行
*
* @param exception
* @param context
* @throws Exception
*/
@Override
public void onException(Exception exception, AnalysisContext context) {
LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
excelDataConvertException.getColumnIndex());
}
}
/**
* 这里会一行行的返回头
*
* @param headMap
* @param context
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
Map<Integer, String> rowComments = context.readRowHolder().getRowComments();
LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
if (!CollectionUtils.isEmpty(rowComments)) {
for (Integer i : rowComments.keySet()) {
LOGGER.info("解析到头数据低{}列包含批注:{}", i, rowComments.get(i));
}
}
}
@Override
public void invoke(DemoData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
if (list.size() >= BATCH_COUNT) {
saveData();
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
LOGGER.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
LOGGER.info("存储数据库成功!");
}
}

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

@ -161,6 +161,23 @@ public class ReadTest {
EasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead(); EasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead();
} }
/**
* 读取单元格批注
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 由于默认异步读取excel所以需要创建excel一行一行的回调监听器参照{@link DemoHeadDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void commentsRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, DemoData.class, new DemoCellCommentsListener()).sheet().doRead();
}
/** /**
* 读取公式和单元格类型 * 读取公式和单元格类型
* *

BIN
src/test/resources/demo/demo.xlsx

Binary file not shown.
Loading…
Cancel
Save