From 6c8fe25a4d727e10e3cbf8b4de8f6bb623558a59 Mon Sep 17 00:00:00 2001 From: wangmeng Date: Sat, 22 Mar 2025 17:30:02 +0800 Subject: [PATCH 1/3] enhancement:validate when import - Added ValidateReadListener to record validation error messages. - Introduced ValidateError and ValidateErrorHolder to store error messages. - Added FileErrorHandler and TextErrorHandler to handle error messages. - Updated ExcelReaderBuilder to include validation-related methods. - Added test cases to verify the validation feature. --- .../idev/excel/annotation/ExcelProperty.java | 6 + .../read/builder/ExcelReaderBuilder.java | 50 +++++- .../read/listener/ValidateReadListener.java | 149 ++++++++++++++++++ .../excel/read/metadata/ValidateError.java | 52 ++++++ .../metadata/holder/ValidateErrorHolder.java | 44 ++++++ .../read/processor/FileErrorHandler.java | 109 +++++++++++++ .../read/processor/TextErrorHandler.java | 33 ++++ .../read/processor/ValidateErrorHandler.java | 27 ++++ .../java/cn/idev/excel/util/FileUtils.java | 19 +++ .../test/core/validate/ValidateDemoData.java | 21 +++ .../test/core/validate/ValidateTest.java | 118 ++++++++++++++ .../test/resources/validate/checkRead.xlsx | Bin 0 -> 10083 bytes .../test/resources/validate/checkRead2.xlsx | Bin 0 -> 10089 bytes 13 files changed, 620 insertions(+), 8 deletions(-) create mode 100644 fastexcel-core/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java create mode 100644 fastexcel-core/src/main/java/cn/idev/excel/read/metadata/ValidateError.java create mode 100644 fastexcel-core/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java create mode 100644 fastexcel-core/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java create mode 100644 fastexcel-core/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java create mode 100644 fastexcel-core/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java create mode 100644 fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateDemoData.java create mode 100644 fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateTest.java create mode 100644 fastexcel-test/src/test/resources/validate/checkRead.xlsx create mode 100644 fastexcel-test/src/test/resources/validate/checkRead2.xlsx diff --git a/fastexcel-core/src/main/java/cn/idev/excel/annotation/ExcelProperty.java b/fastexcel-core/src/main/java/cn/idev/excel/annotation/ExcelProperty.java index 78688b7b4..a60807f2c 100644 --- a/fastexcel-core/src/main/java/cn/idev/excel/annotation/ExcelProperty.java +++ b/fastexcel-core/src/main/java/cn/idev/excel/annotation/ExcelProperty.java @@ -66,4 +66,10 @@ */ @Deprecated String format() default ""; + + /** + * use with {@link .ValidateReadListener} to verify whether a field is empty + * @return whether the field can be null + */ + boolean notNull() default false; } diff --git a/fastexcel-core/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java b/fastexcel-core/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java index 60eed57c2..25c3ec56b 100644 --- a/fastexcel-core/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java +++ b/fastexcel-core/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java @@ -1,13 +1,5 @@ package cn.idev.excel.read.builder; -import java.io.File; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.HashSet; -import java.util.List; - -import javax.xml.parsers.SAXParserFactory; - import cn.idev.excel.ExcelReader; import cn.idev.excel.cache.ReadCache; import cn.idev.excel.cache.selector.ReadCacheSelector; @@ -18,8 +10,20 @@ import cn.idev.excel.event.AnalysisEventListener; import cn.idev.excel.event.SyncReadListener; import cn.idev.excel.read.listener.ModelBuildEventListener; +import cn.idev.excel.read.listener.ValidateReadListener; import cn.idev.excel.read.metadata.ReadWorkbook; +import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; +import cn.idev.excel.read.processor.TextErrorHandler; +import cn.idev.excel.read.processor.ValidateErrorHandler; import cn.idev.excel.support.ExcelTypeEnum; +import lombok.Getter; + +import javax.xml.parsers.SAXParserFactory; +import java.io.File; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.HashSet; +import java.util.List; /** * Build ExcelReader @@ -31,6 +35,10 @@ public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder errorHandler; + @Getter + private ValidateErrorHolder errorHolder; public ExcelReaderBuilder() { this.readWorkbook = new ReadWorkbook(); @@ -268,4 +276,30 @@ public ExcelReaderSheetBuilder sheet(Integer sheetNo, String sheetName) { protected ReadWorkbook parameter() { return readWorkbook; } + + + public ExcelReaderBuilder setErrorHandler(ValidateErrorHandler validateErrorHandler) { + this.errorHandler = validateErrorHandler; + return this; + } + + + /** + * enable validate, + * Note: The default {@link TextErrorHandler} is used here. + * If a replacement is needed, call {@link ExcelReaderBuilder#setErrorHandler} after this method. + * + * @return + */ + public ExcelReaderBuilder validate() { + ValidateReadListener validateReadListener = new ValidateReadListener<>(); + registerReadListener(validateReadListener); + errorHolder = validateReadListener; + setErrorHandler(TextErrorHandler.INSTANCE); + return this; + } + + public T handleError() { + return (T) getErrorHandler().handleError(getErrorHolder()); + } } diff --git a/fastexcel-core/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java b/fastexcel-core/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java new file mode 100644 index 000000000..2630fc461 --- /dev/null +++ b/fastexcel-core/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java @@ -0,0 +1,149 @@ +package cn.idev.excel.read.listener; + + +import cn.idev.excel.annotation.ExcelProperty; +import cn.idev.excel.context.AnalysisContext; +import cn.idev.excel.exception.ExcelDataConvertException; +import cn.idev.excel.metadata.Head; +import cn.idev.excel.metadata.data.ReadCellData; +import cn.idev.excel.read.metadata.ValidateError; +import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; +import cn.idev.excel.read.metadata.property.ExcelReadHeadProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.*; + +/** + * validate read listener + * + * @author wangmeng + */ +public class ValidateReadListener implements ReadListener, ValidateErrorHolder { + + private static final Logger LOGGER = LoggerFactory.getLogger(ValidateReadListener.class); + + private boolean existValidate = true; + + private final Map fieldMap = new HashMap<>(); + + private final Map> errorMap = new TreeMap<>(); + + + private final static String CHECK_EMPTY_TEXT = "%s cannot be null or empty"; + private final static String CONVERSION_FAIL_TEXT = "the '%s' field type conversion failed, please enter the correct content"; + + + private File sourceFile = null; + private Integer sheetNo; + + + /** + * Record {@link ExcelDataConvertException} + * + * @param exception + * @param context + * @throws Exception + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException convertException = ((ExcelDataConvertException) exception); + Field field = convertException.getExcelContentProperty().getField(); + String headName = fieldMap.get(field); + ValidateError error = new ValidateError(context.readRowHolder().getRowIndex(), headName, String.format(CONVERSION_FAIL_TEXT, headName)); + // mark conversion failure + error.setConvertError(true); + addError(error); + } + } + + + /** + * Initialize all fields that require validation + * + * @param headMap + * @param context + */ + @Override + public void invokeHead(Map> headMap, AnalysisContext context) { + ExcelReadHeadProperty excelReadHeadProperty = context.currentReadHolder().excelReadHeadProperty(); + for (Head head : excelReadHeadProperty.getHeadMap().values()) { + Field field = head.getField(); + String headName = String.join("-", head.getHeadNameList()); + field.setAccessible(true); + fieldMap.put(field, headName); + + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + if (excelProperty != null && excelProperty.notNull()) { + + } + } + if (fieldMap.isEmpty()) { + existValidate = false; + } + if (sourceFile == null) { + sourceFile = context.readWorkbookHolder().getFile(); + } + sheetNo = context.readSheetHolder().getSheetNo(); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (existValidate) { + checkNotNull(data, context); + } + } + + + private void checkNotNull(T data, AnalysisContext context) { + Integer rowIndex = context.readRowHolder().getRowIndex(); + fieldMap.forEach((field, headName) -> { + try { + Object attribute = field.get(data); + if (attribute == null || + (field.getType().equals(String.class) && ((String) attribute).isEmpty())) { + addError(rowIndex, String.format(CHECK_EMPTY_TEXT, headName)); + } + } catch (IllegalAccessException e) { + LOGGER.warn("failed to retrieve field properties through reflection"); + } + }); + } + + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + + @Override + public Map> getError() { + return errorMap; + } + + @Override + public void addError(Integer rowNum, String message) { + ValidateError error = new ValidateError(rowNum, message); + errorMap.computeIfAbsent(rowNum, key -> new ArrayList<>()); + errorMap.get(rowNum).add(error); + } + + + public void addError(ValidateError error) { + errorMap.computeIfAbsent(error.getRowNum(), key -> new ArrayList<>()); + errorMap.get(error.getRowNum()).add(error); + } + + + @Override + public File getSourceFile() { + return sourceFile; + } + + @Override + public Integer getSheetNo() { + return sheetNo; + } +} diff --git a/fastexcel-core/src/main/java/cn/idev/excel/read/metadata/ValidateError.java b/fastexcel-core/src/main/java/cn/idev/excel/read/metadata/ValidateError.java new file mode 100644 index 000000000..27a720390 --- /dev/null +++ b/fastexcel-core/src/main/java/cn/idev/excel/read/metadata/ValidateError.java @@ -0,0 +1,52 @@ +package cn.idev.excel.read.metadata; + +import cn.idev.excel.exception.ExcelDataConvertException; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * validation error message + * + * @author wangmeng + */ +@Getter +@Setter +@EqualsAndHashCode +@NoArgsConstructor +public class ValidateError { + + /** + * rowNum + */ + private Integer rowNum; + + /** + * headName + */ + private String headName; + + /** + * message + */ + private String message; + + /** + * Record whether it was caused by {@link ExcelDataConvertException} + */ + private boolean convertError = false; + + + public ValidateError(Integer rowNum, String headName, String message) { + this.rowNum = rowNum; + this.headName = headName; + this.message = message; + } + + + public ValidateError(Integer rowNum, String message) { + this.rowNum = rowNum; + this.message = message; + } +} diff --git a/fastexcel-core/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java b/fastexcel-core/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java new file mode 100644 index 000000000..70df9570b --- /dev/null +++ b/fastexcel-core/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java @@ -0,0 +1,44 @@ +package cn.idev.excel.read.metadata.holder; + +import cn.idev.excel.read.metadata.ValidateError; + +import java.io.File; +import java.util.List; +import java.util.Map; + +/** + * validate read listener + * + * @author wangmeng + */ +public interface ValidateErrorHolder { + + /** + * get a map of error messages + * + * @return {@link List }<{@link ValidateError }> + */ + Map> getError(); + + /** + * add an error message + * + * @param rowNum rowNum, + * @param message error message + */ + void addError(Integer rowNum, String message); + + + /** + * get the source file for reading + * + * @return file for reading + */ + File getSourceFile(); + + /** + * get sheetNo + * @return sheetNo + */ + Integer getSheetNo(); +} diff --git a/fastexcel-core/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java b/fastexcel-core/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java new file mode 100644 index 000000000..2e44bd60a --- /dev/null +++ b/fastexcel-core/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java @@ -0,0 +1,109 @@ +package cn.idev.excel.read.processor; + +import cn.idev.excel.read.metadata.ValidateError; +import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; +import cn.idev.excel.util.FileUtils; +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.usermodel.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * handle the error message as file + * + * @author wangmeng + */ +public class FileErrorHandler implements ValidateErrorHandler { + + private final static Logger LOGGER = LoggerFactory.getLogger(FileErrorHandler.class); + + private final static String COLUMN_NAME = "Error message"; + + public final static FileErrorHandler INSTANCE = new FileErrorHandler(); + + @Override + public File handleError(ValidateErrorHolder errorHolder) { + File sourceFile = errorHolder.getSourceFile(); + try { + File tempFile = FileUtils.createErrorTempleFile(sourceFile); + fillInErrorData(tempFile, errorHolder); + return tempFile; + } catch (IOException e) { + LOGGER.warn("create error temp file fail", e); + } + return null; + } + + + /** + * fill error data into the Excel file + * + * @param tempFile + * @param errorHolder + * @throws IOException + */ + public void fillInErrorData(File tempFile, ValidateErrorHolder errorHolder) throws IOException { + Map> errorMap = errorHolder.getError(); + + Workbook workbook = null; + // open the original Excel file and add error messages + try (FileInputStream inputStream = new FileInputStream(tempFile)) { + workbook = new XSSFWorkbook(inputStream); + Sheet sheet = workbook.getSheetAt(errorHolder.getSheetNo()); + + // add error column headers + Row headerRow = sheet.getRow(0); + short lastCellNum = headerRow.getLastCellNum(); + // check if the error column already exists + Cell lastValidCell = headerRow.getCell(lastCellNum - 1); + if (lastValidCell != null) { + if (!COLUMN_NAME.equals(lastValidCell.getStringCellValue())) { + Cell errorHeaderCell = headerRow.createCell(lastCellNum); + errorHeaderCell.setCellValue(COLUMN_NAME); + errorMap.forEach((rowNum, list) -> { + Row row = sheet.getRow(rowNum); + if (row != null) { + Cell errorCell = row.createCell(lastCellNum); + errorCell.setCellValue(mergeText(list)); + } + }); + } else { + int lastRowNum = sheet.getLastRowNum(); + for (int rowNum = 1; rowNum <= lastRowNum; rowNum++) { + Row row = sheet.getRow(rowNum); + String setErrorMsg = mergeText(errorMap.get(rowNum)); + // if there is no error information to set, the old error information should be cleared + Cell errorCell = row.getCell(lastCellNum - 1); + if (setErrorMsg == null) { + if (errorCell != null) { + errorCell.setCellValue((String) null); + } + } else { + if (errorCell == null) { + errorCell = row.createCell(lastCellNum - 1); + } + errorCell.setCellValue(setErrorMsg); + } + } + } + } + } + + try (FileOutputStream outputStream = new FileOutputStream(tempFile)) { + // write it back + workbook.write(outputStream); + workbook.close(); + } + } + +} diff --git a/fastexcel-core/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java b/fastexcel-core/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java new file mode 100644 index 000000000..7e0891b65 --- /dev/null +++ b/fastexcel-core/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java @@ -0,0 +1,33 @@ +package cn.idev.excel.read.processor; + +import cn.idev.excel.read.metadata.ValidateError; +import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; + +import java.util.List; +import java.util.Map; + +/** + * handle the error message as text + * + * @author wangmeng + */ +public class TextErrorHandler implements ValidateErrorHandler { + + private final static String ERROR_STRING = "error message:"; + private final static String LINE_ERROR_STRING = " Line %s: %s"; + + public final static TextErrorHandler INSTANCE = new TextErrorHandler(); + + @Override + public String handleError(ValidateErrorHolder errorHolder) { + Map> errorMap = errorHolder.getError(); + if (errorMap.isEmpty()) { + return null; + } + StringBuilder sb = new StringBuilder(ERROR_STRING); + errorMap.forEach((index, errorList) -> { + sb.append(String.format(LINE_ERROR_STRING, index, mergeText(errorList))); + }); + return sb.toString(); + } +} diff --git a/fastexcel-core/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java b/fastexcel-core/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java new file mode 100644 index 000000000..156ff5b37 --- /dev/null +++ b/fastexcel-core/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java @@ -0,0 +1,27 @@ +package cn.idev.excel.read.processor; + +import cn.idev.excel.read.metadata.ValidateError; +import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Handle error messages + * the source of the error is + * {@link cn.idev.excel.read.metadata.holder.ValidateErrorHolder} + * + * @author wangmeng + */ +public interface ValidateErrorHandler { + + + T handleError(ValidateErrorHolder errorHolder); + + + default String mergeText(List list) { + return list.stream().map(each->each.getMessage() + ";").collect(Collectors.joining("")); + } + + +} diff --git a/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java b/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java index ea5ea7ecc..692d225de 100644 --- a/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java +++ b/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Files; import java.util.UUID; import cn.idev.excel.exception.ExcelAnalysisException; @@ -33,6 +34,7 @@ public class FileUtils { public static final String POI_FILES = "poifiles"; public static final String EX_CACHE = "excache"; + public static final String ERROR_FILES = "errorfiles"; /** * If a server has multiple projects in use at the same time, a directory with the same name will be created under * the temporary directory, but each project is run by a different user, so there is a permission problem, so each @@ -48,6 +50,10 @@ public class FileUtils { * Used to store easy excel temporary files. */ private static String cachePath = tempFilePrefix + EX_CACHE + File.separator; + /** + * Used to store error temporary files + */ + private static String errorFilePath = tempFilePrefix + ERROR_FILES + File.separator; private static final int WRITE_BUFF_SIZE = 8192; @@ -61,6 +67,9 @@ private FileUtils() {} // Initialize the cache directory File cacheFile = new File(cachePath); createDirectory(cacheFile); + // Initialize the error file directory + File errorFile = new File(errorFilePath); + createDirectory(errorFile); } /** @@ -199,6 +208,16 @@ public static void delete(File file) { } } + /** + * Generate a temporary error file based on the source file + * @param sourceFile sourceFile + */ + public static File createErrorTempleFile(File sourceFile) throws IOException { + File tempFile = new File(errorFilePath, UUID.randomUUID() + ".xlsx"); + writeToFile(tempFile, Files.newInputStream(sourceFile.toPath())); + return tempFile; + } + public static String getTempFilePrefix() { return tempFilePrefix; } diff --git a/fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateDemoData.java b/fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateDemoData.java new file mode 100644 index 000000000..abc528e5e --- /dev/null +++ b/fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateDemoData.java @@ -0,0 +1,21 @@ +package cn.idev.excel.test.core.validate; + +import cn.idev.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author wangmeng + * @since 2025/3/22 + */ +@Data +public class ValidateDemoData { + + @ExcelProperty(value = "订单号", notNull = true) + private String orderNo; + @ExcelProperty(value = "用户名", notNull = true) + private String username; + @ExcelProperty(value = "金额") + private BigDecimal amount; +} diff --git a/fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateTest.java b/fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateTest.java new file mode 100644 index 000000000..3599faeb1 --- /dev/null +++ b/fastexcel-test/src/test/java/cn/idev/excel/test/core/validate/ValidateTest.java @@ -0,0 +1,118 @@ +package cn.idev.excel.test.core.validate; + +import cn.idev.excel.FastExcel; +import cn.idev.excel.exception.ExcelDataConvertException; +import cn.idev.excel.read.builder.ExcelReaderBuilder; +import cn.idev.excel.read.listener.PageReadListener; +import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; +import cn.idev.excel.read.processor.FileErrorHandler; +import cn.idev.excel.test.util.TestFileUtil; +import com.alibaba.fastjson2.JSON; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.List; + +/** + * Test cases for reading validation + * + * @author wangmeng + */ +@Slf4j +public class ValidateTest { + + + @Test + public void test() { + // 不存在转换失败情况 + String fileName = TestFileUtil.getPath() + "validate" + File.separator + "checkRead" + ".xlsx"; + testCheckRead(fileName); + testCheckOutFile(fileName); + existConvertException(fileName); + // 存在转换失败 + String fileName2 = TestFileUtil.getPath() + "validate" + File.separator + "checkRead2" + ".xlsx"; + existConvertException(fileName2); + existConvertException(fileName); + // 手动添加业务校验 + testAddError(fileName); + testAddError(fileName2); + } + + + public void testCheckRead(String fileName) { + ExcelReaderBuilder readerBuilder = FastExcel.read(fileName).head(ValidateDemoData.class); + List list = readerBuilder.registerReadListener(new PageReadListener<>(l -> { + System.out.println("读取内容:" + JSON.toJSONString(l)); + })).validate().sheet().doReadSync(); + + ValidateErrorHolder errorHolder = readerBuilder.getErrorHolder(); + System.out.println(JSON.toJSONString(errorHolder)); + String errorText = readerBuilder.handleError(); + System.out.println(errorText); + } + + public void testCheckOutFile(String fileName) { + ExcelReaderBuilder readerBuilder = FastExcel.read(fileName).head(ValidateDemoData.class); + List list = readerBuilder.registerReadListener(new PageReadListener<>(l -> { + System.out.println("读取内容:" + JSON.toJSONString(l)); + })).validate().setErrorHandler(FileErrorHandler.INSTANCE).sheet().doReadSync(); + + ValidateErrorHolder errorHolder = readerBuilder.getErrorHolder(); + System.out.println(JSON.toJSONString(errorHolder)); + File errorFile = readerBuilder.handleError(); + System.out.println("错误信息输出到" + errorFile.getAbsolutePath()); + } + + + public void existConvertException(String fileName) { + ExcelReaderBuilder readerBuilder = FastExcel.read(fileName).head(ValidateDemoData.class); + try { + List list = readerBuilder.registerReadListener(new PageReadListener<>(l -> { + System.out.println("读取内容:" + JSON.toJSONString(l)); + })).validate().setErrorHandler(FileErrorHandler.INSTANCE).sheet().doReadSync(); + } catch (ExcelDataConvertException e) { + log.info("存在类型转换失败异常"); + } + ValidateErrorHolder errorHolder = readerBuilder.getErrorHolder(); + System.out.println(JSON.toJSONString(errorHolder)); + File errorFile = readerBuilder.handleError(); + System.out.println("错误信息输出到" + errorFile.getAbsolutePath()); + } + + + public void testAddError(String fileName) { + ExcelReaderBuilder readerBuilder = FastExcel.read(fileName).head(ValidateDemoData.class); + List list = null; + try { + list = readerBuilder.registerReadListener(new PageReadListener<>(l -> { + System.out.println("读取内容:" + JSON.toJSONString(l)); + })).validate().setErrorHandler(FileErrorHandler.INSTANCE).sheet().doReadSync(); + } catch (ExcelDataConvertException e) { + log.info("存在类型转换失败异常"); + } + ValidateErrorHolder errorHolder = readerBuilder.getErrorHolder(); + System.out.println(JSON.toJSONString(errorHolder)); + + // 手动业务校验 + if(CollectionUtils.isEmpty(list)){ + return; + } + + for (int i = 0; i < list.size(); i++) { + if(true){ + errorHolder.addError(i+1,"订单号已存在"); + } + if(true){ + errorHolder.addError(i+1,"用户不存在"); + } + } + + + File errorFile = readerBuilder.handleError(); + System.out.println("错误信息输出到" + errorFile.getAbsolutePath()); + } + + +} diff --git a/fastexcel-test/src/test/resources/validate/checkRead.xlsx b/fastexcel-test/src/test/resources/validate/checkRead.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6040bfec7fe4985df44f52e4d95b44fdbd823ac7 GIT binary patch literal 10083 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 I`o#VJ0D`l3(*OVf literal 0 HcmV?d00001 diff --git a/fastexcel-test/src/test/resources/validate/checkRead2.xlsx b/fastexcel-test/src/test/resources/validate/checkRead2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a9929c5aa350b1da293cf5300bc9389d932167a5 GIT binary patch literal 10089 zcmeHtWmH|s(l)_^ySoPn?(Xhx!QI{6A-Dy1*Wd(qcMpW%?j%5f0Plg!oy>6O-gWDk)SxLR3e#EnUS(4z!h`=27zRP9HHCZwS7_eH9GY>rOh zw9+Me{b?cRQvFL4f+vV-d!&D~o-wc!WwV`2oCBLDIZ0Z@VK_6wBwO0Isje8tk4vci zG!EXiZ1^}1!TFXslqQ6`*nB+kcOIX)*x>zO2;QTjIkXd9C=$w5WvjR%SYc;O2WiN2 z1sB*FnK7kvc&hmYAx_dtf-Ub~T-_OW-!^@~Hw@E=8 z3m2z3Zt=5*U}9K%$~#~4fr-S|6t%&Hu%`BYIc}lf2GUpF1U9hjMnZ|GhhJJz<8r)n z%O~K~&RSi?xo!rU59PLM-sj2e14MiuwF&z(e>$eOl4#n0#2i4@W5`Ij=Nju-LhL_J`lt(@wEx zYOuntv%~M%hCe?(+9=hTqg8gHf}@ZHE7Ag~tsm#r$!yooQfyT`7+0k?Fgcn2hSa;y z;gS^Hc#ZO?f>RdF1H|u21B07ulbH77s5Lp4i%9+`z85}^2*xZ~PT-`u%j5oCQw{;^ z<|8>7PuM*LrI^&FK`PEMLZff%MB5|bh0Wjb$A`0opa9^H2*4ltZ}>YoINDe}X`moh zTC#@^A^6n)k?_c?R>#^>A}&rA0UoWqO=8hY7#myy4bbASeM^G4Q#H)% z8ydG{9hllDn8V~@mu9nXx=AQ}R zei69X*jqT58W}mhG)MMgS_Yf|4fTQo0b%?b?K2Dgld2*UR&AE(5C&Gsk9|J={7S;t z0w+|gfv}t}UE1%>m9`~7oxWHLKYdcQ`q@kX!)q_i%f#ozgZJoWMX_KJu{^$6=7vIo zEr4U@Q@P8V#~TB$%UH&c-0`4k=KPdE|8{1Hx`XZmAZwO z_@pxhmL&+Rj%l3x{RevrB>FZGH@x2tAo_!fW!Z<~Du->nKZ2yfOhQ01DHsw&)%+FSJTm3H zxkc8Wj05iV3S4h~-vB50%~TyOh>b$a{8DpAt&Y`?+x+r#m%oaJTPuW zcH6fnSx>y^`wl?j8dQPf>fzb;X~F47>|*SooPxh?TU|!W-r^4~ZB{<^zN=!W!$ zcE2+$a0`XFh70LC&YL=V**5K*q2CzoRhA>m>dvn&bRKwZwlLyyWC==ISlJuKkVWM#tvVk*lz0d zbT%k6TUO)2sHGC()#VrSejg4Bx>{@vUvOm?sd}G@9Jc()VXNY6);?qD6~@PcauH%< zvt616{rhNH#Vo%EMrz`FJzI3dquftz)8UzME5Znq&?YzomX3sF$Fthjn+KB4@K9m2Hq}@3qtsx@0m>4)f1|U((LW>0B`Dn6KLYgeg6IQ@Lm4?4-nw z86KW-v{v>#qsGt7bW_L8c`PMMHa~f?-~iRcBcJU(>EWh?fL0<`%T~E?KB?QzR}k1J z_WjP)GTw7AA>}<~t@b(xQkT6UN#Xcn%m&GX563og7V#tc;$0)NeBoczXx)0}KeL9bf~Vb_aiwJrh5>oMZK|Xl!Pb4&rm(h@Gz| zBx3{4bC&ft2Ldk3%JB^cQ{w3n*b}aXoGoLp^`aysLi}1WO?G^I1u7c~52-;!6bg@E zna4xDGB~+tf!XFVjG3z*-uNBYKVzv>@kyB2`m_*|Sh}bCC}3gue+@= zAj75+bE*3xZKH%;ogVM6E3>&VH$fo?vckD%Ar0Qtwq@Yb2kMc~)W8&-S&h2-leAt8 zjfdtjPNq#}*rUujBMD8@iOB<-pJsmVz7HCQ1M4e6G1nDylQrw5>YS>}=Xw9hR30y# zXbF=4IyB?*90U^_<@IZPEWLc6_3?*9+`13Y@}KzU;|>pWXg)wk6dG}pXTgMvQze=g zILqxV08uX3Ww;m3m!RG<0l|i>6;}66ebTI|OJ$!2P7#eh8MprQ#px{RLDGW7Wn?U% z_-KuJaIdO-{cz5>Wn+VRaIMVZhon4}xeCrbmf=}FvuBZpnKCDwc7VRb^gb3x_;9@p zvnYBDeO`#RYn$Q$UY)}aBrr>g;(|hqS|#_er0ly0m-R9Mc@lA~LAT%mQ^-0iLJ9D6 zP*Fo9NoI(pp21t|;9z|#F=_NrLh=;LKzw6JD7}))xo@Z1+&);X?hji(*K5Cp@MiM5 zJ3gF2F_*!iAHC6_;AYma8oq#laC^|K$y1O_2RIW zoVNYvR-+BR#~K63*0GANK$Fo;eV<(&qSNc5hy^P;3+3b7=BBsbTzXEBgI;bO_OiYLQ*z?rdH6n0a zj;#ok#4n9g2ULoCQfksWk8t~hAn+V3RXpK`(v`fxu`fO$ z=3T_m*v(|WQ(&N!ES(X*Nnp^~(3h>Xs>JVylRQ7ocniPv3fqep@??mH(qn%%o>7U2 z8x1**WooF#4}Bwt0!A)%yEZUdfp7`u#<$<^xJtMvetjiki_KAFH62HAFcRTm?*_{l z($U6_OI+RpC)9(57_Tr=6Bolity+9+PR=s_jPRr^hLMP96C!3jXW1d$fgg=XQs$C7&?n4q0AQLF}kV1 zv^vfa~^u3@NLd7jnCy)*uT~^-yzR zoH{NN5j{MGIM#aQP^>tNG_&$o%FPFvDK^kDQ}4HITC+zTa;&7XE3NX@ejjMy&s`%z zri}}kbDMOvzp3;X^QCEXaX^DR_S+COAkjdX+H?t);3=<#tIMhGR>1 ziiCNspU{=qlN1$XibgE>E?HmD2%T)7Np0T0Ok1_C$|BQ_s}KRQi9L|28)Q2)72yP4 z^vwQ^50|`^ibwrfV|lvPrRpg5dQhv=jxv|8!(!=a;l|g+jqYRmQgFrIGF0$8yPA(+M8LMI6Ung-c58# z0M3#9=N?@yYCG1f6>>t(jiGDEdmz+9i{-{92F3~p$a@9F*`l=EZWl}B;SDx=LPCS* zclRkh$v2cL=3%fQLTF^0FenO{;e620AJBJ02C~(-P}?N}(N1FYPT)j>)s=iCEpt#x zWb1ZXd-vSZ&GXx}3dr2|O=>5#Soff55J^?sQ;isLy$Iyo%*Clk`RY-uHM#DV$8Bvz zzML4$ROqw}R7`C|Jany|U0yugd_2ya@A=r_^VQ~SuscTz9_;bbF00_C&*c646YRf3 zkWXupxdoU$C*X_*{|kbr^PIkojm7iMN%0-vXoljIRrjcSgPRUIjU=QHD^Mph!Sldv72yTzC8r={#iu_z7jOb!mxqn zqK*|9V~$6MS5;X6M{%Y=xcj zdoP8j?P?s3;IYt!QM~j8z27Csui8EHRFmf-Di0IXmKiNfWIG-=3L3fb3NFyMst^aq z>BFa_b>QPR!GP5q?0a-m)0R!}4#8+FC+XKD1$9#Rs5OO%h)q%GYM`8{9#&ZIufjuq zxE#sqo1nM`*lmynRAaLRu(e~s{}g7ps9Nbeo|b(`SM{umxarHJ%A_nYvJNgO7i-yg zzpx=A=8!61t9k~Rr#`|`|9LCnILHtHt^aPBEB$G7R@K5co3!nPZ>U>YAfz81T$^^s;=gr7zuZ#~U&ee|18lC| zO9KJH{_#yXx>*`Me++Y4R?*99s1H%SJ|DHZAbO=XKD3U>C~%}y*G>DYn8(HdDW~+N zRNEe@50n`5i3M3>swt5uWq;HNGg2+^%m$$jtw^%Eo?tTDLH6-;IIZ`Zkgi0Q9eU45 zJjNC^!9Kyh`)OC}Zs}{A_mV>*r}LzXXH}*7vaoV>Tf?edYhLs1vF5yrvhuCo$YGt< zYVF}c%8F_gYx~cF6>ry_CDv#wP9?seg{ravJ=YpVitoz<&Q)`(SF)Dy?fbXLJ5c~AHa}N4W zVj166?;UgeJE*&zF}R~yr6Bf|@0>uJ4HwMYOAA%+sJ^OvC0Jfv?#^nz9q)u+UDSWv zLtJgDC=OagnJ<$)FcNsY-=JUaG%jrKRw-&X00chp7uC?~L8@Zgo?9{(X#5O;PpoV~%~%b~oLWSnyK&A%p~^WeD{Q zw|1FHEpae=Sx5Y#r59-7q*BxL>Y~D^l#~i%rmy3Evx)tRyJ4#mW=!ZNLZ+!Pzs0_Yl`E0Z8ZPY3m@=Bo z)zvm#vw~bcHTjk?*`FC@)bz_+HYY|kGqqslH}PvU=8*ZH(9Q!fn34vNQAP%{o$_jQ zwDt(HHgkl1&@iVlZ!|MpRLx&whWvmT(8Vfv%VNbCF_${|8jSnvd(y4kvWe}3i z&aA!}e-X4-atd2znv@u9z^JmWtN}XNKn|`enx|auv8D+*o#MGJo@}s|A1>?eUS76S z;eK6_A@bf`YaO}8mtyRtIHI%7T z%jQzeOv@T|fbW>|G^h@N@|rA5W$tWzZzM{T-kLG5%qG19Cc2}tug$My9UFYmn2tEA zA{}#_uKhWsrR|U!dtaZA`B_IYl}hr&O@6Aloc%Y^ccRG)QARCp9Sa+gtA#jYL!Y;1 z+EXY%Xjt>9&woU&9w(S);-%OsxW5O$l}o&tl7LqC)N8?Nsa%0w=VGvpiW+*H<%I)FgN~2BEeRgEpccLXn-Q< zwLqnuzBbetdm}}Vbp}-e+vbfG7lx5HC;Sd6!MGV|H-#Q&5rusJ`cR%UU&`v&0EWul z#%tY#n`7?e4}c4R)B}Fp6>t%Gddmp6j4d}uSjjFN#$dhm2Vv-k{v{9DS5dwM_3;ucN2z(3UfOvVGZNMLi~DdRxdD#qLwcYAHCV`9KN=1?9?g} zalVNI<}Fia{wRXpo%Q)$HS@ISCz7@ ztzhm)F2vyVqO1to_9joq^MiYrf%uF3TL(9H+3ozXDc(nWw+C&@7!-XPpanUS8!X=Y zZ)Xdqk=`ymw`*0^IBz1wqPTN8{2afp-)xI^M3e4aVv-QSKK>XQ0J3(x4l{+t+Z@=D zQ1GU6fWjG07NgZC2$(Jx7U(P#6WaJW@kLwI&O+FuWf=|2Vz&-Rvofrs2KS{rO&&&1xM{ri*-^VE(<1 zd_zKtxlm;%HGiD2LpxS1Z*T(d_Kmra41ZQ)c5G98gycICG%g-0`53H3A=nIRyQu1G zAt|`#*XYA08zT&g_&#$3bxg`KUN##NGI!jmz=H!u3 z2VWnuZdr+jS{4F?X#s?drz(v9DJ%^OwGw8Z$;rTFmY z=V3ZX{;PY<+|g|lG`f2Dq4$k@ksU){@P5oyw^aCHf0bx2FY~-h`>qZ;=iwSU@YOezwI(mD_PG#I#m zmg}qQ3JrN$79W@tLYp_s>~o_F9>{9dD#g`}iCy>osh?(C*1h!jw=6*)$W~QVry#(y zvT1=VuRd_d?~&WcTl{8+!RBOFd4KA;+m7x3}@jQ_nU-M5o;Bq^)`ywqUOi zXww%)wfZ~B`}5fhI=9Q8dAh2t_=}ad&4IWn*>;1r99-z%1qSSJB`nd9#J=-Xm}Cgy zd=qarwXY<{m&M5}T*S_6Kpeo*W-Vtud?C`Gg(oM?)%TS$)T0I5jxDJ5#>S@faD0tB zB~NgIk!njRHp9s>1~nqUGjFj2;ZhhJoPEOHiD%^0MIxlU!uTz$uvSpAV)&PBtqwct zlmRUn{BY9ju^YabnceQL*eT7r5iyQH(%i#G5{7}^tt2-dW*ss6i??Mi|2eVtN9gjO z;1qTZb-DwXb$&bkcm5NO<&wk@1#*dLGR-X$|pRlJ*9D%)PV2xM^1LL z%)?AktkbgG1T7aRAqsxH3D^iXlObD=ZSRzs!P=WQ$^=JPiAc^TgCRn-?y%ImvZ8>A z2ba$$-uGi4SO3(-FXSvpPTJMYObT58NZcBspJ2}w&mMdk2g5s#KSXd5w5dhJ?mX{6 zx1XUm&7Qn9PPfZERMwGv{~`%s;|50L064+o0+#4gv{zHm#@f-y+EGWz&DO}_-P0+y zK4HYV`zha(cncrfh)OS4Qc4N@o+s(8!ahXPRiIEWycgzhLj-j2K3Gu&<}ir%iQazOOUnEIzKUy|$;X61Zs1U$r2| zqcj}abk`djPPVP2EP&ifpp96{b7TojpxnfwmIz@r3^)%6bl-95EIf(KJumP#r1o@0 zO|`T&+FsNQNrx#IP=;HqbJLa}i2PItsZgw`lFboC(iMW_&4q6yd6>iQnI`{kC7EqN z*U4c=yN6*o{k4t?4)i*I8-y%5lIF~m8v+!xZ+4lZsE3CVT%YzGWEm8VH9>eL0YtM> z=Vs#qhcAT#@DHQ=qnRaji$(9H1ou*5v+=cow*pIErDm&_m9fno6kjGqAG`g2&J7&< z+^wD4;d_I~NxlL`c@C=lDouH*C4i!UUI7sRt~iAMsIy-J{PLZvh%e&;9-tw*NNhr{axY?McJozcl>B z{AVf0-$(wknB$4}m)08ojrVtH$IIcr%-H^xLJslg@c$UW^X)lb|G!H?2dqN?_ Date: Sat, 22 Mar 2025 18:00:43 +0800 Subject: [PATCH 2/3] fix: Fix issue where error files were not deleted Added errorFile.deleteOnExit() after creating the error file directory. Ensured that the generated error files are deleted when the program exits --- fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java b/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java index 692d225de..c03017948 100644 --- a/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java +++ b/fastexcel-core/src/main/java/cn/idev/excel/util/FileUtils.java @@ -70,6 +70,7 @@ private FileUtils() {} // Initialize the error file directory File errorFile = new File(errorFilePath); createDirectory(errorFile); + errorFile.deleteOnExit(); } /** From b6ef0a7658bac33431ea47cd1c5c12bf1b5975ff Mon Sep 17 00:00:00 2001 From: wangmeng Date: Mon, 11 Aug 2025 14:29:14 +0800 Subject: [PATCH 3/3] refactor(fastexcel): Adjust the code according to Spotless --- .../read/builder/ExcelReaderBuilder.java | 7 ++-- .../read/listener/ValidateReadListener.java | 36 +++++++------------ .../excel/read/metadata/ValidateError.java | 2 -- .../metadata/holder/ValidateErrorHolder.java | 2 -- .../read/processor/FileErrorHandler.java | 22 +++++------- .../read/processor/TextErrorHandler.java | 8 ++--- .../read/processor/ValidateErrorHandler.java | 8 +---- .../java/cn/idev/excel/util/FileUtils.java | 3 -- 8 files changed, 27 insertions(+), 61 deletions(-) diff --git a/fastexcel/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java b/fastexcel/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java index c345d5e6c..e81c2356e 100644 --- a/fastexcel/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java +++ b/fastexcel/src/main/java/cn/idev/excel/read/builder/ExcelReaderBuilder.java @@ -16,15 +16,13 @@ import cn.idev.excel.read.processor.TextErrorHandler; import cn.idev.excel.read.processor.ValidateErrorHandler; import cn.idev.excel.support.ExcelTypeEnum; -import lombok.Getter; - -import javax.xml.parsers.SAXParserFactory; import java.io.File; import java.io.InputStream; import java.nio.charset.Charset; import java.util.HashSet; import java.util.List; import javax.xml.parsers.SAXParserFactory; +import lombok.Getter; /** * Build ExcelReader @@ -39,6 +37,7 @@ public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder errorHandler; + @Getter private ValidateErrorHolder errorHolder; @@ -295,13 +294,11 @@ public ExcelReaderBuilder ignoreHiddenSheet(Boolean ignoreHiddenSheet) { return this; } - public ExcelReaderBuilder setErrorHandler(ValidateErrorHandler validateErrorHandler) { this.errorHandler = validateErrorHandler; return this; } - /** * enable validate, * Note: The default {@link TextErrorHandler} is used here. diff --git a/fastexcel/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java b/fastexcel/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java index 2630fc461..5ba73cd2f 100644 --- a/fastexcel/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java +++ b/fastexcel/src/main/java/cn/idev/excel/read/listener/ValidateReadListener.java @@ -1,6 +1,5 @@ package cn.idev.excel.read.listener; - import cn.idev.excel.annotation.ExcelProperty; import cn.idev.excel.context.AnalysisContext; import cn.idev.excel.exception.ExcelDataConvertException; @@ -9,17 +8,15 @@ import cn.idev.excel.read.metadata.ValidateError; import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; import cn.idev.excel.read.metadata.property.ExcelReadHeadProperty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.lang.reflect.Field; import java.util.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * validate read listener * - * @author wangmeng */ public class ValidateReadListener implements ReadListener, ValidateErrorHolder { @@ -31,15 +28,13 @@ public class ValidateReadListener implements ReadListener, ValidateErrorHo private final Map> errorMap = new TreeMap<>(); - - private final static String CHECK_EMPTY_TEXT = "%s cannot be null or empty"; - private final static String CONVERSION_FAIL_TEXT = "the '%s' field type conversion failed, please enter the correct content"; - + private static final String CHECK_EMPTY_TEXT = "%s cannot be null or empty"; + private static final String CONVERSION_FAIL_TEXT = + "the '%s' field type conversion failed, please enter the correct content"; private File sourceFile = null; private Integer sheetNo; - /** * Record {@link ExcelDataConvertException} * @@ -53,14 +48,14 @@ public void onException(Exception exception, AnalysisContext context) throws Exc ExcelDataConvertException convertException = ((ExcelDataConvertException) exception); Field field = convertException.getExcelContentProperty().getField(); String headName = fieldMap.get(field); - ValidateError error = new ValidateError(context.readRowHolder().getRowIndex(), headName, String.format(CONVERSION_FAIL_TEXT, headName)); + ValidateError error = new ValidateError( + context.readRowHolder().getRowIndex(), headName, String.format(CONVERSION_FAIL_TEXT, headName)); // mark conversion failure error.setConvertError(true); addError(error); } } - /** * Initialize all fields that require validation * @@ -69,7 +64,8 @@ public void onException(Exception exception, AnalysisContext context) throws Exc */ @Override public void invokeHead(Map> headMap, AnalysisContext context) { - ExcelReadHeadProperty excelReadHeadProperty = context.currentReadHolder().excelReadHeadProperty(); + ExcelReadHeadProperty excelReadHeadProperty = + context.currentReadHolder().excelReadHeadProperty(); for (Head head : excelReadHeadProperty.getHeadMap().values()) { Field field = head.getField(); String headName = String.join("-", head.getHeadNameList()); @@ -77,9 +73,7 @@ public void invokeHead(Map> headMap, AnalysisContext co fieldMap.put(field, headName); ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); - if (excelProperty != null && excelProperty.notNull()) { - - } + if (excelProperty != null && excelProperty.notNull()) {} } if (fieldMap.isEmpty()) { existValidate = false; @@ -97,14 +91,12 @@ public void invoke(T data, AnalysisContext context) { } } - private void checkNotNull(T data, AnalysisContext context) { Integer rowIndex = context.readRowHolder().getRowIndex(); fieldMap.forEach((field, headName) -> { try { Object attribute = field.get(data); - if (attribute == null || - (field.getType().equals(String.class) && ((String) attribute).isEmpty())) { + if (attribute == null || (field.getType().equals(String.class) && ((String) attribute).isEmpty())) { addError(rowIndex, String.format(CHECK_EMPTY_TEXT, headName)); } } catch (IllegalAccessException e) { @@ -113,10 +105,8 @@ private void checkNotNull(T data, AnalysisContext context) { }); } - @Override - public void doAfterAllAnalysed(AnalysisContext context) { - } + public void doAfterAllAnalysed(AnalysisContext context) {} @Override public Map> getError() { @@ -130,13 +120,11 @@ public void addError(Integer rowNum, String message) { errorMap.get(rowNum).add(error); } - public void addError(ValidateError error) { errorMap.computeIfAbsent(error.getRowNum(), key -> new ArrayList<>()); errorMap.get(error.getRowNum()).add(error); } - @Override public File getSourceFile() { return sourceFile; diff --git a/fastexcel/src/main/java/cn/idev/excel/read/metadata/ValidateError.java b/fastexcel/src/main/java/cn/idev/excel/read/metadata/ValidateError.java index 27a720390..04debd9ba 100644 --- a/fastexcel/src/main/java/cn/idev/excel/read/metadata/ValidateError.java +++ b/fastexcel/src/main/java/cn/idev/excel/read/metadata/ValidateError.java @@ -37,14 +37,12 @@ public class ValidateError { */ private boolean convertError = false; - public ValidateError(Integer rowNum, String headName, String message) { this.rowNum = rowNum; this.headName = headName; this.message = message; } - public ValidateError(Integer rowNum, String message) { this.rowNum = rowNum; this.message = message; diff --git a/fastexcel/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java b/fastexcel/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java index 70df9570b..0754ec5b4 100644 --- a/fastexcel/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java +++ b/fastexcel/src/main/java/cn/idev/excel/read/metadata/holder/ValidateErrorHolder.java @@ -1,7 +1,6 @@ package cn.idev.excel.read.metadata.holder; import cn.idev.excel.read.metadata.ValidateError; - import java.io.File; import java.util.List; import java.util.Map; @@ -28,7 +27,6 @@ public interface ValidateErrorHolder { */ void addError(Integer rowNum, String message); - /** * get the source file for reading * diff --git a/fastexcel/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java b/fastexcel/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java index 2e44bd60a..4acac14ae 100644 --- a/fastexcel/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java +++ b/fastexcel/src/main/java/cn/idev/excel/read/processor/FileErrorHandler.java @@ -3,6 +3,12 @@ import cn.idev.excel.read.metadata.ValidateError; import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; import cn.idev.excel.util.FileUtils; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; @@ -11,25 +17,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.List; -import java.util.Map; - /** * handle the error message as file * - * @author wangmeng */ public class FileErrorHandler implements ValidateErrorHandler { - private final static Logger LOGGER = LoggerFactory.getLogger(FileErrorHandler.class); + private static final Logger LOGGER = LoggerFactory.getLogger(FileErrorHandler.class); - private final static String COLUMN_NAME = "Error message"; + private static final String COLUMN_NAME = "Error message"; - public final static FileErrorHandler INSTANCE = new FileErrorHandler(); + public static final FileErrorHandler INSTANCE = new FileErrorHandler(); @Override public File handleError(ValidateErrorHolder errorHolder) { @@ -44,7 +42,6 @@ public File handleError(ValidateErrorHolder errorHolder) { return null; } - /** * fill error data into the Excel file * @@ -105,5 +102,4 @@ public void fillInErrorData(File tempFile, ValidateErrorHolder errorHolder) thro workbook.close(); } } - } diff --git a/fastexcel/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java b/fastexcel/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java index 7e0891b65..e52c35445 100644 --- a/fastexcel/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java +++ b/fastexcel/src/main/java/cn/idev/excel/read/processor/TextErrorHandler.java @@ -2,21 +2,19 @@ import cn.idev.excel.read.metadata.ValidateError; import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; - import java.util.List; import java.util.Map; /** * handle the error message as text * - * @author wangmeng */ public class TextErrorHandler implements ValidateErrorHandler { - private final static String ERROR_STRING = "error message:"; - private final static String LINE_ERROR_STRING = " Line %s: %s"; + private static final String ERROR_STRING = "error message:"; + private static final String LINE_ERROR_STRING = " Line %s: %s"; - public final static TextErrorHandler INSTANCE = new TextErrorHandler(); + public static final TextErrorHandler INSTANCE = new TextErrorHandler(); @Override public String handleError(ValidateErrorHolder errorHolder) { diff --git a/fastexcel/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java b/fastexcel/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java index 156ff5b37..8b0d5eb3a 100644 --- a/fastexcel/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java +++ b/fastexcel/src/main/java/cn/idev/excel/read/processor/ValidateErrorHandler.java @@ -2,7 +2,6 @@ import cn.idev.excel.read.metadata.ValidateError; import cn.idev.excel.read.metadata.holder.ValidateErrorHolder; - import java.util.List; import java.util.stream.Collectors; @@ -11,17 +10,12 @@ * the source of the error is * {@link cn.idev.excel.read.metadata.holder.ValidateErrorHolder} * - * @author wangmeng */ public interface ValidateErrorHandler { - T handleError(ValidateErrorHolder errorHolder); - default String mergeText(List list) { - return list.stream().map(each->each.getMessage() + ";").collect(Collectors.joining("")); + return list.stream().map(each -> each.getMessage() + ";").collect(Collectors.joining("")); } - - } diff --git a/fastexcel/src/main/java/cn/idev/excel/util/FileUtils.java b/fastexcel/src/main/java/cn/idev/excel/util/FileUtils.java index c3b113875..836ff06d8 100644 --- a/fastexcel/src/main/java/cn/idev/excel/util/FileUtils.java +++ b/fastexcel/src/main/java/cn/idev/excel/util/FileUtils.java @@ -55,7 +55,6 @@ public class FileUtils { */ private static String cachePath = tempFilePrefix + EX_CACHE + File.separator; - /** * Used to store error temporary files */ @@ -215,8 +214,6 @@ public static void delete(File file) { } } - - /** * Generate a temporary error file based on the source file * @param sourceFile sourceFile