浏览代码

add default method

Looly 5 年之前
父节点
当前提交
6b6366e1ef

+ 3 - 0
CHANGELOG.md

@@ -22,10 +22,13 @@
 * 【core   】     ImgUtil增加去除背景色的方法(pr#124@Gitee)
 * 【system 】     OshiUtil增加获取CPU使用率的方法(pr#124@Gitee)
 * 【crypto 】     AsymmetricAlgorithm去除EC(issue#887@Github)
+* 【cache  】     超时缓存使用的线程池大小默认为1(issue#890@Github)
+* 【poi    】     ExcelSaxReader支持handleCell方法
 
 ### Bug修复
 * 【core   】     修复SimpleCache死锁问题(issue#I1HOKB@Gitee)
 * 【core   】     修复SemaphoreRunnable释放问题(issue#I1HLQQ@Gitee)
+* 【poi    】     修复Sax方式读取Excel行号错误问题(issue#882@Gitee)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 1 - 1
hutool-cache/src/main/java/cn/hutool/cache/GlobalPruneTimer.java

@@ -56,7 +56,7 @@ public enum GlobalPruneTimer {
 		if (null != pruneTimer) {
 			shutdownNow();
 		}
-		this.pruneTimer = new ScheduledThreadPoolExecutor(16, r -> ThreadUtil.newThread(r, StrUtil.format("Pure-Timer-{}", cacheTaskNumber.getAndIncrement())));
+		this.pruneTimer = new ScheduledThreadPoolExecutor(1, r -> ThreadUtil.newThread(r, StrUtil.format("Pure-Timer-{}", cacheTaskNumber.getAndIncrement())));
 	}
 
 	/**

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/img/Img.java

@@ -554,7 +554,7 @@ public class Img implements Serializable {
 	 * @return 处理过的图片
 	 */
 	public Image getImg() {
-		return this.targetImage;
+		return null == this.targetImage ? this.srcImage : this.targetImage;
 	}
 
 	/**

+ 7 - 0
hutool-core/src/test/java/cn/hutool/core/img/ImgTest.java

@@ -20,6 +20,13 @@ public class ImgTest {
 	public void compressTest() {
 		Img.from(FileUtil.file("f:/test/4347273249269e3fb272341acc42d4e.jpg")).setQuality(0.8).write(FileUtil.file("f:/test/test_dest.jpg"));
 	}
+
+	@Test
+	@Ignore
+	public void writeTest() {
+		final Img from = Img.from(FileUtil.file("d:/test/81898311-001d6100-95eb-11ea-83c2-a14d7b1010bd.png"));
+		ImgUtil.write(from.getImg(), FileUtil.file("d:/test/dest.jpg"));
+	}
 	
 	@Test
 	@Ignore

+ 2 - 1
hutool-core/src/test/java/cn/hutool/core/img/ImgUtilTest.java

@@ -102,7 +102,8 @@ public class ImgUtilTest {
 	@Test
 	@Ignore
 	public void compressTest() {
-		ImgUtil.compress(FileUtil.file("e:/pic/1111.png"), FileUtil.file("e:/pic/1111_target.jpg"), 0.8f);
+		ImgUtil.compress(FileUtil.file("d:/test/dest.png"),
+				FileUtil.file("d:/test/1111_target.jpg"), 0.1f);
 	}
 	
 	@Test

+ 45 - 0
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/AttributeName.java

@@ -0,0 +1,45 @@
+package cn.hutool.poi.excel.sax;
+
+import org.xml.sax.Attributes;
+
+/**
+ * Excel的XML中属性名枚举
+ *
+ * @author looly
+ * @since 5.3.6
+ */
+public enum AttributeName {
+
+	/**
+	 * 行列号属性,行标签下此为行号属性名,cell标签下下为列号属性名
+	 */
+	r,
+	/**
+	 * ST(StylesTable) 的索引,样式index,用于获取行或单元格样式
+	 */
+	s,
+	/**
+	 * Type类型,单元格类型属性,见{@link CellDataType}
+	 */
+	t;
+
+	/**
+	 * 是否匹配给定属性
+	 *
+	 * @param attributeName 属性
+	 * @return 是否匹配
+	 */
+	public boolean match(String attributeName) {
+		return this.name().equals(attributeName);
+	}
+
+	/**
+	 * 从属性里列表中获取对应属性值
+	 *
+	 * @param attributes 属性列表
+	 * @return 属性值
+	 */
+	public String getValue(Attributes attributes){
+		return attributes.getValue(name());
+	}
+}

+ 1 - 1
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/CellDataType.java

@@ -15,7 +15,7 @@ public enum CellDataType {
 	FORMULA("str"),
 	/** 富文本类型 */
 	INLINESTR("inlineStr"),
-	/** 字符串类型 */
+	/** 共享字符串索引类型 */
 	SSTINDEX("s"),
 	/** 数字类型 */
 	NUMBER(""),

+ 28 - 0
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/ElementName.java

@@ -0,0 +1,28 @@
+package cn.hutool.poi.excel.sax;
+
+/**
+ * 标签名枚举
+ *
+ * @author looly
+ * @since 5.3.6
+ */
+public enum ElementName {
+	/**
+	 * 行标签名,表示一行
+	 */
+	row,
+	/**
+	 * 单元格标签名,表示一个单元格
+	 */
+	c;
+
+	/**
+	 * 给定标签名是否匹配当前标签
+	 *
+	 * @param elementName 标签名
+	 * @return 是否匹配
+	 */
+	public boolean match(String elementName){
+		return this.name().equals(elementName);
+	}
+}

+ 37 - 13
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java

@@ -18,6 +18,7 @@ import org.apache.poi.hssf.record.BOFRecord;
 import org.apache.poi.hssf.record.BlankRecord;
 import org.apache.poi.hssf.record.BoolErrRecord;
 import org.apache.poi.hssf.record.BoundSheetRecord;
+import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.LabelRecord;
 import org.apache.poi.hssf.record.LabelSSTRecord;
@@ -77,7 +78,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 	 * 自定义需要处理的sheet编号,如果-1表示处理所有sheet
 	 */
 	private int rid = -1;
-	// 当前索引
+	// 当前rid索引
 	private int curRid = -1;
 
 	private final RowHandler rowHandler;
@@ -193,7 +194,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 			if (record instanceof MissingCellDummyRecord) {
 				// 空值的操作
 				MissingCellDummyRecord mc = (MissingCellDummyRecord) record;
-				addToRowCellList(mc.getColumn(), StrUtil.EMPTY);
+				addToRowCellList(mc);
 			} else if (record instanceof LastCellOfRowDummyRecord) {
 				// 行结束
 				processLastCell((LastCellOfRowDummyRecord) record);
@@ -208,17 +209,40 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 	// ---------------------------------------------------------------------------------------------- Private method start
 
 	/**
+	 * 将空数据加入到行列表中
+	 *
+	 * @param record MissingCellDummyRecord
+	 */
+	private void addToRowCellList(MissingCellDummyRecord record) {
+		addToRowCellList(record.getRow(), record.getColumn(), StrUtil.EMPTY);
+	}
+
+	/**
 	 * 将单元格数据加入到行列表中
-	 * @param index 加入位置
-	 * @param value 值
+	 *
+	 * @param record 单元格
+	 * @param value  值
+	 */
+	private void addToRowCellList(CellValueRecordInterface record, Object value) {
+		addToRowCellList(record.getRow(), record.getColumn(), value);
+	}
+
+	/**
+	 * 将单元格数据加入到行列表中
+	 *
+	 * @param row    行号
+	 * @param column 单元格
+	 * @param value  值
 	 */
-	private void addToRowCellList(int index, Object value){
-		while(index > this.rowCellList.size()){
+	private void addToRowCellList(int row, int column, Object value) {
+		while (column > this.rowCellList.size()) {
 			// 对于中间无数据的单元格补齐空白
 			this.rowCellList.add(StrUtil.EMPTY);
+			this.rowHandler.handleCell(this.curRid, row, rowCellList.size() - 1, value, null);
 		}
 
-		this.rowCellList.add(index, value);
+		this.rowCellList.add(column, value);
+		this.rowHandler.handleCell(this.curRid, row, column, value, null);
 	}
 
 	/**
@@ -232,12 +256,12 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 		switch (record.getSid()) {
 			case BlankRecord.sid:
 				// 空白记录
-				addToRowCellList(((BlankRecord) record).getColumn(), StrUtil.EMPTY);
+				addToRowCellList(((BlankRecord) record), StrUtil.EMPTY);
 				break;
 			case BoolErrRecord.sid:
 				// 布尔类型
 				final BoolErrRecord berec = (BoolErrRecord) record;
-				addToRowCellList(berec.getColumn(), berec.getBooleanValue());
+				addToRowCellList(berec, berec.getBooleanValue());
 				break;
 			case FormulaRecord.sid:
 				// 公式类型
@@ -253,7 +277,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 				} else {
 					value = StrUtil.wrap(HSSFFormulaParser.toFormulaString(stubWorkbook, formulaRec.getParsedExpression()), "\"");
 				}
-				addToRowCellList(formulaRec.getColumn(), value);
+				addToRowCellList(formulaRec, value);
 				break;
 			case StringRecord.sid:
 				// 单元格中公式的字符串
@@ -266,7 +290,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 			case LabelRecord.sid:
 				final LabelRecord lrec = (LabelRecord) record;
 				value = lrec.getValue();
-				addToRowCellList(lrec.getColumn(), value);
+				addToRowCellList(lrec, value);
 				break;
 			case LabelSSTRecord.sid:
 				// 字符串类型
@@ -274,7 +298,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 				if (null != sstRecord) {
 					value = sstRecord.getString(lsrec.getSSTIndex()).toString();
 				}
-				addToRowCellList(lsrec.getColumn(), ObjectUtil.defaultIfNull(value, StrUtil.EMPTY));
+				addToRowCellList(lsrec, ObjectUtil.defaultIfNull(value, StrUtil.EMPTY));
 				break;
 			case NumberRecord.sid: // 数字类型
 				final NumberRecord numrec = (NumberRecord) record;
@@ -296,7 +320,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
 					}
 				}
 				// 向容器加入列值
-				addToRowCellList(numrec.getColumn(), value);
+				addToRowCellList(numrec, value);
 				break;
 			default:
 				break;

+ 116 - 90
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java

@@ -1,6 +1,7 @@
 package cn.hutool.poi.excel.sax;
 
 import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.text.StrBuilder;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.poi.excel.sax.handler.RowHandler;
 import cn.hutool.poi.exceptions.POIException;
@@ -29,52 +30,39 @@ import java.util.List;
  */
 public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> implements ContentHandler {
 
-	/**
-	 * Cell单元格元素
-	 */
-	private static final String C_ELEMENT = "c";
-	/**
-	 * 行元素
-	 */
-	private static final String ROW_ELEMENT = "row";
-	/**
-	 * Cell中的行列号(Reference),行模式下此为行号属性名,列模式下为列号属性名
-	 */
-	private static final String R_ATTR = "r";
-	/**
-	 * SST(SharedStringsTable) 的索引,样式index
-	 */
-	private static final String S_ATTR_VALUE = "s";
-	// 列中属性值
-	private static final String T_ATTR_VALUE = "t";
 	// sheet r:Id前缀
 	private static final String RID_PREFIX = "rId";
 
+	// 单元格的格式表,对应style.xml
+	private StylesTable stylesTable;
 	// excel 2007 的共享字符串表,对应sharedString.xml
 	private SharedStringsTable sharedStringsTable;
-	// 当前行
-	private int curRow;
+	// sheet的索引
+	private int sheetIndex;
+
+	// 当前非空行
+	private int index;
 	// 当前列
 	private int curCell;
-	// 上一次的内容
-	private final StringBuilder lastContent = new StringBuilder(64);
 	// 单元数据类型
 	private CellDataType cellDataType;
+	// 当前行号,从0开始
+	private long rowNumber;
 	// 当前列坐标, 如A1,B5
 	private String curCoordinate;
 	// 前一个列的坐标
 	private String preCoordinate;
 	// 行的最大列坐标
 	private String maxCellCoordinate;
-	// 单元格的格式表,对应style.xml
-	private StylesTable stylesTable;
+	// 单元格样式
+	private XSSFCellStyle xssfCellStyle;
 	// 单元格存储的格式化字符串,nmtFmt的formatCode属性的值
 	private String numFmtString;
-	// sheet的索引
-	private int sheetIndex;
 
+	// 上一次的内容
+	private final StrBuilder lastContent = StrUtil.strBuilder();
 	// 存储每行的列元素
-	List<Object> rowCellList = new ArrayList<>();
+	private List<Object> rowCellList = new ArrayList<>();
 
 	/**
 	 * 行处理器
@@ -136,9 +124,9 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
 			final XSSFReader xssfReader = new XSSFReader(opcPackage);
 
 			// 获取共享样式表
-			try{
+			try {
 				stylesTable = xssfReader.getStylesTable();
-			} catch (Exception e){
+			} catch (Exception e) {
 				//ignore
 			}
 			// 获取共享字符串表
@@ -155,7 +143,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
 				final Iterator<InputStream> sheetInputStreams = xssfReader.getSheetsData();
 				while (sheetInputStreams.hasNext()) {
 					// 重新读取一个sheet时行归零
-					curRow = 0;
+					index = 0;
 					this.sheetIndex++;
 					sheetInputStream = sheetInputStreams.next();
 					ExcelSaxUtil.readFrom(sheetInputStream, this);
@@ -178,24 +166,11 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
 	 */
 	@Override
 	public void startElement(String uri, String localName, String qName, Attributes attributes) {
-		// 单元格元素
-		if (C_ELEMENT.equals(localName)) {
-			// 获取当前列坐标
-			String tempCurCoordinate = attributes.getValue(R_ATTR);
-			// 前一列为null,则将其设置为"@",A为第一列,ascii码为65,前一列即为@,ascii码64
-			if (preCoordinate == null) {
-				preCoordinate = String.valueOf(ExcelSaxUtil.CELL_FILL_CHAR);
-			} else {
-				// 存在,则前一列要设置为上一列的坐标
-				preCoordinate = curCoordinate;
-			}
-			// 重置当前列
-			curCoordinate = tempCurCoordinate;
-			// 设置单元格类型
-			setCellType(attributes);
+		if (ElementName.row.match(localName)) {// 行开始
+			startRow(attributes);
+		} else if (ElementName.c.match(localName)) {// 单元格元素
+			startCell(attributes);
 		}
-
-		lastContent.setLength(0);
 	}
 
 	/**
@@ -203,42 +178,10 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
 	 */
 	@Override
 	public void endElement(String uri, String localName, String qName) {
-		final String contentStr = StrUtil.trim(lastContent);
-
-//		if (T_ELEMENT.equals(qName)) {
-//			// type标签
-//			// rowCellList.add(curCell++, contentStr);
-//		} else
-		if (C_ELEMENT.equals(localName)) {
-			// cell标签
-			Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString);
-			// 补全单元格之间的空格
-			fillBlankCell(preCoordinate, curCoordinate, false);
-			rowCellList.add(curCell++, value);
-		} else if (ROW_ELEMENT.equals(localName)) {
-			// 如果是row标签,说明已经到了一行的结尾
-			// 最大列坐标以第一行的为准
-			if (curRow == 0) {
-				maxCellCoordinate = curCoordinate;
-			}
-
-			// 补全一行尾部可能缺失的单元格
-			if (maxCellCoordinate != null) {
-				fillBlankCell(curCoordinate, maxCellCoordinate, true);
-			}
-
-			rowHandler.handle(sheetIndex, curRow, rowCellList);
-
-			// 一行结束
-			// 新建一个新列,之前的列抛弃(可能被回收或rowHandler处理)
-			rowCellList = new ArrayList<>(curCell + 1);
-			// 行数增加
-			curRow++;
-			// 当前列置0
-			curCell = 0;
-			// 置空当前列坐标和前一列坐标
-			curCoordinate = null;
-			preCoordinate = null;
+		if (ElementName.c.match(localName)) { // 单元格结束
+			endCell();
+		} else if (ElementName.row.match(localName)) {// 行结束
+			endRow();
 		}
 	}
 
@@ -297,6 +240,89 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
 	// --------------------------------------------------------------------------------------- Pass method end
 
 	// --------------------------------------------------------------------------------------- Private method start
+
+	/**
+	 * 行开始
+	 *
+	 * @param attributes 属性列表
+	 */
+	private void startRow(Attributes attributes) {
+		this.rowNumber = Long.parseLong(AttributeName.r.getValue(attributes)) - 1;
+	}
+
+	/**
+	 * 单元格开始
+	 *
+	 * @param attributes 属性列表
+	 */
+	private void startCell(Attributes attributes) {
+		// 获取当前列坐标
+		final String tempCurCoordinate = AttributeName.r.getValue(attributes);
+		// 前一列为null,则将其设置为"@",A为第一列,ascii码为65,前一列即为@,ascii码64
+		if (preCoordinate == null) {
+			preCoordinate = String.valueOf(ExcelSaxUtil.CELL_FILL_CHAR);
+		} else {
+			// 存在,则前一列要设置为上一列的坐标
+			preCoordinate = curCoordinate;
+		}
+		// 重置当前列
+		curCoordinate = tempCurCoordinate;
+		// 设置单元格类型
+		setCellType(attributes);
+
+		// 清空之前的数据
+		lastContent.reset();
+	}
+
+	/**
+	 * 一个单元格结尾
+	 */
+	private void endCell() {
+		final String contentStr = StrUtil.trim(lastContent);
+		final Object value = ExcelSaxUtil.getDataValue(this.cellDataType, contentStr, this.sharedStringsTable, this.numFmtString);
+		// 补全单元格之间的空格
+		fillBlankCell(preCoordinate, curCoordinate, false);
+		addCellValue(curCell++, value);
+	}
+
+	/**
+	 * 一行结尾
+	 */
+	private void endRow() {
+		// 最大列坐标以第一个非空行的为准
+		if (index == 0) {
+			maxCellCoordinate = curCoordinate;
+		}
+
+		// 补全一行尾部可能缺失的单元格
+		if (maxCellCoordinate != null) {
+			fillBlankCell(curCoordinate, maxCellCoordinate, true);
+		}
+
+		rowHandler.handle(sheetIndex, rowNumber, rowCellList);
+
+		// 一行结束
+		// 新建一个新列,之前的列抛弃(可能被回收或rowHandler处理)
+		rowCellList = new ArrayList<>(curCell + 1);
+		// 行数增加
+		index++;
+		// 当前列置0
+		curCell = 0;
+		// 置空当前列坐标和前一列坐标
+		curCoordinate = null;
+		preCoordinate = null;
+	}
+
+	/**
+	 * 在一行中的指定列增加值
+	 * @param index 位置
+	 * @param value 值
+	 */
+	private void addCellValue(int index, Object value){
+		this.rowCellList.add(index, value);
+		this.rowHandler.handleCell(this.sheetIndex, this.rowNumber, index, value, this.xssfCellStyle);
+	}
+
 	/**
 	 * 填充空白单元格,如果前一个单元格大于后一个,不需要填充<br>
 	 *
@@ -311,7 +337,7 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
 				len++;
 			}
 			while (len-- > 0) {
-				rowCellList.add(curCell++, "");
+				addCellValue(curCell++, "");
 			}
 		}
 	}
@@ -319,19 +345,19 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
 	/**
 	 * 设置单元格的类型
 	 *
-	 * @param attribute 属性
+	 * @param attributes 属性
 	 */
-	private void setCellType(Attributes attribute) {
+	private void setCellType(Attributes attributes) {
 		// numFmtString的值
 		numFmtString = "";
-		this.cellDataType = CellDataType.of(attribute.getValue(T_ATTR_VALUE));
+		this.cellDataType = CellDataType.of(AttributeName.t.getValue(attributes));
 
 		// 获取单元格的xf索引,对应style.xml中cellXfs的子元素xf
-		if(null != this.stylesTable){
-			final String xfIndexStr = attribute.getValue(S_ATTR_VALUE);
+		if (null != this.stylesTable) {
+			final String xfIndexStr = AttributeName.s.getValue(attributes);
 			if (null != xfIndexStr) {
 				int xfIndex = Integer.parseInt(xfIndexStr);
-				final XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(xfIndex);
+				this.xssfCellStyle = stylesTable.getStyleAt(xfIndex);
 				numFmtString = xssfCellStyle.getDataFormatString();
 				// 单元格存储格式的索引,对应style.xml中的numFmts元素的子元素索引
 				int numFmtIndex = xssfCellStyle.getDataFormat();

+ 17 - 3
hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/RowHandler.java

@@ -1,5 +1,7 @@
 package cn.hutool.poi.excel.sax.handler;
 
+import org.apache.poi.ss.usermodel.CellStyle;
+
 import java.util.List;
 
 /**
@@ -9,12 +11,24 @@ import java.util.List;
  */
 @FunctionalInterface
 public interface RowHandler {
-	
+
 	/**
-	 * 处理一数据
+	 * 处理一个单元格的数据
 	 * @param sheetIndex 当前Sheet序号
 	 * @param rowIndex 当前行号
+	 * @param cellIndex 当前列号
+	 * @param value 单元格的值
+	 * @param xssfCellStyle 单元格样式
+	 */
+	default void handleCell(int sheetIndex, long rowIndex, int cellIndex, Object value, CellStyle xssfCellStyle){
+		//pass
+	}
+
+	/**
+	 * 处理一行数据
+	 * @param sheetIndex 当前Sheet序号
+	 * @param rowIndex 当前行号,从0开始计数
 	 * @param rowList 行数据列表
 	 */
-	void handle(int sheetIndex, int rowIndex, List<Object> rowList);
+	void handle(int sheetIndex, long rowIndex, List<Object> rowList);
 }

+ 39 - 2
hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java

@@ -7,15 +7,17 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.poi.excel.ExcelUtil;
 import cn.hutool.poi.excel.sax.Excel03SaxReader;
 import cn.hutool.poi.excel.sax.handler.RowHandler;
+import org.apache.poi.ss.usermodel.CellStyle;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import java.util.List;
+
 /**
  * Excel sax方式读取
- * 
- * @author looly
  *
+ * @author looly
  */
 public class ExcelSaxReadTest {
 
@@ -64,4 +66,39 @@ public class ExcelSaxReadTest {
 			}
 		};
 	}
+
+	@Test
+	@Ignore
+	public void handle07CellTest() {
+		ExcelUtil.readBySax("d:/test/test.xlsx", -1, new RowHandler() {
+
+					@Override
+					public void handleCell(int sheetIndex, long rowIndex, int cellIndex, Object value, CellStyle xssfCellStyle) {
+						Console.log("{} {} {}", rowIndex, cellIndex, value);
+					}
+
+					@Override
+					public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
+
+					}
+				}
+		);
+	}
+
+	@Test
+	@Ignore
+	public void handle03CellTest() {
+		ExcelUtil.readBySax("d:/test/test.xls", -1, new RowHandler() {
+
+					@Override
+					public void handleCell(int sheetIndex, long rowIndex, int cellIndex, Object value, CellStyle xssfCellStyle) {
+						Console.log("{} {} {}", rowIndex, cellIndex, value);
+					}
+
+					@Override
+					public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
+					}
+				}
+		);
+	}
 }