add reader

This commit is contained in:
Looly 2020-09-26 02:22:34 +08:00
parent 4c12094a7f
commit 50134d8822
13 changed files with 639 additions and 122 deletions

View File

@ -23,6 +23,7 @@
* 【http 】 完善StrUtil的注释pr#186@Gitee
* 【aop 】 去除调试日志issue#1116@Github
* 【core 】 增加'反转义pr#1121@Github
* 【poi 】 增加SheetReader和XXXRowHandlerissue#I1WHJP@Gitee
### Bug修复
* 【crypto 】 修复SM2验签后无法解密问题issue#I1W0VP@Gitee

View File

@ -1,12 +1,13 @@
package cn.hutool.cron.demo;
import org.junit.Ignore;
import org.junit.Test;
import cn.hutool.core.lang.Console;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.TaskExecutor;
import cn.hutool.cron.listener.TaskListener;
import cn.hutool.cron.task.Task;
import org.junit.Ignore;
import org.junit.Test;
/**
* 定时任务样例
@ -38,6 +39,23 @@ public class CronTest {
@Test
@Ignore
public void cronTest2() {
CronUtil.getScheduler().addListener(new TaskListener() {
@Override
public void onStart(TaskExecutor executor) {
Console.log("Listen task start!");
}
@Override
public void onSucceeded(TaskExecutor executor) {
}
@Override
public void onFailed(TaskExecutor executor, Throwable exception) {
}
});
// 支持秒级别定时任务
CronUtil.setMatchSecond(true);
CronUtil.start();

View File

@ -0,0 +1,45 @@
package cn.hutool.poi.excel;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.extractor.ExcelExtractor;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* {@link ExcelExtractor}工具封装
*
* @author looly
* @since 5.4.4
*/
public class ExcelExtractorUtil {
/**
* 获取 {@link ExcelExtractor} 对象
*
* @return {@link ExcelExtractor}
*/
public static ExcelExtractor getExtractor(Workbook wb) {
ExcelExtractor extractor;
if (wb instanceof HSSFWorkbook) {
extractor = new org.apache.poi.hssf.extractor.ExcelExtractor((HSSFWorkbook) wb);
} else {
extractor = new XSSFExcelExtractor((XSSFWorkbook) wb);
}
return extractor;
}
/**
* 读取为文本格式<br>
* 使用{@link ExcelExtractor} 提取Excel内容
*
* @param wb {@link Workbook}
* @param withSheetName 是否附带sheet名
* @return Excel文本
* @since 4.1.0
*/
public static String readAsText(Workbook wb, boolean withSheetName) {
final ExcelExtractor extractor = getExtractor(wb);
extractor.setIncludeSheetNames(withSheetName);
return extractor.getText();
}
}

View File

