mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add PartBuilder
This commit is contained in:
parent
6bcdce2d20
commit
4ad131777d
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.cron.pattern;
|
||||
|
||||
import org.dromara.hutool.core.lang.builder.Builder;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.text.StrJoiner;
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
/**
|
||||
* 定时任务表达式构建器
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public class CronPatternBuilder implements Builder<String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
final String[] parts = new String[7];
|
||||
|
||||
/**
|
||||
* 创建构建器
|
||||
* @return CronPatternBuilder
|
||||
*/
|
||||
public static CronPatternBuilder of() {
|
||||
return new CronPatternBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置值
|
||||
*
|
||||
* @param part 部分,如秒、分、时等
|
||||
* @param values 时间值列表
|
||||
* @return this
|
||||
*/
|
||||
public CronPatternBuilder setValues(final Part part, final int... values) {
|
||||
for (final int value : values) {
|
||||
part.checkValue(value);
|
||||
}
|
||||
return set(part, ArrayUtil.join(values, ","));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置区间
|
||||
*
|
||||
* @param part 部分,如秒、分、时等
|
||||
* @param begin 起始值
|
||||
* @param end 结束值
|
||||
* @return this
|
||||
*/
|
||||
public CronPatternBuilder setRange(final Part part, final int begin, final int end) {
|
||||
Assert.notNull(part );
|
||||
part.checkValue(begin);
|
||||
part.checkValue(end);
|
||||
return set(part, StrUtil.format("{}-{}", begin, end));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对应部分的定时任务值
|
||||
*
|
||||
* @param part 部分,如秒、分、时等
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public CronPatternBuilder set(final Part part, final String value) {
|
||||
parts[part.ordinal()] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
for (int i = Part.MINUTE.ordinal(); i < Part.YEAR.ordinal(); i++) {
|
||||
// 从分到周,用户未设置使用默认值
|
||||
// 秒和年如果不设置,忽略之
|
||||
if(StrUtil.isBlank(parts[i])){
|
||||
parts[i] = "*";
|
||||
}
|
||||
}
|
||||
|
||||
return StrJoiner.of(StrUtil.SPACE)
|
||||
.setNullMode(StrJoiner.NullMode.IGNORE)
|
||||
.append(this.parts)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -36,12 +36,33 @@ import java.util.Calendar;
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public enum Part {
|
||||
/**
|
||||
* 秒[0-59]
|
||||
*/
|
||||
SECOND(Calendar.SECOND, 0, 59),
|
||||
/**
|
||||
* 分[0-59]
|
||||
*/
|
||||
MINUTE(Calendar.MINUTE, 0, 59),
|
||||
/**
|
||||
* 时[0-23]
|
||||
*/
|
||||
HOUR(Calendar.HOUR_OF_DAY, 0, 23),
|
||||
/**
|
||||
* 日[1-31]
|
||||
*/
|
||||
DAY_OF_MONTH(Calendar.DAY_OF_MONTH, 1, 31),
|
||||
/**
|
||||
* 月[1-12]
|
||||
*/
|
||||
MONTH(Calendar.MONTH, Month.JANUARY.getValueBaseOne(), Month.DECEMBER.getValueBaseOne()),
|
||||
/**
|
||||
* 周中的天,如周一、周日等,[0-6]即[SUNDAY-SATURDAY]
|
||||
*/
|
||||
DAY_OF_WEEK(Calendar.DAY_OF_WEEK, Week.SUNDAY.ordinal(), Week.SATURDAY.ordinal()),
|
||||
/**
|
||||
* 年[1970-2099]
|
||||
*/
|
||||
YEAR(Calendar.YEAR, 1970, 2099);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.cron.pattern.builder;
|
||||
|
||||
import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.dromara.hutool.core.collection.ListUtil;
|
||||
import org.dromara.hutool.core.lang.builder.Builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Cron表达式的分片构建器
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface PartBuilder extends Builder<String> {
|
||||
|
||||
/**
|
||||
* 始终匹配
|
||||
*
|
||||
* @return Always
|
||||
*/
|
||||
static Always always() {
|
||||
return Always.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 始终匹配
|
||||
*/
|
||||
class Always implements PartBuilder {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 始终匹配
|
||||
*/
|
||||
public static final Always INSTANCE = new Always();
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
return "*";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 固定值
|
||||
*/
|
||||
class On implements PartBuilder {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param value 值
|
||||
*/
|
||||
public On(final int value) {
|
||||
this(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param value 值
|
||||
*/
|
||||
public On(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 区间表达式
|
||||
*/
|
||||
class Range implements PartBuilder {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String start;
|
||||
private final String end;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param start 起始值(包含)
|
||||
* @param end 结束值(包含)
|
||||
*/
|
||||
public Range(final int start, final int end) {
|
||||
this(String.valueOf(start), String.valueOf(end));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param start 起始值(包含)
|
||||
* @param end 结束值(包含)
|
||||
*/
|
||||
public Range(final String start, final String end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
return start + "-" + end;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 逻辑与表达式
|
||||
*/
|
||||
class And implements PartBuilder {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<PartBuilder> builders;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param values 值列表
|
||||
*/
|
||||
public And(final int... values) {
|
||||
this.builders = new ArrayList<>(values.length);
|
||||
for (final int value : values) {
|
||||
this.builders.add(new On(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param builders 表达式列表
|
||||
*/
|
||||
public And(final PartBuilder... builders) {
|
||||
this.builders = ListUtil.of(builders);
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加表达式
|
||||
*
|
||||
* @param builder 表达式
|
||||
* @return this
|
||||
*/
|
||||
public And and(final PartBuilder builder) {
|
||||
this.builders.add(builder);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
return CollUtil.join(builders, ",", PartBuilder::build);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 每隔指定步长<br>
|
||||
* 如 5/3,表示每3步取一次,即5,8,11,14,17...
|
||||
*/
|
||||
class Every implements PartBuilder {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final PartBuilder partBuilder;
|
||||
private final int step;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param step 步长
|
||||
*/
|
||||
public Every(final int step) {
|
||||
this(PartBuilder.always(), step);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param partBuilder 表达式
|
||||
* @param step 步长
|
||||
*/
|
||||
public Every(final PartBuilder partBuilder, final int step) {
|
||||
this.partBuilder = partBuilder;
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
final String build = partBuilder.build();
|
||||
if ("*".equals(build) && 1 == step) {
|
||||
return build;
|
||||
}
|
||||
return build + "/" + step;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.cron.pattern.builder;
|
||||
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.lang.builder.Builder;
|
||||
import org.dromara.hutool.core.text.StrJoiner;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
import org.dromara.hutool.cron.pattern.Part;
|
||||
|
||||
/**
|
||||
* 定时任务表达式构建器
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.8.0
|
||||
*/
|
||||
public class PatternBuilder implements Builder<String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
final String[] parts = new String[7];
|
||||
|
||||
/**
|
||||
* 创建构建器
|
||||
* @return CronPatternBuilder
|
||||
*/
|
||||
public static PatternBuilder of() {
|
||||
return new PatternBuilder();
|
||||
}
|
||||
|
||||
// region ----- set
|
||||
/**
|
||||
* 设置值
|
||||
*
|
||||
* @param part 部分,如秒、分、时等
|
||||
* @param values 时间值列表
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setValues(final Part part, final int... values) {
|
||||
for (final int value : values) {
|
||||
part.checkValue(value);
|
||||
}
|
||||
return set(part, new PartBuilder.And(values));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置区间
|
||||
*
|
||||
* @param part 部分,如秒、分、时等
|
||||
* @param begin 起始值
|
||||
* @param end 结束值
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setRange(final Part part, final int begin, final int end) {
|
||||
Assert.notNull(part);
|
||||
part.checkValue(begin);
|
||||
part.checkValue(end);
|
||||
return set(part, new PartBuilder.Range(begin, end));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置年对应部分的定时任务值
|
||||
*
|
||||
* @param value 表达式值,如"*"、"2024,2025"、"2015-2025"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setYear(final PartBuilder value) {
|
||||
return set(Part.YEAR, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置周中的天对应部分的定时任务值
|
||||
*
|
||||
* @param value 表达式值,如"Sun"、"7"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setDayOfWeek(final PartBuilder value) {
|
||||
return set(Part.DAY_OF_WEEK, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置月份对应部分的定时任务值
|
||||
*
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setMonth(final PartBuilder value) {
|
||||
return set(Part.MONTH, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置日对应部分的定时任务值
|
||||
*
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setDayOfMonth(final PartBuilder value) {
|
||||
return set(Part.DAY_OF_MONTH, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置时对应部分的定时任务值
|
||||
*
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setHour(final PartBuilder value) {
|
||||
return set(Part.HOUR, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置分对应部分的定时任务值
|
||||
*
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setMinute(final PartBuilder value) {
|
||||
return set(Part.MINUTE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置秒对应部分的定时任务值
|
||||
*
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder setSecond(final PartBuilder value) {
|
||||
return set(Part.SECOND, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对应部分的定时任务值
|
||||
*
|
||||
* @param part 部分,如秒、分、时等
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder set(final Part part, final PartBuilder value) {
|
||||
return set(part, ObjUtil.apply(value, PartBuilder::build));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对应部分的定时任务值
|
||||
*
|
||||
* @param part 部分,如秒、分、时等
|
||||
* @param value 表达式值,如"*"、"1,2"、"5-12"等
|
||||
* @return this
|
||||
*/
|
||||
public PatternBuilder set(final Part part, final String value) {
|
||||
parts[part.ordinal()] = value;
|
||||
return this;
|
||||
}
|
||||
// endregion
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
for (int i = Part.MINUTE.ordinal(); i < Part.YEAR.ordinal(); i++) {
|
||||
// 从分到周,用户未设置使用默认值
|
||||
// 秒和年如果不设置,忽略之
|
||||
if(StrUtil.isBlank(parts[i])){
|
||||
parts[i] = "*";
|
||||
}
|
||||
}
|
||||
|
||||
return StrJoiner.of(StrUtil.SPACE)
|
||||
.setNullMode(StrJoiner.NullMode.IGNORE)
|
||||
.append(this.parts)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 模式构建器
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
package org.dromara.hutool.cron.pattern.builder;
|
@ -14,34 +14,52 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.cron.pattern;
|
||||
package org.dromara.hutool.cron.pattern.builder;
|
||||
|
||||
import org.dromara.hutool.cron.CronException;
|
||||
import org.dromara.hutool.cron.pattern.Part;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class CronPatternBuilderTest {
|
||||
public class PatternBuilderTest {
|
||||
|
||||
@Test
|
||||
public void buildMatchAllTest(){
|
||||
String build = CronPatternBuilder.of().build();
|
||||
String build = PatternBuilder.of().build();
|
||||
Assertions.assertEquals("* * * * *", build);
|
||||
|
||||
build = CronPatternBuilder.of()
|
||||
build = PatternBuilder.of()
|
||||
.set(Part.SECOND, "*")
|
||||
.build();
|
||||
Assertions.assertEquals("* * * * * *", build);
|
||||
|
||||
build = CronPatternBuilder.of()
|
||||
build = PatternBuilder.of()
|
||||
.set(Part.SECOND, "*")
|
||||
.set(Part.YEAR, "*")
|
||||
.build();
|
||||
Assertions.assertEquals("* * * * * * *", build);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMatchAllTest2(){
|
||||
String build = PatternBuilder.of().build();
|
||||
Assertions.assertEquals("* * * * *", build);
|
||||
|
||||
build = PatternBuilder.of()
|
||||
.setSecond(PartBuilder.always())
|
||||
.build();
|
||||
Assertions.assertEquals("* * * * * *", build);
|
||||
|
||||
build = PatternBuilder.of()
|
||||
.setSecond(PartBuilder.always())
|
||||
.setYear(PartBuilder.always())
|
||||
.build();
|
||||
Assertions.assertEquals("* * * * * * *", build);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildRangeTest(){
|
||||
final String build = CronPatternBuilder.of()
|
||||
final String build = PatternBuilder.of()
|
||||
.set(Part.SECOND, "*")
|
||||
.setRange(Part.HOUR, 2, 9)
|
||||
.build();
|
||||
@ -51,7 +69,7 @@ public class CronPatternBuilderTest {
|
||||
@Test
|
||||
public void buildRangeErrorTest(){
|
||||
Assertions.assertThrows(CronException.class, ()->{
|
||||
final String build = CronPatternBuilder.of()
|
||||
final String build = PatternBuilder.of()
|
||||
.set(Part.SECOND, "*")
|
||||
// 55无效值
|
||||
.setRange(Part.HOUR, 2, 55)
|
||||
@ -59,4 +77,32 @@ public class CronPatternBuilderTest {
|
||||
Assertions.assertEquals("* * 2-9 * * *", build);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildValuesTest(){
|
||||
final String build = PatternBuilder.of()
|
||||
.setSecond(PartBuilder.always())
|
||||
.setValues(Part.HOUR, 2, 9, 12)
|
||||
.build();
|
||||
Assertions.assertEquals("* * 2,9,12 * * *", build);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildOnTest(){
|
||||
final String build = PatternBuilder.of()
|
||||
.setSecond(PartBuilder.always())
|
||||
.setHour(new PartBuilder.On(12))
|
||||
.build();
|
||||
Assertions.assertEquals("* * 12 * * *", build);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void buildEveryTest(){
|
||||
final String build = PatternBuilder.of()
|
||||
.setSecond(PartBuilder.always())
|
||||
.setHour(new PartBuilder.Every(2))
|
||||
.build();
|
||||
Assertions.assertEquals("* * */2 * * *", build);
|
||||
}
|
||||
}
|
@ -14,10 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.cron.pattern;
|
||||
package org.dromara.hutool.cron.pattern.parser;
|
||||
|
||||
import org.dromara.hutool.cron.pattern.matcher.PatternMatcher;
|
||||
import org.dromara.hutool.cron.pattern.parser.PatternParser;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
Loading…
x
Reference in New Issue
Block a user