
cn.creekmoon.excelUtils.core.SheetReader Maven / Gradle / Ivy
package cn.creekmoon.excelUtils.core;
import cn.creekmoon.excelUtils.converter.StringConverter;
import cn.creekmoon.excelUtils.exception.CheckedExcelException;
import cn.creekmoon.excelUtils.exception.GlobalExceptionManager;
import cn.creekmoon.excelUtils.util.ExcelUtils;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.sax.Excel07SaxReader;
import cn.hutool.poi.excel.sax.handler.RowHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import static cn.creekmoon.excelUtils.core.ExcelConstants.*;
@Slf4j
public class SheetReader {
public SheetReaderContext sheetReaderContext;
protected ExcelImport parent;
protected SheetWriter sheetWriter;
public SheetReader addConvert(String title, ExFunction convert, BiConsumer setter) {
sheetReaderContext.title2converts.put(title, convert);
sheetReaderContext.title2consumers.put(title, setter);
return this;
}
/**
* 添加单个单元格的转换器
*
* @param colIndex 列下标(从0开始)
* @param rowIndex 行下标(从0开始)
* @param setter 消费者
* @return
*/
public SheetReader addSingleCellReader(int colIndex, int rowIndex, Consumer setter) {
sheetReaderContext.singleCellConsumers.computeIfAbsent(rowIndex, HashMap::new);
sheetReaderContext.singleCellConsumers.get(rowIndex).put(colIndex, setter);
return this;
}
/**
* 添加单个单元格的转换器
*
* @param cellReference 单元格引用(A1,B1,C1...)
* @param reader 消费者
* @return
*/
public SheetReader addSingleCellReader(String cellReference, Consumer reader) {
int colIndex = ExcelUtils.excelCellToColumnNumber(cellReference) - 1;
int rowIndex = ExcelUtils.excelCellToRowNumber(cellReference) - 1;
return addSingleCellReader(colIndex, rowIndex, reader);
}
public SheetReader addConvert(String title, BiConsumer reader) {
addConvert(title, x -> x, reader);
return this;
}
public SheetReader addConvertAndSkipEmpty(String title, BiConsumer setter) {
sheetReaderContext.skipEmptyTitles.add(title);
addConvert(title, x -> x, setter);
return this;
}
public SheetReader addConvertAndSkipEmpty(String title, ExFunction convert, BiConsumer setter) {
sheetReaderContext.skipEmptyTitles.add(title);
addConvert(title, convert, setter);
return this;
}
public SheetReader addConvertAndMustExist(String title, BiConsumer setter) {
sheetReaderContext.mustExistTitles.add(title);
addConvert(title, x -> x, setter);
return this;
}
public SheetReader addConvertAndMustExist(String title, ExFunction convert, BiConsumer setter) {
sheetReaderContext.mustExistTitles.add(title);
addConvert(title, convert, setter);
return this;
}
/**
* 添加校验阶段后置处理器 当所有的convert执行完成后会执行这个操作做最后的校验处理
*
* @param postProcessor 后置处理器
* @param
* @return
*/
public SheetReader addConvertPostProcessor(ExConsumer postProcessor) {
if (postProcessor != null) {
this.sheetReaderContext.convertPostProcessors.add(postProcessor);
}
return this;
}
/**
* 读取excel
*
* @param verifyAllDataFormats true=校验所有行的格式后,才按行进行消费(默认) false=直接按行消费
* @param dataConsumer 数据消费者
* @return
*/
public ExcelImport read(boolean verifyAllDataFormats, ExConsumer dataConsumer) {
if (verifyAllDataFormats) {
/* 以readAll模式进行读,再逐行消费*/
List rs = readAll();
rs.forEach(x -> {
try {
dataConsumer.accept(x);
this.setResult(x, IMPORT_SUCCESS_MSG);
} catch (Exception e) {
parent.getErrorCount().incrementAndGet();
this.setResult(x, GlobalExceptionManager.getExceptionMsg(e));
}
});
} else {
/*以原生的按行读取*/
readByRow(dataConsumer);
}
return parent;
}
public ExcelImport read(ExConsumer dataConsumer) {
return read(true, dataConsumer);
}
@SneakyThrows
public ExcelImport readByRow(ExConsumer dataConsumer) {
/*尝试拿锁*/
ExcelImport.importSemaphore.acquire();
try {
//新版读取 使用SAX读取模式
Excel07SaxReader excel07SaxReader = initSaxReader(sheetReaderContext.sheetIndex,
(obj, rawMap) -> {
dataConsumer.accept(obj);
rawMap.put(RESULT_TITLE, IMPORT_SUCCESS_MSG);
},
(obj, rawMap) -> {
sheetWriter.writeByMap(Collections.singletonList(rawMap));
//parent.excelExport.getBigExcelWriter().write(Collections.singletonList(rawMap));
});
sheetWriter = parent.excelExport.switchSheet(ExcelExport.generateSheetNameByIndex(sheetReaderContext.sheetIndex), Map.class);
sheetWriter.setColumnWidthDefault();
/*第一个参数 文件流 第二个参数 -1就是读取所有的sheet页*/
excel07SaxReader.read(this.parent.file.getInputStream(), -1);
} catch (Exception e) {
log.error("SaxReader读取Excel文件异常", e);
e.printStackTrace();
ExcelExport.cleanTempFileDelay(parent.excelExport.stopWrite());
} finally {
/*释放信号量*/
ExcelImport.importSemaphore.release();
}
return this.parent;
}
/**
* 读取Excel内容到一个List (内存模式)
* 这个方法保证所有的数据都是通过格式校验的, 如果任一格式校验失败将返回整个空数组.
*
* @return
*/
@SneakyThrows
public List readAll() {
ArrayList convertObjectList = new ArrayList<>();
/*尝试拿锁*/
ExcelImport.importSemaphore.acquire();
AtomicReference CONVERT_FAIL = new AtomicReference<>(false);
try {
//新版读取 使用SAX读取模式
Excel07SaxReader excel07SaxReader = initSaxReader(sheetReaderContext.sheetIndex,
(obj, rawMap) -> {
convertObjectList.add(obj);
},
(obj, rawMap) -> {
if (obj == null && rawMap != null) {
//假如存在任一数据convert阶段就失败的单, 将打一个标记
CONVERT_FAIL.set(true);
}
parent.convertObject2rawData.put(obj, rawMap);
parent.sheetIndex2rawData
.computeIfAbsent(sheetReaderContext.sheetIndex, k -> new ArrayList<>())
.add(rawMap);
});
/*第一个参数 文件流 第二个参数 -1就是读取所有的sheet页*/
excel07SaxReader.read(this.parent.file.getInputStream(), -1);
} catch (Exception e) {
log.error("SaxReader读取Excel文件异常", e);
ExcelExport.cleanTempFileDelay(parent.excelExport.stopWrite());
} finally {
/*释放信号量*/
ExcelImport.importSemaphore.release();
}
//假如存在convert阶段就失败的单, 说明readAll无法读取完整的数据, 此时将返回空集合
return CONVERT_FAIL.get() ? Collections.emptyList() : convertObjectList;
}
/**
* 增加读取范围限制
*
* @param titleRowIndex 标题所在的行数(下标按照从0开始, 如果是第一行则填0)
* @param latestRowIndex 最后一条数据所在的行数(下标按照从0开始, 如果是第一行则填0)
* @return
*/
public SheetReader indexConfig(int titleRowIndex, int firstRowIndex, int latestRowIndex) {
this.sheetReaderContext.titleRowIndex = titleRowIndex;
this.sheetReaderContext.firstRowIndex = firstRowIndex;
this.sheetReaderContext.latestRowIndex = latestRowIndex;
return this;
}
/**
* 增加读取范围限制
*
* @param titleRowIndex 标题所在的行数(下标按照从0开始, 如果是第一行则填0)
* @param latestRowIndex 最后一条数据所在的行数(下标按照从0开始, 如果是第一行则填0)
* @return
*/
public SheetReader indexConfig(int titleRowIndex, int latestRowIndex) {
return indexConfig(titleRowIndex, titleRowIndex + 1, latestRowIndex);
}
/**
* 增加读取范围限制
*
* @param titleRowIndex 标题所在的行数(下标按照从0开始, 如果是第一行则填0)
* @return
*/
public SheetReader indexConfig(int titleRowIndex) {
return indexConfig(titleRowIndex, titleRowIndex + 1, Integer.MAX_VALUE);
}
/**
* 行转换
*
* @param row 实际上是Map对象
* @throws Exception
*/
private R rowConvert(Map row) throws Exception {
/*进行模板一致性检查*/
if (sheetReaderContext.ENABLE_TITLE_CHECK) {
if (sheetReaderContext.TITLE_CHECK_FAIL_FLAG || !titleConsistencyCheck(sheetReaderContext.title2converts.keySet(), row.keySet())) {
sheetReaderContext.TITLE_CHECK_FAIL_FLAG = true;
throw new CheckedExcelException(TITLE_CHECK_ERROR);
}
}
sheetReaderContext.ENABLE_TITLE_CHECK = false;
/*过滤空白行*/
if (sheetReaderContext.ENABLE_BLANK_ROW_FILTER
&& row.values().stream().allMatch(x -> x == null || "".equals(x))
) {
return null;
}
/*初始化空对象*/
R convertObject = (R) this.sheetReaderContext.newObjectSupplier.get();
/*最大转换次数*/
int maxConvertCount = this.sheetReaderContext.title2consumers.keySet().size();
/*执行convert*/
for (Map.Entry entry : row.entrySet()) {
/*如果包含不支持的标题, 或者已经超过最大次数则不再进行读取*/
if (!this.sheetReaderContext.title2consumers.containsKey(entry.getKey()) || maxConvertCount-- <= 0) {
continue;
}
String value = Optional.ofNullable(entry.getValue()).map(x -> (String) x).orElse("");
/*检查必填项/检查可填项*/
if (StrUtil.isBlank(value)) {
if (this.sheetReaderContext.mustExistTitles.contains(entry.getKey())) {
throw new CheckedExcelException(StrFormatter.format(FIELD_LACK_MSG, entry.getKey()));
}
if (this.sheetReaderContext.skipEmptyTitles.contains(entry.getKey())) {
continue;
}
}
/*转换数据*/
try {
Object convertValue = this.sheetReaderContext.title2converts.get(entry.getKey()).apply(value);
this.sheetReaderContext.title2consumers.get(entry.getKey()).accept(convertObject, convertValue);
} catch (Exception e) {
log.warn("EXCEL导入数据转换失败!", e);
throw new CheckedExcelException(StrFormatter.format(ExcelConstants.CONVERT_FAIL_MSG + GlobalExceptionManager.getExceptionMsg(e), entry.getKey()));
}
}
return convertObject;
}
/**
* 初始化SAX读取器
*
* @param targetSheetIndex 读取的sheetIndex下标
* @param dataConsumer 数据消费者(暴露给外部使用)
* @param finalDataConsumer 最终结果集消费者(内部使用)
* @return
*/
Excel07SaxReader initSaxReader(int targetSheetIndex, ExBiConsumer> dataConsumer, BiConsumer> finalDataConsumer) {
HashMap colIndex2Title = new HashMap<>();
/*返回一个Sax读取器*/
return new Excel07SaxReader(new RowHandler() {
@Override
public void doAfterAllAnalysed() {
/*sheet读取结束时*/
}
@Override
public void handle(int sheetIndex, long rowIndex, List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy