From 7c3646a579afec1b4c109d98f0d420c52efe0b39 Mon Sep 17 00:00:00 2001 From: lin feng Date: Wed, 21 Jun 2023 14:05:22 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fill=E8=83=BD=E5=8A=9B=E6=89=A9=E5=B1=95?= =?UTF-8?q?=EF=BC=9A=20=E6=B7=BB=E5=8A=A0=E9=80=9A=E9=81=93=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E6=89=A9=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/excel/ExcelWriter.java | 15 ++ .../alibaba/excel/util/CellVariableUtils.java | 73 ++++++++ .../alibaba/excel/util/PipeFilterUtils.java | 123 +++++++++++++ .../com/alibaba/excel/write/ExcelBuilder.java | 9 + .../alibaba/excel/write/ExcelBuilderImpl.java | 10 ++ .../AbstractExcelWriterParameterBuilder.java | 21 +++ .../builder/ExcelWriterSheetBuilder.java | 13 ++ .../executor/ExcelWriteFillExecutor.java | 144 +++++++++++++-- .../excel/write/handler/BasePipeFilter.java | 82 +++++++++ .../excel/write/handler/PipeDataWrapper.java | 36 ++++ .../excel/write/handler/PipeFilter.java | 41 +++++ .../write/handler/PipeFilterFactory.java | 139 +++++++++++++++ .../filter/AbstractCalculatorFilter.java | 165 ++++++++++++++++++ .../handler/filter/AbstractEchoFilter.java | 52 ++++++ .../handler/filter/AbstractMatchFilter.java | 164 +++++++++++++++++ .../filter/AbstractPriorMatchFilter.java | 35 ++++ .../write/handler/filter/AdditionFilter.java | 15 ++ .../write/handler/filter/ContainsFilter.java | 20 +++ .../handler/filter/DateFormatFilter.java | 56 ++++++ .../write/handler/filter/DivisionFilter.java | 16 ++ .../write/handler/filter/EchoFilter.java | 59 +++++++ .../write/handler/filter/EndsWithFilter.java | 20 +++ .../write/handler/filter/EqualsFilter.java | 20 +++ .../write/handler/filter/ListEchoFilter.java | 64 +++++++ .../write/handler/filter/ListIndexFilter.java | 92 ++++++++++ .../write/handler/filter/ListRangeFilter.java | 99 +++++++++++ .../handler/filter/MultiplicationFilter.java | 16 ++ .../write/handler/filter/PatternFilter.java | 22 +++ .../handler/filter/PriorContainsFilter.java | 21 +++ .../handler/filter/PriorEndsWithFilter.java | 19 ++ .../handler/filter/PriorEqualsFilter.java | 21 +++ .../handler/filter/PriorPatternFilter.java | 21 +++ .../handler/filter/PriorStartsWithFilter.java | 20 +++ .../write/handler/filter/ReplaceFilter.java | 77 ++++++++ .../handler/filter/StartsWithFilter.java | 20 +++ .../write/handler/filter/SubstringFilter.java | 74 ++++++++ .../handler/filter/SubtractionFilter.java | 15 ++ .../write/handler/filter/TrimFilter.java | 51 ++++++ .../write/metadata/WriteBasicParameter.java | 11 +- .../easyexcel/test/demo/fill/FillData.java | 4 +- .../write/handler/PipeFilterFactoryTest.java | 155 ++++++++++++++++ 41 files changed, 2109 insertions(+), 21 deletions(-) create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/util/CellVariableUtils.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/util/PipeFilterUtils.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/BasePipeFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeDataWrapper.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractCalculatorFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractEchoFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractMatchFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractPriorMatchFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AdditionFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ContainsFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DateFormatFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DivisionFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EchoFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EndsWithFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EqualsFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListEchoFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListIndexFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListRangeFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/MultiplicationFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PatternFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorContainsFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEndsWithFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEqualsFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorPatternFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorStartsWithFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ReplaceFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/StartsWithFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubstringFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubtractionFilter.java create mode 100644 easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/TrimFilter.java create mode 100644 easyexcel-test/src/test/java/com/alibaba/excel/write/handler/PipeFilterFactoryTest.java diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/ExcelWriter.java b/easyexcel-core/src/main/java/com/alibaba/excel/ExcelWriter.java index 3c074384..14b15ebc 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/ExcelWriter.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/ExcelWriter.java @@ -2,14 +2,18 @@ package com.alibaba.excel; import java.io.Closeable; import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.function.Supplier; import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.write.ExcelBuilder; import com.alibaba.excel.write.ExcelBuilderImpl; +import com.alibaba.excel.write.executor.ExcelWriteFillExecutor; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteTable; import com.alibaba.excel.write.metadata.WriteWorkbook; +import com.alibaba.excel.write.metadata.fill.AnalysisCell; import com.alibaba.excel.write.metadata.fill.FillConfig; import lombok.extern.slf4j.Slf4j; @@ -87,6 +91,7 @@ public class ExcelWriter implements Closeable { return this; } + /** * Fill value to a sheet * @@ -135,6 +140,16 @@ public class ExcelWriter implements Closeable { return this; } + /** + * Set fields for automatic filling errors + * @param errorField error filed + * @return this + */ + public ExcelWriter autoFillError(String errorField) { + excelBuilder.setAutoErrorField(errorField); + return this; + } + /** * Close IO */ diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/util/CellVariableUtils.java b/easyexcel-core/src/main/java/com/alibaba/excel/util/CellVariableUtils.java new file mode 100644 index 00000000..eabd86d4 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/util/CellVariableUtils.java @@ -0,0 +1,73 @@ +package com.alibaba.excel.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * Description: + * 单元格变量工具 + * + * @author linfeng + * @version 1.0.0 + * @since 2023/6/7 10:38 + */ +public class CellVariableUtils { + + private static final String FILL_PREFIX = "{"; + private static final String FILL_SUFFIX = "}"; + private static final char IGNORE_CHAR = '\\'; + private static final String COLLECTION_PREFIX = "."; + + /** + * 根据cell值获取单元格变量 + * @author linfeng + * @param cellValue 单元格值 + * @return 变量集合 + */ + public static List getVariable(String cellValue) { + + List varList = new ArrayList<>(); + int startIndex = 0; + int length = cellValue.length(); + out: + while (startIndex < length) { + int prefixIndex = cellValue.indexOf(FILL_PREFIX, startIndex); + if (prefixIndex < 0) { + break; + } + if (prefixIndex != 0) { + char prefixPrefixChar = cellValue.charAt(prefixIndex - 1); + if (prefixPrefixChar == IGNORE_CHAR) { + startIndex = prefixIndex + 1; + continue; + } + } + int suffixIndex = -1; + while (suffixIndex == -1 && startIndex < length) { + suffixIndex = cellValue.indexOf(FILL_SUFFIX, startIndex + 1); + if (suffixIndex < 0) { + break out; + } + startIndex = suffixIndex + 1; + char prefixSuffixChar = cellValue.charAt(suffixIndex - 1); + if (prefixSuffixChar == IGNORE_CHAR) { + suffixIndex = -1; + } + } + + String variable = cellValue.substring(prefixIndex + 1, suffixIndex); + if (StringUtils.isEmpty(variable)) { + continue; + } + int collectPrefixIndex = variable.indexOf(COLLECTION_PREFIX); + if (collectPrefixIndex == 0) { + variable = variable.substring(collectPrefixIndex + 1); + if (StringUtils.isEmpty(variable)) { + continue; + } + } + varList.add(variable); + } + return varList; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/util/PipeFilterUtils.java b/easyexcel-core/src/main/java/com/alibaba/excel/util/PipeFilterUtils.java new file mode 100644 index 00000000..b8951331 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/util/PipeFilterUtils.java @@ -0,0 +1,123 @@ +package com.alibaba.excel.util; + +import org.springframework.cglib.beans.BeanMap; +import org.springframework.lang.Nullable; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Description: + * + * @author linfeng + * @version 1.0.0 + * @since 2023/5/27 22:51 + */ +public class PipeFilterUtils { + + private static final String PIPELINE_FLAG = "|"; + private static final String MULTI_PIPE_FLAG = "\\|"; + private static final String FILTER_PARAM_FLAG = ":"; + private static final String PARAM_FLAG = ","; + + private static final String VAR_FLAG = "\\."; + + /** + * Return {@code true} if the supplied Collection is {@code null} or empty. + * Otherwise, return {@code false}. + * @param collection the Collection to check + * @return whether the given Collection is empty + */ + public static boolean isEmpty(@Nullable Collection collection) { + return (collection == null || collection.isEmpty()); + } + + /** + * Return {@code true} if the supplied Map is {@code null} or empty. + * Otherwise, return {@code false}. + * @param map the Map to check + * @return whether the given Map is empty + */ + public static boolean isEmpty(@Nullable Map map) { + return (map == null || map.isEmpty()); + } + + public static String trim(String source) { + return StringUtils.isBlank(source) ? "" : source.trim(); + } + + public static String[] getPipelines(String pipelines) { + return pipelines.split(MULTI_PIPE_FLAG); + } + + public static String[] getPipeFilter(String pipeline) { + return pipeline.split(FILTER_PARAM_FLAG); + } + + public static String[] getPipeFilterParams(String pipeFilter) { + return pipeFilter.split(PARAM_FLAG); + } + + /** + * 是否是管道,是管道返回true,反之返回false + * + * @param variable 表达式 + * @return 是否管道 + */ + public static boolean isPipeline(String variable) { + return Objects.nonNull(variable) && variable.contains(PIPELINE_FLAG); + } + + /** + * 获取变量字符串的管道前面的变量 + * + * @param variable 包含管道的变量字符串 + * @return 管道前面的变量字符串 + */ + public static String getVariableName(String variable) { + String[] varArray = PipeFilterUtils.getPipelines(variable); + if (Objects.nonNull(varArray[0])) { + return varArray[0].trim(); + } + return null; + } + + /** + * 从map中获取值 + * @param dataMap map + * @param key 例如: demo.test.name + * @return 返回值 + */ + public static Object getValueOfMap(Map dataMap, String key) { + + if (StringUtils.isBlank(key)) { + return null; + } + Map tempDataMap = dataMap; + String[] keyArray = key.split(VAR_FLAG); + for (int i = 0; i < keyArray.length; i++) { + if (StringUtils.isBlank(keyArray[i])) { + continue; + } + Object obj = tempDataMap.get(keyArray[i]); + if (Objects.isNull(obj)) { + continue; + } + if (i == keyArray.length - 1) { + return obj; + } else { + if (obj instanceof BeanMap) { + tempDataMap = (BeanMap) obj; + } else if (obj instanceof Map) { + tempDataMap = (Map)obj; + } else { + tempDataMap = BeanMapUtils.create(obj); + } + } + } + return null; + } + +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilder.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilder.java index 6a323388..1668da85 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilder.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilder.java @@ -1,11 +1,15 @@ package com.alibaba.excel.write; import java.util.Collection; +import java.util.List; +import java.util.Map; import com.alibaba.excel.context.WriteContext; +import com.alibaba.excel.write.executor.ExcelWriteFillExecutor; import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteTable; +import com.alibaba.excel.write.metadata.fill.AnalysisCell; import com.alibaba.excel.write.metadata.fill.FillConfig; /** @@ -76,4 +80,9 @@ public interface ExcelBuilder { */ void finish(boolean onException); + /** + * Automatic filling error, setting error fields + * @param errorField error field + */ + void setAutoErrorField(String errorField); } diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java index 67e2b9a2..5c4a3129 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -1,6 +1,8 @@ package com.alibaba.excel.write; import java.util.Collection; +import java.util.List; +import java.util.Map; import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.context.WriteContextImpl; @@ -100,6 +102,14 @@ public class ExcelBuilderImpl implements ExcelBuilder { } } + @Override + public void setAutoErrorField(String errorField) { + if (excelWriteFillExecutor == null) { + excelWriteFillExecutor = new ExcelWriteFillExecutor(context); + } + excelWriteFillExecutor.setFillErrorField(errorField); + } + @Override public void merge(int firstRow, int lastRow, int firstCol, int lastCol) { CellRangeAddress cra = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java index 014f97e2..58af66b4 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java @@ -2,10 +2,14 @@ package com.alibaba.excel.write.builder; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; +import java.util.Objects; +import java.util.function.Supplier; import com.alibaba.excel.metadata.AbstractParameterBuilder; import com.alibaba.excel.write.handler.WriteHandler; import com.alibaba.excel.write.metadata.WriteBasicParameter; +import com.alibaba.excel.write.handler.BasePipeFilter; /** * Build ExcelBuilder @@ -133,4 +137,21 @@ public abstract class AbstractExcelWriterParameterBuilder> pipeFilter) { + if (parameter().getCustomPipeFilterMap() == null) { + parameter().setCustomPipeFilterMap(new HashMap<>(16)); + } + if (Objects.isNull(name) || Objects.isNull(pipeFilter)) { + return self(); + } + parameter().getCustomPipeFilterMap().put(name.toLowerCase(), pipeFilter); + return self(); + } } diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java index b7fd6805..a11faa3e 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java @@ -51,6 +51,19 @@ public class ExcelWriterSheetBuilder extends AbstractExcelWriterParameterBuilder return this; } + /** + * 自动填充错误 + * @param errorField 错误字段 + * @return this + */ + public ExcelWriterSheetBuilder autoFillError(String errorField) { + if (excelWriter == null) { + throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet()' to call this method"); + } + excelWriter.autoFillError(errorField); + return this; + } + public WriteSheet build() { return writeSheet; } diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 81524223..bc604120 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -25,17 +25,21 @@ import com.alibaba.excel.util.ListUtils; import com.alibaba.excel.util.MapUtils; import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.WriteHandlerUtils; +import com.alibaba.excel.write.handler.PipeDataWrapper; import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; import com.alibaba.excel.write.handler.context.RowWriteHandlerContext; import com.alibaba.excel.write.metadata.fill.AnalysisCell; import com.alibaba.excel.write.metadata.fill.FillConfig; import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.excel.write.handler.PipeFilterFactory; +import com.alibaba.excel.util.PipeFilterUtils; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import com.alibaba.excel.util.PoiUtils; @@ -51,6 +55,7 @@ import org.apache.poi.ss.usermodel.Sheet; * * @author Jiaju Zhuang */ +@Slf4j public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { private static final String ESCAPE_FILL_PREFIX = "\\\\\\{"; @@ -59,6 +64,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { private static final String FILL_SUFFIX = "}"; private static final char IGNORE_CHAR = '\\'; private static final String COLLECTION_PREFIX = "."; + private static final String DEFAULT_ERROR_FIELD = "error"; /** * Fields to replace in the template */ @@ -91,6 +97,50 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { super(writeContext); } + /** + * Fill in the field name with error information + */ + private String fillErrorField; + + /** + * setting the error field name + * + * @param fillErrorField error field name + */ + public void setFillErrorField(String fillErrorField) { + this.fillErrorField = fillErrorField; + } + + /** + * If fill error field is empty, use default field + * + * @return fill error field + */ + public String getFillErrorField() { + return StringUtils.isBlank(fillErrorField) ? DEFAULT_ERROR_FIELD : fillErrorField; + } + + /** + * 获取excel中cell fill 错误消息 + * + * @return 错误map + */ + public Map> getTemplateAllAnalysisCell() { + Map> allAnalysisCellMap = MapUtils.newHashMap(); + if (!org.springframework.util.CollectionUtils.isEmpty(templateAnalysisCache)) { + allAnalysisCellMap.putAll(templateAnalysisCache); + } + for (Map.Entry> entry : templateCollectionAnalysisCache.entrySet()) { + List analysisCells = allAnalysisCellMap.get(entry.getKey()); + if (Objects.isNull(analysisCells)) { + analysisCells = new ArrayList<>(); + } + analysisCells.addAll(entry.getValue()); + allAnalysisCellMap.put(entry.getKey(), analysisCells); + } + return allAnalysisCellMap; + } + public void fill(Object data, FillConfig fillConfig) { if (data == null) { data = new HashMap(16); @@ -105,7 +155,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { String currentDataPrefix; if (data instanceof FillWrapper) { - FillWrapper fillWrapper = (FillWrapper)data; + FillWrapper fillWrapper = (FillWrapper) data; currentDataPrefix = fillWrapper.getName(); realData = fillWrapper.getCollectionData(); } else { @@ -117,7 +167,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { // processing data if (realData instanceof Collection) { List analysisCellList = readTemplateData(templateCollectionAnalysisCache); - Collection collectionData = (Collection)realData; + Collection collectionData = (Collection) realData; if (CollectionUtils.isEmpty(collectionData)) { return; } @@ -174,7 +224,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } private void increaseRowIndex(Map> templateAnalysisCache, int number, - int maxRowIndex) { + int maxRowIndex) { for (Map.Entry> entry : templateAnalysisCache.entrySet()) { UniqueDataFlagKey uniqueDataFlagKey = entry.getKey(); if (!Objects.equals(currentUniqueDataFlag.getSheetNo(), uniqueDataFlagKey.getSheetNo()) || !Objects.equals( @@ -190,17 +240,16 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } private void doFill(List analysisCellList, Object oneRowData, FillConfig fillConfig, - Integer relativeRowIndex) { + Integer relativeRowIndex) { if (CollectionUtils.isEmpty(analysisCellList) || oneRowData == null) { return; } Map dataMap; if (oneRowData instanceof Map) { - dataMap = (Map)oneRowData; + dataMap = (Map) oneRowData; } else { dataMap = BeanMapUtils.create(oneRowData); } - Set dataKeySet = new HashSet<>(dataMap.keySet()); RowWriteHandlerContext rowWriteHandlerContext = WriteHandlerUtils.createRowWriteHandlerContext(writeContext, null, relativeRowIndex, Boolean.FALSE); @@ -212,10 +261,29 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { if (analysisCell.getOnlyOneVariable()) { String variable = analysisCell.getVariableList().get(0); - if (!dataKeySet.contains(variable)) { - continue; + + Object value; + // Determine if the pipeline is included + if (PipeFilterUtils.isPipeline(variable)) { + value = PipeFilterUtils.getValueOfMap(dataMap, PipeFilterUtils.getVariableName(variable)); + try { + PipeDataWrapper wrapper = PipeFilterFactory.createPipeFilter(writeContext) + .setCell(analysisCell.getRowIndex(), analysisCell.getColumnIndex()) + .addParams(variable).apply(PipeDataWrapper.success(value)); + if (wrapper.success()) { + value = wrapper.getData(); + } else { + value = wrapper.getData(); + fillError2DataMap(dataMap, wrapper.getMessage()); + } + } catch (Exception e) { + fillError2DataMap(dataMap, e.getMessage()); + } + } else { + + value = PipeFilterUtils.getValueOfMap(dataMap, variable); } - Object value = dataMap.get(variable); + ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(dataMap, writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(), variable, writeContext.currentWriteHolder()); @@ -247,10 +315,29 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { for (String variable : analysisCell.getVariableList()) { cellValueBuild.append(analysisCell.getPrepareDataList().get(index++)); - if (!dataKeySet.contains(variable)) { - continue; + + Object value; + // Determine if the pipeline is included + if (PipeFilterUtils.isPipeline(variable)) { + value = PipeFilterUtils.getValueOfMap(dataMap, PipeFilterUtils.getVariableName(variable)); + try { + PipeDataWrapper wrapper = PipeFilterFactory.createPipeFilter(writeContext) + .setCell(analysisCell.getRowIndex(), analysisCell.getColumnIndex()) + .addParams(variable).apply(PipeDataWrapper.success(value)); + if (wrapper.success()) { + value = wrapper.getData(); + } else { + value = wrapper.getData(); + fillError2DataMap(dataMap, wrapper.getMessage()); + } + } catch (Exception e) { + fillError2DataMap(dataMap, e.getMessage()); + } + } else { + + value = PipeFilterUtils.getValueOfMap(dataMap, variable); } - Object value = dataMap.get(variable); + ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(dataMap, writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(), variable, writeContext.currentWriteHolder()); @@ -302,6 +389,29 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } } + /** + * Fill in error information into the data map for subsequent error output to Excel files + * If there are no error fields in the dataMap, throw a pipeline instruction exception + * + * @param dataMap Data to be filled in Excel + * @param msg message + */ + private void fillError2DataMap(@SuppressWarnings("rawtypes") Map dataMap, String msg) { + if (dataMap.containsKey(getFillErrorField())) { + Object errorData = dataMap.get(getFillErrorField()); + if (Objects.nonNull(errorData) && StringUtils.isNotBlank((String) errorData)) { + + //noinspection unchecked + dataMap.put(getFillErrorField(), errorData + "," + msg); + } else { + //noinspection unchecked + dataMap.put(getFillErrorField(), msg); + } + } else { + throw new RuntimeException(msg); + } + } + private Integer getRelativeRowIndex() { Integer relativeRowIndex = relativeRowIndexMap.get(currentUniqueDataFlag); if (relativeRowIndex == null) { @@ -314,7 +424,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } private void createCell(AnalysisCell analysisCell, FillConfig fillConfig, - CellWriteHandlerContext cellWriteHandlerContext, RowWriteHandlerContext rowWriteHandlerContext) { + CellWriteHandlerContext cellWriteHandlerContext, RowWriteHandlerContext rowWriteHandlerContext) { Sheet cachedSheet = writeContext.writeSheetHolder().getCachedSheet(); if (WriteTemplateAnalysisCellTypeEnum.COMMON.equals(analysisCell.getCellType())) { Row row = cachedSheet.getRow(analysisCell.getRowIndex()); @@ -377,7 +487,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } private Cell createCellIfNecessary(Row row, Integer lastColumnIndex, - CellWriteHandlerContext cellWriteHandlerContext) { + CellWriteHandlerContext cellWriteHandlerContext) { Cell cell = row.getCell(lastColumnIndex); if (cell != null) { return cell; @@ -391,7 +501,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } private Row createRowIfNecessary(Sheet sheet, Sheet cachedSheet, Integer lastRowIndex, FillConfig fillConfig, - AnalysisCell analysisCell, boolean isOriginalCell, RowWriteHandlerContext rowWriteHandlerContext) { + AnalysisCell analysisCell, boolean isOriginalCell, RowWriteHandlerContext rowWriteHandlerContext) { rowWriteHandlerContext.setRowIndex(lastRowIndex); Row row = sheet.getRow(lastRowIndex); if (row != null) { @@ -481,7 +591,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { * @return Returns the data that the cell needs to replace */ private String prepareData(Cell cell, int rowIndex, int columnIndex, - Map> firstRowCache) { + Map> firstRowCache) { if (!CellType.STRING.equals(cell.getCellType())) { return null; } @@ -564,7 +674,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } private String dealAnalysisCell(AnalysisCell analysisCell, String value, int rowIndex, int lastPrepareDataIndex, - int length, Map> firstRowCache, StringBuilder preparedData) { + int length, Map> firstRowCache, StringBuilder preparedData) { if (analysisCell != null) { if (lastPrepareDataIndex == length) { analysisCell.getPrepareDataList().add(StringUtils.EMPTY); diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/BasePipeFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/BasePipeFilter.java new file mode 100644 index 00000000..b4f6423b --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/BasePipeFilter.java @@ -0,0 +1,82 @@ +package com.alibaba.excel.write.handler; + +import java.util.*; + +/** + * Description: + * pipeline filter + * + * @author linfeng + */ +public abstract class BasePipeFilter implements PipeFilter { + + private final List filterParams = new ArrayList<>(); + protected int rowIndex; + protected int columnIndex; + + /** + * filter name + * + * @return filter name + */ + protected abstract String filterName(); + + protected boolean isValidity(PipeDataWrapper apply) { + Object data = apply.getData(); + if (Objects.nonNull(data)) { + return !(data instanceof Collection || data instanceof Map); + } + return true; + } + + /** + * @return Error message prefix + */ + protected String errorPrefix() { + return String.format("Column [%s], [%s] instruction error:", columnIndex + 1, filterName()); + } + + /** + * filter params + * + * @return params collection + */ + public List params() { + return filterParams; + } + + /** + * add param + * + * @param params collection + * @return filter + */ + public BasePipeFilter addParams(String... params) { + params().addAll(Arrays.asList(params)); + return this; + } + + /** + * set excel cell + * + * @param row row index + * @param column column index + * @return 过滤器 + */ + public BasePipeFilter setCell(int row, int column) { + this.rowIndex = row; + this.columnIndex = column; + return this; + } + + + /** + * verify + * + * @param wrapper data + * @return true + */ + protected boolean verify(PipeDataWrapper wrapper) { + return Objects.nonNull(wrapper) && wrapper.success(); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeDataWrapper.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeDataWrapper.java new file mode 100644 index 00000000..faaf5189 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeDataWrapper.java @@ -0,0 +1,36 @@ +package com.alibaba.excel.write.handler; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.Serializable; + +/** + * Description: + * filter wrapper + * + * @author linfeng + */ +@Data +@AllArgsConstructor +public class PipeDataWrapper implements Serializable { + private int status; + private String message; + private R data; + + public static PipeDataWrapper success(R data) { + return new PipeDataWrapper<>(200, "OK", data); + } + + public static PipeDataWrapper error(String error, R data) { + return new PipeDataWrapper<>(500, error, data); + } + + public static PipeDataWrapper error(String error) { + return new PipeDataWrapper<>(500, error, null); + } + + public boolean success() { + return status == 200; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilter.java new file mode 100644 index 00000000..9ad8bf7d --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilter.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.write.handler; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +/** + * Description: + * pipe filter + * + * @author linfeng + */ +public interface PipeFilter extends Function, PipeDataWrapper> { + + /** + * apply + * + * @param wrapper the function argument + * @return data wrapper + */ + @Override + PipeDataWrapper apply(PipeDataWrapper wrapper); + + /** + * filter params collection + * + * @return params collection + */ + List params(); + + /** + * add param to pipe filter + * + * @param params param + * @return pipe filter + */ + default PipeFilter addParams(String... params) { + params().addAll(Arrays.asList(params)); + return this; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java new file mode 100644 index 00000000..c018c2b0 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java @@ -0,0 +1,139 @@ +package com.alibaba.excel.write.handler; + +import com.alibaba.excel.context.WriteContext; +import com.alibaba.excel.exception.ExcelRuntimeException; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.write.handler.filter.*; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Description: + * pipe filter factory + * + * @author linfeng + */ +public class PipeFilterFactory extends BasePipeFilter { + + private static final Map>> PIPE_FILTER_MAP = new HashMap<>(); + + static { + // 初始化内置管道过滤器 + PIPE_FILTER_MAP.put("trim", TrimFilter::new); + PIPE_FILTER_MAP.put("equals", EqualsFilter::new); + PIPE_FILTER_MAP.put("prior-equals", PriorEqualsFilter::new); + PIPE_FILTER_MAP.put("ends-with", EndsWithFilter::new); + PIPE_FILTER_MAP.put("prior-ends-with", PriorEndsWithFilter::new); + PIPE_FILTER_MAP.put("starts-with", StartsWithFilter::new); + PIPE_FILTER_MAP.put("prior-starts-with", PriorStartsWithFilter::new); + PIPE_FILTER_MAP.put("pattern", PatternFilter::new); + PIPE_FILTER_MAP.put("prior-pattern", PriorPatternFilter::new); + PIPE_FILTER_MAP.put("date-format", DateFormatFilter::new); + PIPE_FILTER_MAP.put("contains", ContainsFilter::new); + PIPE_FILTER_MAP.put("prior-contains", PriorContainsFilter::new); + PIPE_FILTER_MAP.put("list-index", ListIndexFilter::new); + PIPE_FILTER_MAP.put("list-echo", ListEchoFilter::new); + PIPE_FILTER_MAP.put("list-range", ListRangeFilter::new); + PIPE_FILTER_MAP.put("echo", EchoFilter::new); + PIPE_FILTER_MAP.put("cal-add", AdditionFilter::new); + PIPE_FILTER_MAP.put("cal-sub", SubtractionFilter::new); + PIPE_FILTER_MAP.put("cal-mul", MultiplicationFilter::new); + PIPE_FILTER_MAP.put("cal-div", DivisionFilter::new); + PIPE_FILTER_MAP.put("substring", SubstringFilter::new); + PIPE_FILTER_MAP.put("replace", ReplaceFilter::new); + } + + private PipeFilterFactory(WriteContext writeContext) { + if (Objects.nonNull(writeContext) + && Objects.nonNull(writeContext.writeWorkbookHolder()) + && Objects.nonNull(writeContext.writeWorkbookHolder().getWriteWorkbook()) + && PipeFilterUtils.isEmpty(writeContext.writeWorkbookHolder().getWriteWorkbook().getCustomPipeFilterMap())) { + PIPE_FILTER_MAP.putAll(writeContext.writeWorkbookHolder().getWriteWorkbook().getCustomPipeFilterMap()); + } + } + + /** + * Create pipeline filters + * + * @param writeContext WriteContext + * @return pipe filter factory + */ + public static PipeFilterFactory createPipeFilter(WriteContext writeContext) { + return new PipeFilterFactory(writeContext); + } + + @Override + public PipeDataWrapper apply(PipeDataWrapper value) { + + if (PipeFilterUtils.isEmpty(params())) { + throw new ExcelRuntimeException("Incorrect format of instruction parameter string"); + } + + String variable = params().get(0); + if (StringUtils.isBlank(variable)) { + throw new ExcelRuntimeException("The instruction parameter string cannot be empty"); + } + + String[] pipeArray = PipeFilterUtils.getPipelines(variable); + Objects.requireNonNull(pipeArray, "The instruction parameter string cannot be empty"); + if (pipeArray.length <= 1) { + throw new ExcelRuntimeException("Incorrect format of instruction parameter string"); + } + + List> pipeFilterList = new ArrayList<>(); + for (int i = 1; i < pipeArray.length; i++) { + if (StringUtils.isBlank(pipeArray[i])) { + continue; + } + + String[] expressArray = PipeFilterUtils.getPipeFilter(pipeArray[i]); + if (StringUtils.isBlank(expressArray[0])) { + continue; + } + + String filterName = PipeFilterUtils.trim(expressArray[0]).toLowerCase(); + if (StringUtils.isBlank(filterName)) { + continue; + } + + Supplier> supplier = PIPE_FILTER_MAP.get(filterName); + if (Objects.isNull(supplier)) { + throw new ExcelRuntimeException(String.format("No pipeline filter for [%s]", filterName)); + } + BasePipeFilter pipeFilter = supplier.get(); + if (Objects.nonNull(pipeFilter)) { + pipeFilterList.add(pipeFilter); + } + pipeFilter.setCell(rowIndex, columnIndex); + + if (expressArray.length > 1 && StringUtils.isNotBlank(expressArray[1])) { + String[] paramArray = PipeFilterUtils.getPipeFilterParams(PipeFilterUtils.trim(expressArray[1])); + pipeFilter.addParams(paramArray); + } + + } + + if (PipeFilterUtils.isEmpty(pipeFilterList)) { + return value; + } + // 构建pipeline + Function, PipeDataWrapper> currFilter = pipeFilterList.get(0); + for (int i = 1; i < pipeFilterList.size(); i++) { + currFilter = currFilter.andThen(pipeFilterList.get(i)); + } + PipeDataWrapper dataWrapper = currFilter.apply(value); + if (isValidity(dataWrapper)) { + return dataWrapper; + } + return PipeDataWrapper.error(String.format("column [%s], data error:%s", columnIndex + 1, "the input value cannot be a set or a Map")); + } + + + @Override + protected String filterName() { + return "factory"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractCalculatorFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractCalculatorFilter.java new file mode 100644 index 00000000..9c1f8c47 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractCalculatorFilter.java @@ -0,0 +1,165 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Objects; + +/** + * Description: + * abstract calculator filter + * + * @author linfeng + */ +@Slf4j +public abstract class AbstractCalculatorFilter extends BasePipeFilter { + + public static final String INT = "int"; + public static final String NUMBER = "number"; + public static final String REGEX = "_"; + + public static class Calculator { + + public static double add(double a, double b) { + return a + b; + } + + public static double subtract(double a, double b) { + return a - b; + } + + public static double multiply(double a, double b) { + return a * b; + } + + public static double divide(double a, double b) { + if (b == 0) { + throw new IllegalArgumentException("Divider cannot be 0"); + } + return a / b; + } + } + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "incoming data cannot be empty"); + } + + if (PipeFilterUtils.isEmpty(params())) { + return PipeDataWrapper.error(errorPrefix() + "missing parameter for instruction"); + } + + String params1 = params().get(0); + if (StringUtils.isBlank(params1)) { + return PipeDataWrapper.error(errorPrefix() + "instruction parameter is empty"); + } + + double number1 = 0D; + if (value instanceof Number) { + number1 = ((Number) value).doubleValue(); + } else if (value instanceof String) { + try { + number1 = Double.parseDouble((String) value); + } catch (Exception e) { + number1 = 0D; + } + } + + double number2; + try { + number2 = Double.parseDouble(params1); + } catch (Exception e) { + number2 = 0D; + } + + double result = calculator(number1, number2); + + return showDataWrapper(result); + + } + + /** + * Construct pipeline data wrapping objects based on calculation results + * + * @param result Calculation results + * @return Pipe Data Wrapper + */ + private PipeDataWrapper showDataWrapper(double result) { + if (params().size() <= 1) { + return PipeDataWrapper.success(result); + } else { + String params2 = params().get(1); + if (StringUtils.isBlank(params2)) { + return PipeDataWrapper.success(result); + } + String[] params2Array = params2.split(REGEX); + if (INT.equalsIgnoreCase(params2Array[0])) { + + return PipeDataWrapper.success(BigDecimal.valueOf(result).setScale(0, RoundingMode.HALF_UP).intValue()); + } else if (NUMBER.equalsIgnoreCase(params2Array[0])) { + if (params2Array.length > 1) { + if (StringUtils.isNumeric(params2Array[1])) { + int scale = Integer.parseInt(params2Array[1]); + BigDecimal bigDecimal = BigDecimal.valueOf(result).setScale(scale, RoundingMode.HALF_UP); + if (scale == 0) { + return PipeDataWrapper.success(bigDecimal.intValue()); + } else { + return PipeDataWrapper.success(bigDecimal.doubleValue()); + } + } else { + log.warn("The digit parameter passed by the Calculator instruction [cal_add, cal_sub, cal_mul, cal_div] is not a number"); + return PipeDataWrapper.success(result); + } + } else { + return PipeDataWrapper.success(result); + } + } else { + return PipeDataWrapper.success(result); + } + } + } + + /** + * calculator + * + * @param number1 number + * @param number2 number + * @return Calculation results + */ + private double calculator(double number1, double number2) { + double result; + switch (filterName()) { + case "cal-add": + result = Calculator.add(number1, number2); + break; + case "cal-sub": + result = Calculator.subtract(number1, number2); + break; + case "cal-mul": + result = Calculator.multiply(number1, number2); + break; + case "cal-div": + if (number2 == 0) { + throw new RuntimeException("The cal_div instruction with a divisor of 0 is not supported"); + } + result = Calculator.divide(number1, number2); + break; + default: + throw new RuntimeException("The Calculator instruction is not supported"); + } + return result; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractEchoFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractEchoFilter.java new file mode 100644 index 00000000..31ef8d7c --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractEchoFilter.java @@ -0,0 +1,52 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.write.handler.BasePipeFilter; + +/** + * Description: + * abstract echo + * + * @author linfeng + */ +public abstract class AbstractEchoFilter extends BasePipeFilter { + + protected enum Delimiter { + /** + * blank + */ + BLANK("blank", " "), + /** + * enter + */ + WRAP("wrap", "\n"), + /** + * comma + */ + COMMA("comma", ","); + + private final String value; + private final String delimiter; + + Delimiter(String value, String delimiter) { + this.value = value; + this.delimiter = delimiter; + } + + public static Delimiter ofValue(String value) { + for (Delimiter delim : Delimiter.values()) { + if (delim.value.equalsIgnoreCase(value)) { + return delim; + } + } + return null; + } + + public String getValue() { + return value; + } + + public String getDelimiter() { + return delimiter; + } + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractMatchFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractMatchFilter.java new file mode 100644 index 00000000..2ec74281 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractMatchFilter.java @@ -0,0 +1,164 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.BeanMapUtils; +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; + +import java.util.*; + +/** + * Description: + * abstract match filter + * + * @author linfeng + */ +public abstract class AbstractMatchFilter extends BasePipeFilter { + + /** + * String Matching + * + * @param source source string + * @param match Match String + * @return Match or not + */ + protected abstract boolean strMatch(String source, String match); + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + if (PipeFilterUtils.isEmpty(params())) { + return PipeDataWrapper.error(errorPrefix() + "missing parameter for instruction"); + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "Incoming data cannot be empty"); + } + + Object dataObj; + if (value instanceof String || value instanceof Collection || value instanceof Map) { + dataObj = value; + } else { + dataObj = BeanMapUtils.create(value); + } + + if (params().size() == 1) { + + return singleParamsHandle(dataObj); + } else { + + return moreParamsHandle(dataObj); + } + } + + /** + * 单参数处理 + * + * @param value 待处理数据 + * @return 处理后的数据 + */ + private PipeDataWrapper singleParamsHandle(Object value) { + String center = params().get(0); + if (StringUtils.isBlank(center)) { + return PipeDataWrapper.error(errorPrefix() + "instruction parameter cannot be empty"); + } + + return instructHandle(value, center); + } + + /** + * 多参数处理 + * + * @param value 待处理数据 + * @return 处理后的数据 + */ + protected PipeDataWrapper moreParamsHandle(Object value) { + List result = new ArrayList<>(); + List error = new ArrayList<>(); + for (String center : params()) { + if (Objects.isNull(center)) { + continue; + } + PipeDataWrapper itemDataWrapper = instructHandle(value, center); + if (itemDataWrapper.success()) { + result.add(itemDataWrapper.getData()); + } else { + error.add(itemDataWrapper.getMessage()); + } + } + if (PipeFilterUtils.isEmpty(error)) { + return PipeDataWrapper.success(result); + } else { + return PipeDataWrapper.error(errorPrefix() + String.join(",", error), result); + } + } + + /** + * 指令处理 + * + * @param value 待处理的值 + * @param center 待匹配的字符串 + * @return 数据包裹 + */ + protected PipeDataWrapper instructHandle(Object value, String center) { + + if (value instanceof Collection) { + String result = null; + //noinspection unchecked + Collection collection = (Collection) value; + for (Object col : collection) { + if (Objects.isNull(col)) { + continue; + } + if (col instanceof String) { + String cel = (String) col; + if (strMatch(cel, center)) { + result = cel; + break; + } + } + } + if (StringUtils.isBlank(result)) { + return PipeDataWrapper.error(errorPrefix() + String.format("No data containing [%s]", center)); + } else { + return PipeDataWrapper.success(result); + } + } else if (value instanceof String) { + String col = (String) value; + if (strMatch(col, center)) { + return PipeDataWrapper.success(col); + } else { + return PipeDataWrapper.error(errorPrefix() + String.format("No data containing [%s]", center)); + } + } else if (value instanceof Map) { + + //noinspection unchecked + Map colMap = (Map) value; + for (Map.Entry entry : colMap.entrySet()) { + if (Objects.isNull(entry.getKey())) { + continue; + } + if (strMatch(entry.getKey().toString(), center)) { + if (Objects.nonNull(entry.getValue())) { + return PipeDataWrapper.success(entry.getValue().toString()); + } else { + return PipeDataWrapper.success(""); + } + } + } + return PipeDataWrapper.error(errorPrefix() + String.format("No data containing [%s]", center)); + } else { + + return PipeDataWrapper.error(errorPrefix() + "the incoming data is not a collection or string", value.toString()); + } + } + + +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractPriorMatchFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractPriorMatchFilter.java new file mode 100644 index 00000000..d623e4ff --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AbstractPriorMatchFilter.java @@ -0,0 +1,35 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.write.handler.PipeDataWrapper; + +import java.util.Objects; + +/** + * Description: + * Priority matching filter + * + * @author linfeng + */ +public abstract class AbstractPriorMatchFilter extends AbstractMatchFilter { + + /** + * Multi parameter processing, priority processing + * + * @param value Pending data + * @return processed data + */ + @Override + protected PipeDataWrapper moreParamsHandle(Object value) { + for (String center : params()) { + if (Objects.isNull(center)) { + continue; + } + PipeDataWrapper itemDataWrapper = instructHandle(value, center); + if (itemDataWrapper.success()) { + return itemDataWrapper; + } + } + return PipeDataWrapper.error(errorPrefix() + String.format("The instruction did not match the result of [%s]", String.join(",", params()))); + } + +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AdditionFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AdditionFilter.java new file mode 100644 index 00000000..773556d2 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/AdditionFilter.java @@ -0,0 +1,15 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * add + * @author linfeng + */ +public class AdditionFilter extends AbstractCalculatorFilter { + + + @Override + protected String filterName() { + return "cal-add"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ContainsFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ContainsFilter.java new file mode 100644 index 00000000..7a2c2196 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ContainsFilter.java @@ -0,0 +1,20 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * Contains Filter + * + * @author linfeng + */ +public class ContainsFilter extends AbstractMatchFilter { + + @Override + protected String filterName() { + return "contains"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.contains(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DateFormatFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DateFormatFilter.java new file mode 100644 index 00000000..35b3977e --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DateFormatFilter.java @@ -0,0 +1,56 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; + +import java.util.Date; +import java.util.Objects; + +/** + * Description: + * Date Format Filter + * @author linfeng + */ +public class DateFormatFilter extends BasePipeFilter { + + private static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + @Override + protected String filterName() { + return "date-format"; + } + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "Incoming data cannot be empty"); + } + + if (value instanceof Date) { + + String format; + if (PipeFilterUtils.isEmpty(params())) { + format = DEFAULT_FORMAT; + } else { + format = StringUtils.isBlank(params().get(0)) ? DEFAULT_FORMAT : params().get(0); + } + Date date = (Date) value; + return PipeDataWrapper.success(DateUtils.format(date, format)); + } else if (value instanceof String) { + + return PipeDataWrapper.success(value); + } + + return PipeDataWrapper.error(errorPrefix() + "The data passed in by the instruction is not a Date or string"); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DivisionFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DivisionFilter.java new file mode 100644 index 00000000..d859d54e --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/DivisionFilter.java @@ -0,0 +1,16 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * Division Filter + * + * @author linfeng + */ +public class DivisionFilter extends AbstractCalculatorFilter { + + + @Override + protected String filterName() { + return "cal-div"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EchoFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EchoFilter.java new file mode 100644 index 00000000..701be4b3 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EchoFilter.java @@ -0,0 +1,59 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.PipeDataWrapper; + +import java.util.Objects; + +/** + * Description: + * echo filter + * + * @author linfeng + */ +public class EchoFilter extends AbstractEchoFilter { + @Override + protected String filterName() { + return "echo"; + } + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + if (Objects.isNull(wrapper)) { + return PipeDataWrapper.error(errorPrefix() + "missing parameter for instruction"); + } + + if (!wrapper.success()) { + return PipeDataWrapper.error(wrapper.getMessage()); + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.success(""); + } + + if (!(value instanceof String)) { + return PipeDataWrapper.error(errorPrefix() + "The incoming data is not a string"); + } + + String val = (String) value; + if (StringUtils.isBlank(val)) { + return PipeDataWrapper.success(""); + } + + if (PipeFilterUtils.isEmpty(params())) { + return PipeDataWrapper.success(""); + } + + String delimiter = params().get(0); + + Delimiter delimiterEnum = Delimiter.ofValue(delimiter); + if (Objects.nonNull(delimiterEnum)) { + return PipeDataWrapper.success(val + delimiterEnum.getDelimiter()); + } + + return PipeDataWrapper.success(val + delimiter); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EndsWithFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EndsWithFilter.java new file mode 100644 index 00000000..73492efe --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EndsWithFilter.java @@ -0,0 +1,20 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * ends-with filter + * + * @author linfeng + */ +public class EndsWithFilter extends AbstractMatchFilter { + + @Override + protected String filterName() { + return "ends-with"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.endsWith(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EqualsFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EqualsFilter.java new file mode 100644 index 00000000..a3544ac3 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/EqualsFilter.java @@ -0,0 +1,20 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * equals Filter + * + * @author linfeng + */ +public class EqualsFilter extends AbstractMatchFilter { + + @Override + protected String filterName() { + return "equals"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.equalsIgnoreCase(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListEchoFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListEchoFilter.java new file mode 100644 index 00000000..951eec72 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListEchoFilter.java @@ -0,0 +1,64 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.write.handler.PipeDataWrapper; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Description: + * list-echo + * + * @author linfeng + * @version 1.0.0 + * @since 2023/5/30 16:52 + */ +public class ListEchoFilter extends AbstractEchoFilter { + + @Override + protected String filterName() { + return "list-echo"; + } + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.success(""); + } + + if (!(value instanceof Collection)) { + return PipeDataWrapper.error(errorPrefix() + "The incoming data is not a collection"); + } + + @SuppressWarnings("unchecked") + List collection = (List) value; + + if (PipeFilterUtils.isEmpty(collection)) { + return PipeDataWrapper.success(""); + } + + if (PipeFilterUtils.isEmpty(params())) { + return PipeDataWrapper.success(collection.stream().map(String::valueOf).collect(Collectors.joining(Delimiter.WRAP.getDelimiter()))); + } + + String delimiter = params().get(0); + + Delimiter delimiterEnum = Delimiter.ofValue(delimiter); + if (Objects.nonNull(delimiterEnum)) { + return PipeDataWrapper.success(collection.stream().map(String::valueOf).collect(Collectors.joining(delimiterEnum.getDelimiter()))); + } + + return PipeDataWrapper.success(collection.stream().map(String::valueOf).collect(Collectors.joining(delimiter))); + + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListIndexFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListIndexFilter.java new file mode 100644 index 00000000..8ccd8f87 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListIndexFilter.java @@ -0,0 +1,92 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Description: + * + * @author linfeng + * @version 1.0.0 + * @since 2023/5/30 16:52 + */ +@Slf4j +public class ListIndexFilter extends BasePipeFilter { + + /** + * 参数格式 list-index:n n表示下标,从1开始 + * + * @param wrapper the function argument + * @return + */ + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + if (PipeFilterUtils.isEmpty(params())) { + return PipeDataWrapper.error(errorPrefix() + "missing parameter for instruction"); + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "Incoming data cannot be empty"); + } + + if (!(value instanceof Collection)) { + return PipeDataWrapper.error(errorPrefix() + "The incoming data is not a collection"); + } + + @SuppressWarnings("unchecked") + List collection = (List) value; + + if (CollectionUtils.isEmpty(collection)) { + return PipeDataWrapper.error(errorPrefix() + "Incoming data cannot be empty"); + } + + if (PipeFilterUtils.isEmpty(params()) || params().size() > 1) { + return PipeDataWrapper.error(errorPrefix() + "The index of the passed in parameter is empty or exceeds one"); + } + + String index = params().get(0); + if (StringUtils.isBlank(index)) { + return PipeDataWrapper.error(errorPrefix() + "The index of the incoming parameter is empty"); + } + + try { + int ind = Integer.parseInt(index); + if (ind < 0) { + ind = 0; + } + if (ind >= 1) { + ind -= 1; + } + if (ind >= collection.size() - 1) { + return PipeDataWrapper.error(errorPrefix() + "The index of the passed in parameter exceeds the maximum length of the set"); + } + List collect = collection.stream().map(Object::toString).collect(Collectors.toList()); + return PipeDataWrapper.success(collect.get(ind)); + } catch (NumberFormatException e) { + + log.warn(e.getMessage(), e); + return PipeDataWrapper.error(errorPrefix() + "Index conversion error"); + } + } + + @Override + protected String filterName() { + return "list-index"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListRangeFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListRangeFilter.java new file mode 100644 index 00000000..36524d33 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ListRangeFilter.java @@ -0,0 +1,99 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Description: + * + * @author linfeng + * @version 1.0.0 + * @since 2023/5/30 16:52 + */ +@Slf4j +public class ListRangeFilter extends BasePipeFilter { + + private static final int PARAMS_NUM = 2; + + /** + * list-range:index,count Starting from index, obtain count quantity + * + * @param wrapper the function argument + * @return + */ + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "Incoming data cannot be empty"); + } + + if (!(value instanceof Collection)) { + return PipeDataWrapper.error(errorPrefix() + "The incoming data is not a collection"); + } + + @SuppressWarnings("unchecked") + List collection = (List) value; + + if (PipeFilterUtils.isEmpty(params()) || params().size() > PARAMS_NUM) { + return PipeDataWrapper.error(errorPrefix() + "[list-range:index,count] the input parameter subscript is empty or exceeds two"); + } + + String index = params().get(0); + if (StringUtils.isBlank(index)) { + return PipeDataWrapper.error(errorPrefix() + "[list-range:index,count] the parameter index passed in is empty"); + } + + String count = params().get(1); + if (StringUtils.isBlank(count)) { + return PipeDataWrapper.error(errorPrefix() + "[list-range:index,count] the parameter count passed in is empty"); + } + + try { + int fromIndex = Integer.parseInt(index); + if (fromIndex < 0) { + fromIndex = 0; + } + if (fromIndex >= 1) { + fromIndex -= 1; + } + + int countInt = Integer.parseInt(count); + if (countInt < 1) { + return PipeDataWrapper.error(errorPrefix() + "[list-range:index,count] count parameter must be greater than 0"); + } + + int toIndex = countInt + fromIndex; + int size = collection.size(); + if (toIndex > size) { + log.warn("error:[list-range:index,count] the count parameter value is greater than the size of the input set"); + toIndex = size; + } + + List collect = collection.stream().map(Object::toString).collect(Collectors.toList()); + return PipeDataWrapper.success(collect.subList(fromIndex, toIndex)); + } catch (NumberFormatException e) { + log.warn(e.getMessage(), e); + return PipeDataWrapper.error(errorPrefix() + "[list-range:index,count] Index or count parameter conversion error"); + } + } + + @Override + protected String filterName() { + return "list-range"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/MultiplicationFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/MultiplicationFilter.java new file mode 100644 index 00000000..827cbb72 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/MultiplicationFilter.java @@ -0,0 +1,16 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * cal-mul + * + * @author linfeng + */ +public class MultiplicationFilter extends AbstractCalculatorFilter { + + + @Override + protected String filterName() { + return "cal-mul"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PatternFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PatternFilter.java new file mode 100644 index 00000000..2e6d8814 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PatternFilter.java @@ -0,0 +1,22 @@ +package com.alibaba.excel.write.handler.filter; + +import java.util.regex.Pattern; + +/** + * Description: + * pattern + * + * @author linfeng + */ +public class PatternFilter extends AbstractMatchFilter { + + @Override + protected String filterName() { + return "pattern"; + } + + @Override + protected boolean strMatch(String source, String match) { + return Pattern.matches(match, source); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorContainsFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorContainsFilter.java new file mode 100644 index 00000000..d442424a --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorContainsFilter.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * prior-contains + * + * @author linfeng + */ +public class PriorContainsFilter extends AbstractPriorMatchFilter { + + + @Override + protected String filterName() { + return "prior-contains"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.contains(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEndsWithFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEndsWithFilter.java new file mode 100644 index 00000000..0d9d4f6c --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEndsWithFilter.java @@ -0,0 +1,19 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * prior-ends-with + * @author linfeng + */ +public class PriorEndsWithFilter extends AbstractPriorMatchFilter { + + @Override + protected String filterName() { + return "prior-ends-with"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.endsWith(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEqualsFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEqualsFilter.java new file mode 100644 index 00000000..4b6a2746 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorEqualsFilter.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * prior-equals + * + * @author linfeng + */ +public class PriorEqualsFilter extends AbstractPriorMatchFilter { + + + @Override + protected String filterName() { + return "prior-equals"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.equalsIgnoreCase(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorPatternFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorPatternFilter.java new file mode 100644 index 00000000..6ffc1e03 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorPatternFilter.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.write.handler.filter; + +import java.util.regex.Pattern; + +/** + * Description: + * prior-pattern + * + * @author linfeng + */ +public class PriorPatternFilter extends AbstractPriorMatchFilter { + @Override + protected String filterName() { + return "prior-pattern"; + } + + @Override + protected boolean strMatch(String source, String match) { + return Pattern.matches(match, source); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorStartsWithFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorStartsWithFilter.java new file mode 100644 index 00000000..1e2309a3 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/PriorStartsWithFilter.java @@ -0,0 +1,20 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * starts-with + * + * @author linfeng + */ +public class PriorStartsWithFilter extends AbstractPriorMatchFilter { + + @Override + protected String filterName() { + return "starts-with"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.startsWith(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ReplaceFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ReplaceFilter.java new file mode 100644 index 00000000..99b00aff --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/ReplaceFilter.java @@ -0,0 +1,77 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; +import lombok.extern.slf4j.Slf4j; + +import java.util.Objects; + +/** + * Description: + * replace + * @author linfeng + */ +@Slf4j +public class ReplaceFilter extends BasePipeFilter { + + private static final int PARAMS_NUM = 3; + + @Override + protected String filterName() { + return "replace"; + } + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "incoming data cannot be empty"); + } + + if (PipeFilterUtils.isEmpty(params()) || params().size() != PARAMS_NUM) { + return PipeDataWrapper.error(errorPrefix() + "[replace:oldChar,newChar,all] the input parameter is empty or exceeds two"); + } + + String oldChar = params().get(0); + if (StringUtils.isBlank(oldChar)) { + return PipeDataWrapper.error(errorPrefix() + "[replace:oldChar,newChar,all] the parameter 'oldChar' passed in is empty"); + } + + String newChar = params().get(1); + if (StringUtils.isBlank(newChar)) { + return PipeDataWrapper.error(errorPrefix() + "[replace:oldChar,newChar,all] the parameter 'newChar' passed in is empty"); + } + + String all = params().get(2); + if (StringUtils.isBlank(all)) { + return PipeDataWrapper.error(errorPrefix() + "[replace:oldChar,newChar,all] the parameter 'all' passed in is empty, not 1/0"); + } + if (!StringUtils.isNumeric(all)) { + return PipeDataWrapper.error(errorPrefix() + "[replace:oldChar,newChar,all] the parameter 'all' passed in, not 1/0"); + } + + if (!(value instanceof String)) { + return PipeDataWrapper.error(errorPrefix() + "the instruction input data is not a string"); + } + + try { + int allInt = Integer.parseInt(all); + if (1 == allInt) { + return PipeDataWrapper.success(((String) value).replaceAll(oldChar, newChar)); + } else { + return PipeDataWrapper.success(((String) value).replace(oldChar, newChar)); + } + } catch (Exception e) { + log.warn(e.getMessage()); + return PipeDataWrapper.error(errorPrefix() + "[replace:oldChar,newChar,all] the parameter 'all' conversion error"); + } + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/StartsWithFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/StartsWithFilter.java new file mode 100644 index 00000000..1e4e4ad2 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/StartsWithFilter.java @@ -0,0 +1,20 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * starts-with + * + * @author linfeng + */ +public class StartsWithFilter extends AbstractMatchFilter { + + @Override + protected String filterName() { + return "starts-with"; + } + + @Override + protected boolean strMatch(String source, String match) { + return source.startsWith(match); + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubstringFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubstringFilter.java new file mode 100644 index 00000000..843dc258 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubstringFilter.java @@ -0,0 +1,74 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.util.PipeFilterUtils; +import com.alibaba.excel.util.StringUtils; +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; +import lombok.extern.slf4j.Slf4j; + +import java.util.Objects; + +/** + * Description: + * Substring + * @author linfeng + */ +@Slf4j +public class SubstringFilter extends BasePipeFilter { + + private static final int PARAMS_NUM = 2; + + @Override + protected String filterName() { + return "substring"; + } + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "incoming data cannot be empty"); + } + + if (PipeFilterUtils.isEmpty(params()) || params().size() != PARAMS_NUM) { + return PipeDataWrapper.error(errorPrefix() + "[substring:beginIndex,endIndex] the input parameter is empty or exceeds two"); + } + + String begin = params().get(0); + if (StringUtils.isBlank(begin)) { + return PipeDataWrapper.error(errorPrefix() + "[substring:beginIndex,endIndex] the incoming parameter 'beginIndex' is empty"); + } + + String end = params().get(1); + if (StringUtils.isBlank(end)) { + return PipeDataWrapper.error(errorPrefix() + "[substring:beginIndex,endIndex] the parameter 'endIndex' is empty"); + } + + if (!(value instanceof String)) { + return PipeDataWrapper.error(errorPrefix() + "the instruction input data is not a string"); + } + + try { + int length = ((String) value).length(); + int beginIndex = Integer.parseInt(begin); + int endIndex = Integer.parseInt(end); + if (endIndex > length) { + endIndex = length; + } + int subLen = endIndex - beginIndex; + if (subLen < 0) { + return PipeDataWrapper.error(errorPrefix() + "index error,beginIndex==endIndex"); + } + return PipeDataWrapper.success(((String) value).substring(beginIndex, endIndex)); + } catch (NumberFormatException e) { + log.warn(e.getMessage(), e); + return PipeDataWrapper.error(errorPrefix() + "index conversion error"); + } + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubtractionFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubtractionFilter.java new file mode 100644 index 00000000..4fca6217 --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/SubtractionFilter.java @@ -0,0 +1,15 @@ +package com.alibaba.excel.write.handler.filter; + +/** + * Description: + * sub + * @author linfeng + */ +public class SubtractionFilter extends AbstractCalculatorFilter { + + + @Override + protected String filterName() { + return "cal-sub"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/TrimFilter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/TrimFilter.java new file mode 100644 index 00000000..b867cebb --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/filter/TrimFilter.java @@ -0,0 +1,51 @@ +package com.alibaba.excel.write.handler.filter; + +import com.alibaba.excel.write.handler.BasePipeFilter; +import com.alibaba.excel.write.handler.PipeDataWrapper; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Description: + * trim pipe filter + * + * @author linfeng + */ +public class TrimFilter extends BasePipeFilter { + + @Override + public PipeDataWrapper apply(PipeDataWrapper wrapper) { + + // 验证 + if (!verify(wrapper)) { + return wrapper; + } + + Object value = wrapper.getData(); + if (Objects.isNull(value)) { + return PipeDataWrapper.error(errorPrefix() + "incoming data cannot be empty"); + } + + if (value instanceof String) { + + return PipeDataWrapper.success(value.toString().trim()); + } else if (value instanceof Collection) { + //noinspection unchecked + Collection valList = (Collection) value; + if (CollectionUtils.isEmpty(valList)) { + return PipeDataWrapper.error(errorPrefix() + "incoming data cannot be empty"); + } + return PipeDataWrapper.success(valList.stream().filter(Objects::nonNull).map(str -> str.toString().trim()).collect(Collectors.toList())); + } + + return PipeDataWrapper.error(errorPrefix() + "the instruction input data is not a string or set"); + } + + @Override + protected String filterName() { + return "trim"; + } +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java index a926209a..8f67628f 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java @@ -1,12 +1,12 @@ package com.alibaba.excel.write.metadata; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; +import java.util.function.Supplier; import com.alibaba.excel.metadata.BasicParameter; import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.handler.BasePipeFilter; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -63,4 +63,9 @@ public class WriteBasicParameter extends BasicParameter { * default is false. */ private Boolean orderByIncludeColumn; + + /** + * pipe filter map + */ + private Map>> customPipeFilterMap = new HashMap<>(); } diff --git a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillData.java b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillData.java index 6eb34ada..fdf144e5 100644 --- a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillData.java +++ b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillData.java @@ -1,6 +1,7 @@ package com.alibaba.easyexcel.test.demo.fill; import java.util.Date; +import java.util.List; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -16,5 +17,6 @@ public class FillData { private String name; private double number; private Date date; - + private List images; + private String error; } diff --git a/easyexcel-test/src/test/java/com/alibaba/excel/write/handler/PipeFilterFactoryTest.java b/easyexcel-test/src/test/java/com/alibaba/excel/write/handler/PipeFilterFactoryTest.java new file mode 100644 index 00000000..c8e62f29 --- /dev/null +++ b/easyexcel-test/src/test/java/com/alibaba/excel/write/handler/PipeFilterFactoryTest.java @@ -0,0 +1,155 @@ +package com.alibaba.excel.write.handler; + +import com.alibaba.easyexcel.test.demo.fill.FillData; +import com.alibaba.excel.util.ListUtils; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.springframework.util.Assert; + +import java.util.*; + + +/** + * Description: + * + * @author linfeng + * @version 1.0.0 + * @since 2023/6/21 14:00 + */ +class PipeFilterFactoryTest { + + private List dataPipe() { + List list = ListUtils.newArrayList(); + for (int i = 0; i < 10; i++) { + FillData fillData = new FillData(); + list.add(fillData); + fillData.setName(" 张三 "); + fillData.setNumber(5.2); + fillData.setDate(new Date()); + if (i == 0) { + fillData.setImages(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.4.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg")); + } else { + fillData.setImages(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.4.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg" + , "http://www.baidu.com/images/K100-1.2.jpg")); + } + } + return list; + } + + @Test + void testEndsWithError() { + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("test | ends-with : "); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.4.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg" + , "http://www.baidu.com/images/K100-1.2.jpg"))); + System.out.println(apply.getMessage()); + Assert.isTrue(!apply.success(), "成功"); + } + + @Test + void testEndsWith() { + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("test | ends-with : m100-1.3.jpg,m100-1.5.jpg,m100-1.4.jpg "); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.4.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg" + , "http://www.baidu.com/images/K100-1.2.jpg"))); + Assert.isTrue(!apply.success(), "测试输出多个数字,不能为集合"); + } + + @Test + void testProEndsWith() { + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("test | prior-ends-with : m100-1.3.jpg,m100-1.5.jpg,m100-1.4.jpg "); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.4.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg" + , "http://www.baidu.com/images/K100-1.2.jpg"))); + Assert.isTrue(apply.success(), "失败"); + } + + + @Test + void testSubstr() { + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("test | substring : 0,10 "); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success("这个示例程序创建了两个 double 类型的变量 a 和 b,分别赋值为 10 和 5,然后调用 Calculator 类中的四个方法,输出运算结果。其中,divide 方法在除数为0时会抛出异常,这里使用了 try-catch 语句捕获异常,并输出错误信息。")); + Assert.isTrue(apply.success(), "失败"); + } + + @Test + void testEquals() { +// + Map titleMap = new HashMap<>(2); + titleMap.put("eBayTitle", "eBayTitle这个示例程序创建了两个 double 类型的变量 a 和 b,分别赋值为 10 和 5,然后调用 Calculator 类中的四个方法,输出运算结果"); + titleMap.put("amazonTitle", "amazonTitle其中,divide 方法在除数为0时会抛出异常,这里使用了 try-catch 语句捕获异常,并输出错误信息。"); + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("PublishCenter.titleMap | prior-equals:amazonTitle,eBayTitle "); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success(titleMap)); + Assert.isTrue(apply.success() && apply.getData().toString().startsWith("amazonTitle"), "失败"); + } + + @Test + void testNumber() { +// ebayManno.price | cal-mul:1.4,int | cal-add:0.99,number_2 + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("ebayManno.price | cal-mul:2,int | cal-add:0.99,number_2"); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success("100")); + Assert.isTrue(apply.success() && apply.getData().toString().equals("200.99"), "失败"); + } + + @Test + void testEcho() { +// PhotoStore.attach | prior-ends-with:m100-8.jpg | echo:wrap + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("ebayManno.price | prior-ends-with:m100-1.4.jpg | echo:wrap"); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.4.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg" + , "http://www.baidu.com/images/K100-1.2.jpg"))); + Assert.isTrue(apply.success() && apply.getData().toString().endsWith("\n"), "失败"); + } + + @Test + void testEchoNone() { + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("ebayManno.price | prior-ends-with:m100-1.5.jpg | echo:wrap"); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg" + , "http://www.baidu.com/images/K100-1.2.jpg"))); + Assert.isTrue(apply.success() && apply.getData().toString().endsWith("\n"), "失败"); + } + + @Test + void testListEcho() { + PipeFilterFactory pipeFilterFactory = PipeFilterFactory.createPipeFilter(null); + pipeFilterFactory.addParams("ebayManno.price | list-echo:wrap"); + val apply = pipeFilterFactory.apply(PipeDataWrapper.success(Arrays.asList("http://www.baidu.com/images/m100-1.1.jpg" + , "http://www.baidu.com/images/m100-1.2.jpg" + , "http://www.baidu.com/images/m100-1.3.jpg" + , "http://www.baidu.com/images/m100-1.5.jpg" + , "http://www.baidu.com/images/K100-1.2.jpg"))); + Assert.isTrue(apply.success(), "失败"); + } + +} From b5507b8ed7108d30bd5462ff0e7298ffc784a938 Mon Sep 17 00:00:00 2001 From: lin feng Date: Wed, 21 Jun 2023 15:22:20 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix=EF=BC=9A=E7=AE=A1=E9=81=93=E5=B7=A5?= =?UTF-8?q?=E5=8E=82=E6=B3=A8=E5=86=8Cfilter=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/excel/write/handler/PipeFilterFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java index c018c2b0..bb7021e6 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/handler/PipeFilterFactory.java @@ -50,7 +50,7 @@ public class PipeFilterFactory extends BasePipeFilter { if (Objects.nonNull(writeContext) && Objects.nonNull(writeContext.writeWorkbookHolder()) && Objects.nonNull(writeContext.writeWorkbookHolder().getWriteWorkbook()) - && PipeFilterUtils.isEmpty(writeContext.writeWorkbookHolder().getWriteWorkbook().getCustomPipeFilterMap())) { + && !PipeFilterUtils.isEmpty(writeContext.writeWorkbookHolder().getWriteWorkbook().getCustomPipeFilterMap())) { PIPE_FILTER_MAP.putAll(writeContext.writeWorkbookHolder().getWriteWorkbook().getCustomPipeFilterMap()); } }