mirror of https://github.com/alibaba/easyexcel
41 changed files with 2109 additions and 21 deletions
@ -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<String> getVariable(String cellValue) { |
||||
|
||||
List<String> 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; |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,82 @@
|
||||
package com.alibaba.excel.write.handler; |
||||
|
||||
import java.util.*; |
||||
|
||||
/** |
||||
* Description: |
||||
* pipeline filter |
||||
* |
||||
* @author linfeng |
||||
*/ |
||||
public abstract class BasePipeFilter<T, R> implements PipeFilter<T, R> { |
||||
|
||||
private final List<String> filterParams = new ArrayList<>(); |
||||
protected int rowIndex; |
||||
protected int columnIndex; |
||||
|
||||
/** |
||||
* filter name |
||||
* |
||||
* @return filter name |
||||
*/ |
||||
protected abstract String filterName(); |
||||
|
||||
protected boolean isValidity(PipeDataWrapper<R> 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<String> params() { |
||||
return filterParams; |
||||
} |
||||
|
||||
/** |
||||
* add param |
||||
* |
||||
* @param params collection |
||||
* @return filter |
||||
*/ |
||||
public BasePipeFilter<T, R> addParams(String... params) { |
||||
params().addAll(Arrays.asList(params)); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* set excel cell |
||||
* |
||||
* @param row row index |
||||
* @param column column index |
||||
* @return 过滤器 |
||||
*/ |
||||
public BasePipeFilter<T, R> setCell(int row, int column) { |
||||
this.rowIndex = row; |
||||
this.columnIndex = column; |
||||
return this; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* verify |
||||
* |
||||
* @param wrapper data |
||||
* @return true |
||||
*/ |
||||
protected boolean verify(PipeDataWrapper<T> wrapper) { |
||||
return Objects.nonNull(wrapper) && wrapper.success(); |
||||
} |
||||
} |
@ -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<R> implements Serializable { |
||||
private int status; |
||||
private String message; |
||||
private R data; |
||||
|
||||
public static <R> PipeDataWrapper<R> success(R data) { |
||||
return new PipeDataWrapper<>(200, "OK", data); |
||||
} |
||||
|
||||
public static <R> PipeDataWrapper<R> error(String error, R data) { |
||||
return new PipeDataWrapper<>(500, error, data); |
||||
} |
||||
|
||||
public static <R> PipeDataWrapper<R> error(String error) { |
||||
return new PipeDataWrapper<>(500, error, null); |
||||
} |
||||
|
||||
public boolean success() { |
||||
return status == 200; |
||||
} |
||||
} |
@ -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<T, R> extends Function<PipeDataWrapper<T>, PipeDataWrapper<R>> { |
||||
|
||||
/** |
||||
* apply |
||||
* |
||||
* @param wrapper the function argument |
||||
* @return data wrapper |
||||
*/ |
||||
@Override |
||||
PipeDataWrapper<R> apply(PipeDataWrapper<T> wrapper); |
||||
|
||||
/** |
||||
* filter params collection |
||||
* |
||||
* @return params collection |
||||
*/ |
||||
List<String> params(); |
||||
|
||||
/** |
||||
* add param to pipe filter |
||||
* |
||||
* @param params param |
||||
* @return pipe filter |
||||
*/ |
||||
default PipeFilter<T, R> addParams(String... params) { |
||||
params().addAll(Arrays.asList(params)); |
||||
return this; |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
private static final Map<String, Supplier<BasePipeFilter<Object, Object>>> 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<Object> apply(PipeDataWrapper<Object> 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<BasePipeFilter<Object, Object>> 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<BasePipeFilter<Object, Object>> supplier = PIPE_FILTER_MAP.get(filterName); |
||||
if (Objects.isNull(supplier)) { |
||||
throw new ExcelRuntimeException(String.format("No pipeline filter for [%s]", filterName)); |
||||
} |
||||
BasePipeFilter<Object, Object> 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<Object>, PipeDataWrapper<Object>> currFilter = pipeFilterList.get(0); |
||||
for (int i = 1; i < pipeFilterList.size(); i++) { |
||||
currFilter = currFilter.andThen(pipeFilterList.get(i)); |
||||
} |
||||
PipeDataWrapper<Object> 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"; |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
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<Object> apply(PipeDataWrapper<Object> 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<Object> 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; |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
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; |
||||
} |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
/** |
||||
* 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<Object> apply(PipeDataWrapper<Object> 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<Object> 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<Object> moreParamsHandle(Object value) { |
||||
List<Object> result = new ArrayList<>(); |
||||
List<String> error = new ArrayList<>(); |
||||
for (String center : params()) { |
||||
if (Objects.isNull(center)) { |
||||
continue; |
||||
} |
||||
PipeDataWrapper<Object> 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<Object> instructHandle(Object value, String center) { |
||||
|
||||
if (value instanceof Collection) { |
||||
String result = null; |
||||
//noinspection unchecked
|
||||
Collection<Object> collection = (Collection<Object>) 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<Object, Object> colMap = (Map<Object, Object>) value; |
||||
for (Map.Entry<Object, Object> 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()); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -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<Object> moreParamsHandle(Object value) { |
||||
for (String center : params()) { |
||||
if (Objects.isNull(center)) { |
||||
continue; |
||||
} |
||||
PipeDataWrapper<Object> 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()))); |
||||
} |
||||
|
||||
} |
@ -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"; |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
private static final String DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss"; |
||||
|
||||
@Override |
||||
protected String filterName() { |
||||
return "date-format"; |
||||
} |
||||
|
||||
@Override |
||||
public PipeDataWrapper<Object> apply(PipeDataWrapper<Object> 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"); |
||||
} |
||||
} |
@ -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"; |
||||
} |
||||
} |
@ -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<Object> apply(PipeDataWrapper<Object> 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); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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<Object> apply(PipeDataWrapper<Object> 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<Object> collection = (List<Object>) 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))); |
||||
|
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
/** |
||||
* 参数格式 list-index:n n表示下标,从1开始 |
||||
* |
||||
* @param wrapper the function argument |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public PipeDataWrapper<Object> apply(PipeDataWrapper<Object> 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<Object> collection = (List<Object>) 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<String> 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"; |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
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<Object> apply(PipeDataWrapper<Object> 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<Object> collection = (List<Object>) 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<String> 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"; |
||||
} |
||||
} |
@ -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"; |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
private static final int PARAMS_NUM = 3; |
||||
|
||||
@Override |
||||
protected String filterName() { |
||||
return "replace"; |
||||
} |
||||
|
||||
@Override |
||||
public PipeDataWrapper<Object> apply(PipeDataWrapper<Object> 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"); |
||||
} |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
private static final int PARAMS_NUM = 2; |
||||
|
||||
@Override |
||||
protected String filterName() { |
||||
return "substring"; |
||||
} |
||||
|
||||
@Override |
||||
public PipeDataWrapper<Object> apply(PipeDataWrapper<Object> 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"); |
||||
} |
||||
} |
||||
} |
@ -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"; |
||||
} |
||||
} |
@ -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<Object, Object> { |
||||
|
||||
@Override |
||||
public PipeDataWrapper<Object> apply(PipeDataWrapper<Object> 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<Object> valList = (Collection<Object>) 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"; |
||||
} |
||||
} |
@ -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<FillData> dataPipe() { |
||||
List<FillData> 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<String, Object> 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(), "失败"); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue