1. 工具类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* Cron工具类
* 注意:此工具类异常都不处理,没有进行参数校验,
* 调用方自行处理异常
*/
@Slf4j
public class JobCronUtil {
private static final String EMPTY = "";
private static final String SPACE = " ";
private static final String COMMA = ",";
private static final String HORIZONTAL_LINE = "-";
private static final String STAR = "*";
private static final String QUESTION_MARK = "?";
private static final String FORWARD_SLASH = "/";
private static final String POUND = "#";
private JobCronUtil() {
}
/**
* Model转成cron表达式
*/
public static String getCron(CronModel cronModel) {
log.debug("获取cron表达式参数 cronModel => {}", cronModel);
/*
* 指定时间点
*/
if (JobType.TIME.equals(cronModel.getJobType())) {
return getTimeCron(cronModel);
}
// 每隔几天
else if (JobType.DAY.equals(cronModel.getJobType())) {
return getDayCron(cronModel);
}
// 每隔几周
else if (JobType.WEEK.equals(cronModel.getJobType())) {
return getWeekCron(cronModel);
}
// 每隔几月的哪几个日期的时间点
else if (JobType.MONTH_DAY.equals(cronModel.getJobType())) {
return getMonthDayCron(cronModel);
}
// 每隔几月的第几个周几时间点
else if (JobType.MONTH_WEEK.equals(cronModel.getJobType())) {
return getMonthWeekCron(cronModel);
}
// 每隔几年
else if (JobType.YEAR.equals(cronModel.getJobType())) {
return getYearCron(cronModel);
}
// 任务类型配置错误
else {
log.error("任务类型配置错误");
return null;
}
}
/**
* 指定时间点cron
* 秒 分 时 日 月 周 年
* 0 15 10 05 08 ? 2023
* 2023-08-05 10:15:00
*/
private static String getTimeCron(CronModel cronModel) {
return cronModel.getSecond() + SPACE +
cronModel.getMinute() + SPACE +
cronModel.getHour() + SPACE +
cronModel.getDayOfMonths()[0] + SPACE +
cronModel.getMonths()[0] + SPACE +
QUESTION_MARK + SPACE +
cronModel.getYear();
}
/**
* 每隔几天时间点cron
*/
private static String getDayCron(CronModel cronModel) {
// 秒 分 时 日 月 周
// 0 15 10 */2 * ?
// 每隔2天的10:15:00秒执行
return cronModel.getSecond() + SPACE +
cronModel.getMinute() + SPACE +
cronModel.getHour() + SPACE +
STAR + handleBeApart(cronModel) + SPACE +
STAR + SPACE +
QUESTION_MARK;
}
/**
* 每隔几周时间点cron
* 周 是 1-7 或 SUN-SAT , - * ? / L #
* 秒 分 时 日 月 周
* 0 15 10 ? * 1,3/2
* 每隔2天的10:15:00秒执行
*/
private static String getWeekCron(CronModel cronModel) {
return cronModel.getSecond() + SPACE +
cronModel.getMinute() + SPACE +
cronModel.getHour() + SPACE +
QUESTION_MARK + SPACE +
STAR + SPACE +
arr2Str(cronModel.getDayOfWeeks()) + FORWARD_SLASH + cronModel.getBeApart();
}
/**
* 每隔几月的哪几个日期的时间点
*/
private static String getMonthDayCron(CronModel cronModel) {
// 每隔几月的哪几个日期的时间点
// 秒 分 时 日 月 周
// 0 15 10 1,2,5,8 */2 ?
// 每隔2个月的1,2,5,8号10:15:00秒执行
return cronModel.getSecond() + SPACE +
cronModel.getMinute() + SPACE +
cronModel.getHour() + SPACE +
arr2Str(cronModel.getDayOfMonths()) + SPACE +
STAR + handleBeApart(cronModel) + SPACE +
QUESTION_MARK;
}
/**
* 每隔几月的哪几个日期的时间点
*/
private static String getMonthWeekCron(CronModel cronModel) {
// 每隔几月的第几个周几时间点
// 秒 分 时 日 月 周
// 0 15 10 ? */2 1#3
// 每隔2个月的第三个周日10:15:00秒执行
return cronModel.getSecond() + SPACE +
cronModel.getMinute() + SPACE +
cronModel.getHour() + SPACE +
QUESTION_MARK + SPACE +
STAR + handleBeApart(cronModel) + SPACE +
cronModel.getDayOfWeek() + POUND + cronModel.getWeekOfMonth();
}
/**
* 每隔几年的时间点
*/
private static String getYearCron(CronModel cronModel) {
// 每隔几年的时间点
// 秒 分 时 日 月 周 年
// 0 15 10 10 1 ? */2
// 每隔2个月的第三个周日10:15:00秒执行
return cronModel.getSecond() + SPACE +
cronModel.getMinute() + SPACE +
cronModel.getHour() + SPACE +
arr2Str(cronModel.getDayOfMonths()) + SPACE +
arr2Str(cronModel.getMonths()) + SPACE +
QUESTION_MARK + SPACE +
STAR + handleBeApart(cronModel);
}
private static String arr2Str(Integer[] arr) {
if (checkNumberContinuous(arr)) {
int min = Arrays.stream(arr).min(Integer::compareTo).orElse(0);
int max = Arrays.stream(arr).max(Integer::compareTo).orElse(0);
return min + HORIZONTAL_LINE + max;
}
StringBuilder sb = new StringBuilder();
for (Integer num : arr) {
sb.append(num).append(COMMA);
}
return sb.substring(0, sb.length() - 1);
}
/**
* 检查数组是否连续的
*/
private static boolean checkNumberContinuous(Integer[] arr) {
List<Integer> list = Arrays.stream(arr).sorted().collect(Collectors.toList());
int min = list.get(0);
for (Integer value : list) {
if (min != value) {
return false;
}
min += 1;
}
return true;
}
private static String handleBeApart(CronModel cronModel) {
return cronModel.getBeApart() == 1 ? EMPTY : (FORWARD_SLASH + cronModel.getBeApart());
}
/**
* Cron类别
*/
@AllArgsConstructor
public enum JobType {
/**
* 固定时间
*/
TIME(0, "固定时间"),
/**
* 每隔几天
*/
DAY(1, "天"),
/**
* 每隔几周
*/
WEEK(2, "周"),
/**
* 每隔几月的哪几个日期的时间点
*/
MONTH_DAY(3, "月按日期"),
/**
* 每隔几月的第几个周几时间点
*/
MONTH_WEEK(4, "月按星期"),
/**
* 每隔几年
*/
YEAR(5, "年");
@Getter
private final Integer value;
@Getter
private final String name;
}
/**
* Cron表达式对象
* [秒] [分] [时] [日] [月] [周] [年]
* 域 是否必填 值以及范围 通配符
* 秒 是 0-59 , - * /
* 分 是 0-59 , - * /
* 时 是 0-23 , - * /
* 日 是 1-31 , - * ? / L W
* 月 是 1-12 或 JAN-DEC , - * /
* 周 是 1-7 或 SUN-SAT , - * ? / L #
* 年 否 1970-2099 , - * /
* <p>
* # 表示每月的第几个周几,只能作用于 “周” 上。例如 ”2#3” 表示第三个周一。
*/
@Data
public static class CronModel {
/**
* 类型
*/
JobType jobType;
/**
* 间隔
*/
Integer beApart;
/**
* 秒
*/
Integer second;
/**
* 分
*/
Integer minute;
/**
* 时
*/
Integer hour;
/**
* 日
*/
Integer[] dayOfMonths;
/**
* 月
*/
Integer[] months;
/**
* 周
*/
Integer[] dayOfWeeks;
/**
* 第几个
*/
Integer weekOfMonth;
/**
* 周几
*/
Integer dayOfWeek;
/**
* 年
*/
Integer year;
}
}
2. 使用方式
可以自己通过构造CronModel来生成想要的cron
JobCronUtil.CronModel cronModel = new JobCronUtil.CronModel();
// 定时任务类别
cronModel.setJobType(JobCronUtil.JobType.TIME);
// 间隔
cronModel.setBeApart(1);
// 时间
LocalDateTime dateTime = LocalDateTime.now();
// 秒
cronModel.setSecond(dateTime.getSecond());
// 分
cronModel.setMinute(dateTime.getMinute());
// 时
cronModel.setHour(dateTime.getHour());
// 日
cronModel.setDayOfMonths(new Integer[]{dateTime.getDayOfMonth()});
// 月
cronModel.setMonths(new Integer[]{dateTime.getMonthValue()});
// 年
cronModel.setYear(dateTime.getYear());
String cron = JobCronUtil.getCron(cronModel);