@ -1,28 +1,22 @@
package cn.hutool.poi.excel;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.cell.CellEditor;
import cn.hutool.poi.excel.cell.CellHandler;
import cn.hutool.poi.excel.cell.CellUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import cn.hutool.poi.excel.reader.BeanSheetReader;
import cn.hutool.poi.excel.reader.ListSheetReader;
import cn.hutool.poi.excel.reader.MapSheetReader;
import cn.hutool.poi.excel.reader.SheetReader;
import org.apache.poi.ss.extractor.ExcelExtractor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -256,37 +250,31 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
}
/**
* 读取工作簿中指定的Sheet
* 读取工作簿中指定的Sheet此方法会把第一行作为标题行替换标题别名
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
* @return 行的集合一行使用List表示
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public List<List<Object>> read(int startRowIndex, int endRowIndex) {
checkNotClosed();
List<List<Object>> resultList = new ArrayList<>();
return read(startRowIndex, endRowIndex, true);
}
startRowIndex = Math.max(startRowIndex, this.sheet.getFirstRowNum());// 读取起始行包含
endRowIndex = Math.min(endRowIndex, this.sheet.getLastRowNum());// 读取结束行包含
boolean isFirstLine = true;
List rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
rowList = readRow(i);
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
if (null == rowList) {
rowList = new ArrayList<>(0);
}
if (isFirstLine) {
isFirstLine = false;
if (MapUtil.isNotEmpty(this.headerAlias)) {
rowList = aliasHeader(rowList);
}
}
resultList.add(rowList);
}
}
return resultList;
/**
* 读取工作簿中指定的Sheet
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
* @param aliasFirstLine 是否首行作为标题行转换别名
* @return 行的集合一行使用List表示
* @since 5.4.4
*/
public List<List<Object>> read(int startRowIndex, int endRowIndex, boolean aliasFirstLine) {
final ListSheetReader reader = new ListSheetReader(startRowIndex, endRowIndex, aliasFirstLine);
reader.setCellEditor(this.cellEditor);
reader.setIgnoreEmptyRow(this.ignoreEmptyRow);
reader.setHeaderAlias(headerAlias);
return read(reader);
}
/**
@ -348,33 +336,11 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @return Map的列表
*/
public List<Map<String, Object>> read(int headerRowIndex, int startRowIndex, int endRowIndex) {
checkNotClosed();
// 边界判断
final int firstRowNum = sheet.getFirstRowNum();
final int lastRowNum = sheet.getLastRowNum();
if (headerRowIndex < firstRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is lower than first row index {}.", headerRowIndex, firstRowNum));
} else if (headerRowIndex > lastRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is greater than last row index {}.", headerRowIndex, firstRowNum));
}
startRowIndex = Math.max(startRowIndex, firstRowNum);// 读取起始行包含
endRowIndex = Math.min(endRowIndex, lastRowNum);// 读取结束行包含
// 读取header
List<Object> headerList = readRow(sheet.getRow(headerRowIndex));
final List<Map<String, Object>> result = new ArrayList<>(endRowIndex - startRowIndex + 1);
List<Object> rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
if (i != headerRowIndex) {
// 跳过标题行
rowList = readRow(sheet.getRow(i));
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
result.add(IterUtil.toMap(aliasHeader(headerList), rowList, true));
}
}
}
return result;
final MapSheetReader reader = new MapSheetReader(headerRowIndex, startRowIndex, endRowIndex);
reader.setCellEditor(this.cellEditor);
reader.setIgnoreEmptyRow(this.ignoreEmptyRow);
reader.setHeaderAlias(headerAlias);
return read(reader);
}
/**
@ -412,19 +378,25 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @param beanType 每行对应Bean的类型
* @return Map的列表
*/
@SuppressWarnings("unchecked")
public <T> List<T> read(int headerRowIndex, int startRowIndex, int endRowIndex, Class<T> beanType) {
checkNotClosed();
final List<Map<String, Object>> mapList = read(headerRowIndex, startRowIndex, endRowIndex);
if (Map.class.isAssignableFrom(beanType)) {
return (List<T>) mapList;
}
final BeanSheetReader<T> reader = new BeanSheetReader<>(headerRowIndex, startRowIndex, endRowIndex, beanType);
reader.setCellEditor(this.cellEditor);
reader.setIgnoreEmptyRow(this.ignoreEmptyRow);
reader.setHeaderAlias(headerAlias);
return read(reader);
}
final List<T> beanList = new ArrayList<>(mapList.size());
for (Map<String, Object> map : mapList) {
beanList.add(BeanUtil.toBean(map, beanType));
}
return beanList;
/**
* 读取数据为指定类型
*
* @param <T> 读取数据类型
* @param sheetReader {@link SheetReader}实现
* @return 数据读取结果
* @since 5.4.4
*/
public <T> T read(SheetReader<T> sheetReader){
checkNotClosed();
return Assert.notNull(sheetReader).read(this.sheet);
}
/**
@ -436,9 +408,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @since 4.1.0
*/
public String readAsText(boolean withSheetName) {
final ExcelExtractor extractor = getExtractor();
extractor.setIncludeSheetNames(withSheetName);
return extractor.getText();
return ExcelExtractorUtil.readAsText(this.workbook, withSheetName);
}
/**
@ -448,14 +418,7 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
* @since 4.1.0
*/
public ExcelExtractor getExtractor() {
ExcelExtractor extractor;
Workbook wb = this.workbook;
if (wb instanceof HSSFWorkbook) {
extractor = new org.apache.poi.hssf.extractor.ExcelExtractor((HSSFWorkbook) wb);
} else {
extractor = new XSSFExcelExtractor((XSSFWorkbook) wb);
}
return extractor;
return ExcelExtractorUtil.getExtractor(this.workbook);
}
/**
@ -504,42 +467,6 @@ public class ExcelReader extends ExcelBase<ExcelReader> {
return RowUtil.readRow(row, this.cellEditor);
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerList 原标题列表
* @return 转换别名列表
*/
private List<String> aliasHeader(List<Object> headerList) {
if(CollUtil.isEmpty(headerList)){
return new ArrayList<>(0);
}
final int size = headerList.size();
final ArrayList<String> result = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
result.add(aliasHeader(headerList.get(i), i));
}
return result;
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerObj 原标题
* @param index 标题所在列号当标题为空时列号对应的字母便是header
* @return 转换别名列表
* @since 4.3.2
*/
private String aliasHeader(Object headerObj, int index) {
if (null == headerObj) {
return ExcelUtil.indexToColName(index);
}
final String header = headerObj.toString();
return ObjectUtil.defaultIfNull(this.headerAlias.get(header), header);
}
/**
* 检查是否未关闭状态
*/

