add methods

This commit is contained in:
Looly 2022-03-21 01:55:49 +08:00
parent 4fbda4565a
commit 8718e6dfe1
12 changed files with 269 additions and 169 deletions

View File

@ -13,6 +13,7 @@
* 【core 】 【可能兼容问题】Base58分离编码和解码
* 【core 】 【可能兼容问题】Base62分离编码和解码增加inverted模式支持
* 【core 】 【兼容问题 】PunyCode参数由String改为Charsequence
* 【cron 】 【可能兼容问题】SimpleValueParser改名为AbsValueParser改为abstract
### 🐣新特性
* 【http 】 HttpRequest.form采用TableMap方式issue#I4W427@Gitee

View File

@ -1,51 +1,109 @@
package cn.hutool.cron.pattern.matcher;
package cn.hutool.cron.pattern.parser;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.parser.DayOfMonthValueParser;
import cn.hutool.cron.pattern.parser.ValueParser;
import cn.hutool.cron.pattern.parser.YearValueParser;
import cn.hutool.cron.pattern.matcher.AlwaysTrueValueMatcher;
import cn.hutool.cron.pattern.matcher.BoolArrayValueMatcher;
import cn.hutool.cron.pattern.matcher.ValueMatcher;
import java.util.ArrayList;
import java.util.List;
/**
* {@link ValueMatcher} 构建器用于构建表达式中每一项的匹配器
* @author Looly
* 简易值转换器将给定String值转为int并限定最大值和最小值<br>
* 此类同时识别{@code L} 为最大值
*
* @author Looly
*/
public class ValueMatcherBuilder {
public abstract class AbsValueParser implements ValueParser {
/**
* 最小值包括
*/
protected int min;
/**
* 最大值包括
*/
protected int max;
/**
* 构造
*
* @param min 最小值包括
* @param max 最大值包括
*/
public AbsValueParser(int min, int max) {
if (min > max) {
this.min = max;
this.max = min;
} else {
this.min = min;
this.max = max;
}
}
@Override
public int parse(String value) throws CronException {
if ("L".equalsIgnoreCase(value)) {
// L表示最大值
return max;
}
int i;
try {
i = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new CronException(e, "Invalid integer value: '{}'", value);
}
if (i < min || i > max) {
throw new CronException("Value {} out of range: [{} , {}]", i, min, max);
}
return i;
}
@Override
public int getMin() {
return this.min;
}
@Override
public int getMax() {
return this.max;
}
/**
* 处理定时任务表达式每个时间字段<br>
* 多个时间使用逗号分隔
*
* @param value 某个时间字段
* @param parser 针对这个时间字段的解析器
* @return List
*/
public static ValueMatcher build(String value, ValueParser parser) {
@Override
public ValueMatcher parseAsValueMatcher(String value) {
if (isMatchAllStr(value)) {
//兼容Quartz的"?"表达式不会出现互斥情况"*"作用相同
return new AlwaysTrueValueMatcher();
}
List<Integer> values = parseArray(value, parser);
List<Integer> values = parseArray(value);
if (values.size() == 0) {
throw new CronException("Invalid field: [{}]", value);
}
if (parser instanceof DayOfMonthValueParser) {
//考虑每月的天数不同且存在闰年情况日匹配单独使用
return new DayOfMonthValueMatcher(values);
}else if(parser instanceof YearValueParser){
//考虑年数字太大不适合boolean数组单独使用列表遍历匹配
return new YearValueMatcher(values);
}else {
return new BoolArrayValueMatcher(values);
return buildValueMatcher(values);
}
/**
* 根据解析的数字值列表构建{@link ValueMatcher}<br>
* 默认为{@link BoolArrayValueMatcher}如果有特殊实现子类须重写此方法
*
* @param values 数字值列表
* @return {@link ValueMatcher}
*/
protected ValueMatcher buildValueMatcher(List<Integer> values){
return new BoolArrayValueMatcher(values);
}
/**
@ -56,15 +114,14 @@ public class ValueMatcherBuilder {
* <li><strong>a,b,c,d</strong></li>
* </ul>
* @param value 子表达式值
* @param parser 针对这个字段的解析器
* @return 值列表
*/
private static List<Integer> parseArray(String value, ValueParser parser){
private List<Integer> parseArray(String value){
final List<Integer> values = new ArrayList<>();
final List<String> parts = StrUtil.split(value, StrUtil.C_COMMA);
for (String part : parts) {
CollUtil.addAllIfNotContains(values, parseStep(part, parser));
CollUtil.addAllIfNotContains(values, parseStep(part));
}
return values;
}
@ -79,22 +136,21 @@ public class ValueMatcherBuilder {
* </ul>
*
* @param value 表达式值
* @param parser 针对这个时间字段的解析器
* @return List
*/
private static List<Integer> parseStep(String value, ValueParser parser) {
private List<Integer> parseStep(String value) {
final List<String> parts = StrUtil.split(value, StrUtil.C_SLASH);
int size = parts.size();
List<Integer> results;
if (size == 1) {// 普通形式
results = parseRange(value, -1, parser);
results = parseRange(value, -1);
} else if (size == 2) {// 间隔形式
final int step = parser.parse(parts.get(1));
final int step = parse(parts.get(1));
if (step < 1) {
throw new CronException("Non positive divisor for field: [{}]", value);
}
results = parseRange(parts.get(0), step, parser);
results = parseRange(parts.get(0), step);
} else {
throw new CronException("Invalid syntax of field: [{}]", value);
}
@ -113,18 +169,17 @@ public class ValueMatcherBuilder {
*
* @param value 范围表达式
* @param step 步进
* @param parser 针对这个时间字段的解析器
* @return List
*/
private static List<Integer> parseRange(String value, int step, ValueParser parser) {
private List<Integer> parseRange(String value, int step) {
final List<Integer> results = new ArrayList<>();
// 全部匹配形式
if (value.length() <= 2) {
//根据步进的第一个数字确定起始时间类似于 12/3则从12分等开始
int minValue = parser.getMin();
int minValue = getMin();
if(false == isMatchAllStr(value)) {
minValue = Math.max(minValue, parser.parse(value));
minValue = Math.max(minValue, parse(value));
}else {
//在全匹配模式下如果步进不存在表示步进为1
if(step < 1) {
@ -132,7 +187,7 @@ public class ValueMatcherBuilder {
}
}
if(step > 0) {
final int maxValue = parser.getMax();
final int maxValue = getMax();
if(minValue > maxValue) {
throw new CronException("Invalid value {} > {}", minValue, maxValue);
}
@ -151,15 +206,15 @@ public class ValueMatcherBuilder {
List<String> parts = StrUtil.split(value, '-');
int size = parts.size();
if (size == 1) {// 普通值
final int v1 = parser.parse(value);
final int v1 = parse(value);
if(step > 0) {//类似 20/2的形式
NumberUtil.appendRange(v1, parser.getMax(), step, results);
NumberUtil.appendRange(v1, getMax(), step, results);
}else {
results.add(v1);
}
} else if (size == 2) {// range值
final int v1 = parser.parse(parts.get(0));
final int v2 = parser.parse(parts.get(1));
final int v1 = parse(parts.get(0));
final int v2 = parse(parts.get(1));
if(step < 1) {
//在range模式下如果步进不存在表示步进为1
step = 1;
@ -167,10 +222,10 @@ public class ValueMatcherBuilder {
if (v1 < v2) {// 正常范围例如2-5
NumberUtil.appendRange(v1, v2, step, results);
} else if (v1 > v2) {// 逆向范围反选模式例如5-2
NumberUtil.appendRange(v1, parser.getMax(), step, results);
NumberUtil.appendRange(parser.getMin(), v2, step, results);
NumberUtil.appendRange(v1, getMax(), step, results);
NumberUtil.appendRange(getMin(), v2, step, results);
} else {// v1 == v2此时与单值模式一致
NumberUtil.appendRange(v1, parser.getMax(), step, results);
NumberUtil.appendRange(v1, getMax(), step, results);
}
} else {
throw new CronException("Invalid syntax of field: [{}]", value);

View File

@ -5,7 +5,6 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.AlwaysTrueValueMatcher;
import cn.hutool.cron.pattern.matcher.MatcherTable;
import cn.hutool.cron.pattern.matcher.ValueMatcherBuilder;
import java.util.List;
@ -78,55 +77,40 @@ public class CronPatternParser {
throw new CronException("Pattern [{}] is invalid, it must be 5-7 parts!", pattern);
}
//
if (1 == offset) {// 支持秒的表达式
try {
matcherTable.secondMatchers.add(ValueMatcherBuilder.build(parts[0], SECOND_VALUE_PARSER));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'second' field error!", pattern);
}
} else {// 不支持秒的表达式则第一位按照表达式生成时间的秒数赋值表示整分匹配
matcherTable.secondMatchers.add(ValueMatcherBuilder.build(String.valueOf(DateUtil.date().second()), SECOND_VALUE_PARSER));
}
// 如果不支持秒的表达式则第一位按照表达式生成时间的秒数赋值表示整分匹配
final String secondPart = (1 == offset) ? parts[0] : String.valueOf(DateUtil.date().second());
parseToTable(SECOND_VALUE_PARSER, secondPart);
//
try {
matcherTable.minuteMatchers.add(ValueMatcherBuilder.build(parts[offset], MINUTE_VALUE_PARSER));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'minute' field error!", pattern);
}
// 小时
try {
matcherTable.hourMatchers.add(ValueMatcherBuilder.build(parts[1 + offset], HOUR_VALUE_PARSER));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'hour' field error!", pattern);
}
// 每月第几天
try {
matcherTable.dayOfMonthMatchers.add(ValueMatcherBuilder.build(parts[2 + offset], DAY_OF_MONTH_VALUE_PARSER));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'day of month' field error!", pattern);
}
parseToTable(MINUTE_VALUE_PARSER, parts[offset]);
//
parseToTable(HOUR_VALUE_PARSER, parts[1 + offset]);
//
parseToTable(DAY_OF_MONTH_VALUE_PARSER, parts[2 + offset]);
//
try {
matcherTable.monthMatchers.add(ValueMatcherBuilder.build(parts[3 + offset], MONTH_VALUE_PARSER));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'month' field error!", pattern);
}
// 星期几
try {
matcherTable.dayOfWeekMatchers.add(ValueMatcherBuilder.build(parts[4 + offset], DAY_OF_WEEK_VALUE_PARSER));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'day of week' field error!", pattern);
}
parseToTable(MONTH_VALUE_PARSER, parts[3 + offset]);
//
parseToTable(DAY_OF_WEEK_VALUE_PARSER, parts[4 + offset]);
//
if (parts.length == 7) {// 支持年的表达式
try {
matcherTable.yearMatchers.add(ValueMatcherBuilder.build(parts[6], YEAR_VALUE_PARSER));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'year' field error!", pattern);
}
parseToTable(YEAR_VALUE_PARSER, parts[6]);
} else {// 不支持年的表达式全部匹配
matcherTable.yearMatchers.add(new AlwaysTrueValueMatcher());
}
}
/**
* 将表达式解析后加入到{@link #matcherTable}
*
* @param valueParser 表达式解析器
* @param patternPart 表达式部分
*/
private void parseToTable(ValueParser valueParser, String patternPart) {
valueParser.parseTo(this.matcherTable, patternPart);
}
}

View File

@ -1,6 +1,11 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.DayOfMonthValueMatcher;
import cn.hutool.cron.pattern.matcher.MatcherTable;
import cn.hutool.cron.pattern.matcher.ValueMatcher;
import java.util.List;
/**
* 每月的几号值处理<br>
@ -9,8 +14,11 @@ import cn.hutool.cron.CronException;
* @author Looly
*
*/
public class DayOfMonthValueParser extends SimpleValueParser {
public class DayOfMonthValueParser extends AbsValueParser {
/**
* 构造
*/
public DayOfMonthValueParser() {
super(1, 31);
}
@ -23,4 +31,19 @@ public class DayOfMonthValueParser extends SimpleValueParser {
return super.parse(value);
}
}
@Override
public void parseTo(MatcherTable matcherTable, String pattern) {
try {
matcherTable.dayOfMonthMatchers.add(parseAsValueMatcher(pattern));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'day of month' field error!", pattern);
}
}
@Override
protected ValueMatcher buildValueMatcher(List<Integer> values) {
//考虑每月的天数不同且存在闰年情况日匹配单独使用
return new DayOfMonthValueMatcher(values);
}
}

View File

@ -1,6 +1,7 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.MatcherTable;
/**
* 星期值处理<br>
@ -9,7 +10,7 @@ import cn.hutool.cron.CronException;
*
* @author Looly
*/
public class DayOfWeekValueParser extends SimpleValueParser {
public class DayOfWeekValueParser extends AbsValueParser {
/**
* Weeks aliases.
@ -33,6 +34,15 @@ public class DayOfWeekValueParser extends SimpleValueParser {
}
}
@Override
public void parseTo(MatcherTable matcherTable, String pattern) {
try {
matcherTable.dayOfWeekMatchers.add(parseAsValueMatcher(pattern));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'day of week' field error!", pattern);
}
}
/**
* 解析别名
*

View File

@ -1,15 +1,26 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.MatcherTable;
/**
* 小时值处理<br>
* 小时被限定在0-23
*
* @author Looly
*/
public class HourValueParser extends SimpleValueParser {
public class HourValueParser extends AbsValueParser {
public HourValueParser() {
super(0, 23);
}
@Override
public void parseTo(MatcherTable matcherTable, String pattern) {
try {
matcherTable.hourMatchers.add(parseAsValueMatcher(pattern));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'hour' field error!", pattern);
}
}
}

View File

@ -1,15 +1,29 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.MatcherTable;
/**
* 分钟值处理<br>
* 限定于0-59
*
* @author Looly
*/
public class MinuteValueParser extends SimpleValueParser {
public class MinuteValueParser extends AbsValueParser {
/**
* 构造
*/
public MinuteValueParser() {
super(0, 59);
}
@Override
public void parseTo(MatcherTable matcherTable, String pattern) {
try {
matcherTable.minuteMatchers.add(parseAsValueMatcher(pattern));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'minute' field error!", pattern);
}
}
}

View File

@ -1,6 +1,7 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.MatcherTable;
/**
* 月份值处理<br>
@ -8,7 +9,7 @@ import cn.hutool.cron.CronException;
*
* @author Looly
*/
public class MonthValueParser extends SimpleValueParser {
public class MonthValueParser extends AbsValueParser {
/**
* Months aliases.
@ -28,6 +29,15 @@ public class MonthValueParser extends SimpleValueParser {
}
}
@Override
public void parseTo(MatcherTable matcherTable, String pattern) {
try {
matcherTable.monthMatchers.add(parseAsValueMatcher(pattern));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'month' field error!", pattern);
}
}
/**
* 解析别名
*

View File

@ -1,5 +1,8 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.MatcherTable;
/**
* 秒值处理<br>
* 限定于0-59
@ -7,4 +10,13 @@ package cn.hutool.cron.pattern.parser;
* @author Looly
*/
public class SecondValueParser extends MinuteValueParser {
@Override
public void parseTo(MatcherTable matcherTable, String pattern) {
try {
matcherTable.secondMatchers.add(parseAsValueMatcher(pattern));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'second' field error!", pattern);
}
}
}

View File

@ -1,66 +0,0 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
/**
* 简易值转换器将给定String值转为int并限定最大值和最小值<br>
* 此类同时识别{@code L} 为最大值
*
* @author Looly
*/
public class SimpleValueParser implements ValueParser {
/**
* 最小值包括
*/
protected int min;
/**
* 最大值包括
*/
protected int max;
/**
* 构造
*
* @param min 最小值包括
* @param max 最大值包括
*/
public SimpleValueParser(int min, int max) {
if (min > max) {
this.min = max;
this.max = min;
} else {
this.min = min;
this.max = max;
}
}
@Override
public int parse(String value) throws CronException {
if ("L".equalsIgnoreCase(value)) {
// L表示最大值
return max;
}
int i;
try {
i = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new CronException(e, "Invalid integer value: '{}'", value);
}
if (i < min || i > max) {
throw new CronException("Value {} out of range: [{} , {}]", i, min, max);
}
return i;
}
@Override
public int getMin() {
return this.min;
}
@Override
public int getMax() {
return this.max;
}
}

View File

@ -1,5 +1,8 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.pattern.matcher.MatcherTable;
import cn.hutool.cron.pattern.matcher.ValueMatcher;
/**
* 值处理接口<br>
* 值处理用于限定表达式中相应位置的值范围并转换表达式值为int值
@ -8,6 +11,28 @@ package cn.hutool.cron.pattern.parser;
*/
public interface ValueParser {
/**
* 解析表达式后加入到{@link MatcherTable}的对应列表中
*
* @param matcherTable {@link MatcherTable}
* @param pattern 对应时间部分的表达式
*/
void parseTo(MatcherTable matcherTable, String pattern);
/**
* 解析表达式对应部分为{@link ValueMatcher}支持的表达式包括
* <ul>
* <li>单值或通配符形式 <strong>a</strong> <strong>*</strong></li>
* <li>数组形式 <strong>1,2,3</strong></li>
* <li>间隔形式 <strong>a&#47;b</strong> <strong>*&#47;b</strong></li>
* <li>范围形式 <strong>3-8</strong></li>
* </ul>
*
* @param pattern 对应时间部分的表达式
* @return {@link ValueMatcher}
*/
ValueMatcher parseAsValueMatcher(String pattern);
/**
* 处理String值并转为int<br>
* 转换包括

View File

@ -1,15 +1,36 @@
package cn.hutool.cron.pattern.parser;
import cn.hutool.cron.CronException;
import cn.hutool.cron.pattern.matcher.MatcherTable;
import cn.hutool.cron.pattern.matcher.ValueMatcher;
import cn.hutool.cron.pattern.matcher.YearValueMatcher;
import java.util.List;
/**
* 年值处理<br>
* 年的限定在1970-2099年
*
* @author Looly
*/
public class YearValueParser extends SimpleValueParser {
public class YearValueParser extends AbsValueParser {
public YearValueParser() {
super(1970, 2099);
}
@Override
public void parseTo(MatcherTable matcherTable, String pattern) {
try {
matcherTable.yearMatchers.add(parseAsValueMatcher(pattern));
} catch (Exception e) {
throw new CronException(e, "Invalid pattern [{}], parsing 'year' field error!", pattern);
}
}
@Override
protected ValueMatcher buildValueMatcher(List<Integer> values) {
//考虑年数字太大不适合boolean数组单独使用列表遍历匹配
return new YearValueMatcher(values);
}
}