View File

@ -0,0 +1,140 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.RowUtil;
import cn.hutool.poi.excel.cell.CellEditor;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 抽象{@link Sheet}数据读取实现
*
* @param <T> 读取类型
* @author looly
* @since 5.4.4
*/
public abstract class AbstractSheetReader<T> implements SheetReader<T> {
/**
* 读取起始行包含从0开始计数
*/
protected final int startRowIndex;
/**
* 读取结束行包含从0开始计数
*/
protected final int endRowIndex;
/**
* 是否忽略空行
*/
protected boolean ignoreEmptyRow = true;
/**
* 单元格值处理接口
*/
protected CellEditor cellEditor;
/**
* 标题别名
*/
private Map<String, String> headerAlias = new HashMap<>();
/**
* 构造
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
*/
public AbstractSheetReader(int startRowIndex, int endRowIndex) {
this.startRowIndex = startRowIndex;
this.endRowIndex = endRowIndex;
}
/**
* 设置单元格值处理逻辑<br>
* 当Excel中的值并不能满足我们的读取要求时通过传入一个编辑接口可以对单元格值自定义例如对数字和日期类型值转换为字符串等
*
* @param cellEditor 单元格值处理接口
*/
public void setCellEditor(CellEditor cellEditor) {
this.cellEditor = cellEditor;
}
/**
* 设置是否忽略空行
*
* @param ignoreEmptyRow 是否忽略空行
*/
public void setIgnoreEmptyRow(boolean ignoreEmptyRow) {
this.ignoreEmptyRow = ignoreEmptyRow;
}
/**
* 设置标题行的别名Map
*
* @param headerAlias 别名Map
*/
public void setHeaderAlias(Map<String, String> headerAlias) {
this.headerAlias = headerAlias;
}
/**
* 增加标题别名
*
* @param header 标题
* @param alias 别名
*/
public void addHeaderAlias(String header, String alias) {
this.headerAlias.put(header, alias);
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerList 原标题列表
* @return 转换别名列表
*/
protected List<String> aliasHeader(List<Object> headerList) {
if (CollUtil.isEmpty(headerList)) {
return new ArrayList<>(0);
}
final int size = headerList.size();
final ArrayList<String> result = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
result.add(aliasHeader(headerList.get(i), i));
}
return result;
}
/**
* 转换标题别名如果没有别名则使用原标题当标题为空时列号对应的字母便是header
*
* @param headerObj 原标题
* @param index 标题所在列号当标题为空时列号对应的字母便是header
* @return 转换别名列表
* @since 4.3.2
*/
protected String aliasHeader(Object headerObj, int index) {
if (null == headerObj) {
return ExcelUtil.indexToColName(index);
}
final String header = headerObj.toString();
return ObjectUtil.defaultIfNull(this.headerAlias.get(header), header);
}
/**
* 读取某一行数据
*
* @param rowIndex 行号从0开始
* @return 一行数据
* @since 4.0.3
*/
protected List<Object> readRow(Sheet sheet, int rowIndex) {
return RowUtil.readRow(sheet.getRow(rowIndex), this.cellEditor);
}
}

View File

@ -0,0 +1,87 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.cell.CellEditor;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 读取{@link Sheet}为bean的List列表形式
*
* @author looly
* @since 5.4.4
*/
public class BeanSheetReader<T> implements SheetReader<List<T>> {
private final Class<T> beanClass;
private final MapSheetReader mapSheetReader;
/**
* 构造
*
* @param headerRowIndex 标题所在行如果标题行在读取的内容行中间这行做为数据将忽略
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
* @param beanClass 每行对应Bean的类型
*/
public BeanSheetReader(int headerRowIndex, int startRowIndex, int endRowIndex, Class<T> beanClass) {
mapSheetReader = new MapSheetReader(headerRowIndex, startRowIndex, endRowIndex);
this.beanClass = beanClass;
}
@Override
@SuppressWarnings("unchecked")
public List<T> read(Sheet sheet) {
final List<Map<String, Object>> mapList = mapSheetReader.read(sheet);
if (Map.class.isAssignableFrom(this.beanClass)) {
return (List<T>) mapList;
}
final List<T> beanList = new ArrayList<>(mapList.size());
for (Map<String, Object> map : mapList) {
beanList.add(BeanUtil.toBean(map, this.beanClass));
}
return beanList;
}
/**
* 设置单元格值处理逻辑<br>
* 当Excel中的值并不能满足我们的读取要求时通过传入一个编辑接口可以对单元格值自定义例如对数字和日期类型值转换为字符串等
*
* @param cellEditor 单元格值处理接口
*/
public void setCellEditor(CellEditor cellEditor) {
this.mapSheetReader.setCellEditor(cellEditor);
}
/**
* 设置是否忽略空行
*
* @param ignoreEmptyRow 是否忽略空行
*/
public void setIgnoreEmptyRow(boolean ignoreEmptyRow) {
this.mapSheetReader.setIgnoreEmptyRow(ignoreEmptyRow);
}
/**
* 设置标题行的别名Map
*
* @param headerAlias 别名Map
*/
public void setHeaderAlias(Map<String, String> headerAlias) {
this.mapSheetReader.setHeaderAlias(headerAlias);
}
/**
* 增加标题别名
*
* @param header 标题
* @param alias 别名
*/
public void addHeaderAlias(String header, String alias) {
this.mapSheetReader.addHeaderAlias(header, alias);
}
}

View File

@ -0,0 +1,50 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.List;
/**
* 读取{@link Sheet}为List列表形式
*
* @author looly
* @since 5.4.4
*/
public class ListSheetReader extends AbstractSheetReader<List<List<Object>>> {
private final boolean aliasFirstLine;
/**
* 构造
*
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
*/
public ListSheetReader(int startRowIndex, int endRowIndex, boolean aliasFirstLine) {
super(startRowIndex, endRowIndex);
this.aliasFirstLine = aliasFirstLine;
}
@Override
public List<List<Object>> read(Sheet sheet) {
final List<List<Object>> resultList = new ArrayList<>();
int startRowIndex = Math.max(this.startRowIndex, sheet.getFirstRowNum());// 读取起始行包含
int endRowIndex = Math.min(this.endRowIndex, sheet.getLastRowNum());// 读取结束行包含
List<Object> rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
rowList = readRow(sheet, i);
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
if (aliasFirstLine && i == startRowIndex) {
// 第一行作为标题行替换别名
rowList = Convert.toList(Object.class, aliasHeader(rowList));
}
resultList.add(rowList);
}
}
return resultList;
}
}

View File

@ -0,0 +1,63 @@
package cn.hutool.poi.excel.reader;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.poi.ss.usermodel.Sheet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 读取{@link Sheet}为Map的List列表形式
*
* @author looly
* @since 5.4.4
*/
public class MapSheetReader extends AbstractSheetReader<List<Map<String, Object>>> {
private final int headerRowIndex;
/**
* 构造
*
* @param headerRowIndex 标题所在行如果标题行在读取的内容行中间这行做为数据将忽略
* @param startRowIndex 起始行包含从0开始计数
* @param endRowIndex 结束行包含从0开始计数
*/
public MapSheetReader(int headerRowIndex, int startRowIndex, int endRowIndex) {
super(startRowIndex, endRowIndex);
this.headerRowIndex = headerRowIndex;
}
@Override
public List<Map<String, Object>> read(Sheet sheet) {
// 边界判断
final int firstRowNum = sheet.getFirstRowNum();
final int lastRowNum = sheet.getLastRowNum();
if (headerRowIndex < firstRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is lower than first row index {}.", headerRowIndex, firstRowNum));
} else if (headerRowIndex > lastRowNum) {
throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is greater than last row index {}.", headerRowIndex, firstRowNum));
}
final int startRowIndex = Math.max(this.startRowIndex, firstRowNum);// 读取起始行包含
final int endRowIndex = Math.min(this.endRowIndex, lastRowNum);// 读取结束行包含
// 读取header
List<String> headerList = aliasHeader(readRow(sheet, headerRowIndex));
final List<Map<String, Object>> result = new ArrayList<>(endRowIndex - startRowIndex + 1);
List<Object> rowList;
for (int i = startRowIndex; i <= endRowIndex; i++) {
// 跳过标题行
if (i != headerRowIndex) {
rowList = readRow(sheet, i);
if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) {
result.add(IterUtil.toMap(headerList, rowList, true));
}
}
}
return result;
}
}

View File

@ -0,0 +1,20 @@
package cn.hutool.poi.excel.reader;
import org.apache.poi.ss.usermodel.Sheet;
/**
* Excel {@link Sheet}读取接口通过实现此接口{@link Sheet}中的数据读取为不同类型
*
* @param <T> 读取的数据类型
*/
@FunctionalInterface
public interface SheetReader<T> {
/**
* 读取数据
*
* @param sheet {@link Sheet}
* @return 读取结果
*/
T read(Sheet sheet);
}

View File

@ -0,0 +1,7 @@
/**
* 数据读取接口及实现此包中定义了SheetReader通过实现此接口实现sheet中的数据读取为不同类型
*
* @author looly
*
*/
package cn.hutool.poi.excel.reader;

View File

@ -0,0 +1,59 @@
package cn.hutool.poi.excel.sax.handler;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.func.Func1;
import java.util.List;
/**
* 抽象行数据处理器通过实现{@link #handle(int, long, List)} 处理原始数据<br>
* 并调用{@link #handleData(int, long, Object)}处理经过转换后的数据
*
* @param <T> 转换后的数据类型
* @author looly
* @since 5.4.4
*/
public abstract class AbstractRowHandler<T> implements RowHandler {
/**
* 读取起始行包含从0开始计数
*/
protected final int startRowIndex;
/**
* 读取结束行包含从0开始计数
*/
protected final int endRowIndex;
/**
* 行数据转换函数
*/
protected Func1<List<Object>, T> convertFunc;
/**
* 构造
*
* @param startRowIndex 读取起始行包含从0开始计数
* @param endRowIndex 读取结束行包含从0开始计数
*/
public AbstractRowHandler(int startRowIndex, int endRowIndex) {
this.startRowIndex = startRowIndex;
this.endRowIndex = endRowIndex;
}
@Override
public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
Assert.notNull(convertFunc);
if (rowIndex < this.startRowIndex || rowIndex > this.endRowIndex) {
return;
}
handleData(sheetIndex, rowIndex, convertFunc.callWithRuntimeException(rowList));
}
/**
* 处理转换后的数据
*
* @param sheetIndex 当前Sheet序号
* @param rowIndex 当前行号从0开始计数
* @param data 行数据
*/
public abstract void handleData(int sheetIndex, long rowIndex, T data);
}

View File

@ -0,0 +1,51 @@
package cn.hutool.poi.excel.sax.handler;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import java.util.List;
/**
* Bean形式的行处理器<br>
* 将一行数据转换为Mapkey为指定行value为当前行对应位置的值
*
* @author looly
* @since 5.4.4
*/
public abstract class BeanRowHandler<T> extends AbstractRowHandler<T>{
/**
* 标题所在行从0开始计数
*/
private final int headerRowIndex;
/**
* 标题行
*/
List<String> headerList;
/**
* 构造
*
* @param headerRowIndex 标题所在行从0开始计数
* @param startRowIndex 读取起始行包含从0开始计数
* @param endRowIndex 读取结束行包含从0开始计数
*/
public BeanRowHandler(int headerRowIndex, int startRowIndex, int endRowIndex, Class<T> clazz){
super(startRowIndex, endRowIndex);
Assert.isTrue(headerRowIndex <= startRowIndex, "Header row must before the start row!");
this.headerRowIndex = headerRowIndex;
this.convertFunc = (rowList)-> BeanUtil.toBean(IterUtil.toMap(headerList, rowList), clazz);
}
@Override
public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
if (rowIndex == this.headerRowIndex) {
this.headerList = ListUtil.unmodifiable(Convert.toList(String.class, rowList));
return;
}
super.handle(sheetIndex, rowIndex, rowList);
}
}

View File

@ -0,0 +1,49 @@
package cn.hutool.poi.excel.sax.handler;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import java.util.List;
import java.util.Map;
/**
* Map形式的行处理器<br>
* 将一行数据转换为Mapkey为指定行value为当前行对应位置的值
*
* @author looly
* @since 5.4.4
*/
public abstract class MapRowHandler extends AbstractRowHandler<Map<String, Object>> {
/**
* 标题所在行从0开始计数
*/
private final int headerRowIndex;
/**
* 标题行
*/
List<String> headerList;
/**
* 构造
*
* @param headerRowIndex 标题所在行从0开始计数
* @param startRowIndex 读取起始行包含从0开始计数
* @param endRowIndex 读取结束行包含从0开始计数
*/
public MapRowHandler(int headerRowIndex, int startRowIndex, int endRowIndex){
super(startRowIndex, endRowIndex);
this.headerRowIndex = headerRowIndex;
this.convertFunc = (rowList)-> IterUtil.toMap(headerList, rowList);
}
@Override
public void handle(int sheetIndex, long rowIndex, List<Object> rowList) {
if (rowIndex == this.headerRowIndex) {
this.headerList = ListUtil.unmodifiable(Convert.toList(String.class, rowList));
return;
}
super.handle(sheetIndex, rowIndex, rowList);
}
}