最近接到一个需求,用户要能配置一个定时循环的任务,就是和手机闹钟循环差不多,设置好比如周一、周二、周三,那么在这几天内这个任务就需要自动执行
需求不复杂,首先我需要判断当前是周几,当然用户说了让我看手机闹钟的循环规则,我看了下还有法定工作日和法定节假日这些
所以我们先写个工具类来判断当前日期是否需要执行
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.MonthDay;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Sakura
* @date 2024/6/20 9:48
*/
public class SchedulerTaskUtil {
public enum RepeatCycle {
DAILY, // 每天
MONTHLY, // 每月
HOLIDAYS, // 法定节假日
WORKDAYS, // 法定工作日
MONDAY, // 周一
TUESDAY, // 周二
WEDNESDAY, // 周三
THURSDAY, // 周四
FRIDAY, // 周五
SATURDAY, // 周六
SUNDAY // 周日
}
private static final Set<MonthDay> HOLIDAYS = new HashSet<>();
static {
// 初始化法定节假日 2024 这个需要定期维护有些麻烦
HOLIDAYS.add(MonthDay.of(1, 1)); // 元旦
HOLIDAYS.add(MonthDay.of(2, 10)); // 春节
HOLIDAYS.add(MonthDay.of(2, 11)); // 春节
HOLIDAYS.add(MonthDay.of(2, 12)); // 春节
HOLIDAYS.add(MonthDay.of(2, 13)); // 春节
HOLIDAYS.add(MonthDay.of(2, 14)); // 春节
HOLIDAYS.add(MonthDay.of(2, 15)); // 春节
HOLIDAYS.add(MonthDay.of(2, 16)); // 春节
HOLIDAYS.add(MonthDay.of(2, 17)); // 春节
HOLIDAYS.add(MonthDay.of(4, 4)); // 清明节
HOLIDAYS.add(MonthDay.of(4, 5)); // 清明节
HOLIDAYS.add(MonthDay.of(4, 6)); // 清明节
HOLIDAYS.add(MonthDay.of(5, 1)); // 劳动节
HOLIDAYS.add(MonthDay.of(5, 2)); // 劳动节
HOLIDAYS.add(MonthDay.of(5, 3)); // 劳动节
HOLIDAYS.add(MonthDay.of(5, 4)); // 劳动节
HOLIDAYS.add(MonthDay.of(5, 5)); // 劳动节
HOLIDAYS.add(MonthDay.of(6, 8)); // 端午节
HOLIDAYS.add(MonthDay.of(6, 9)); // 端午节
HOLIDAYS.add(MonthDay.of(6, 10)); // 端午节
HOLIDAYS.add(MonthDay.of(9, 15)); // 中秋节
HOLIDAYS.add(MonthDay.of(9, 16)); // 中秋节
HOLIDAYS.add(MonthDay.of(9, 17)); // 中秋节
HOLIDAYS.add(MonthDay.of(10, 1)); // 国庆节
HOLIDAYS.add(MonthDay.of(10, 2)); // 国庆节
HOLIDAYS.add(MonthDay.of(10, 3)); // 国庆节
HOLIDAYS.add(MonthDay.of(10, 4)); // 国庆节
HOLIDAYS.add(MonthDay.of(10, 5)); // 国庆节
HOLIDAYS.add(MonthDay.of(10, 6)); // 国庆节
HOLIDAYS.add(MonthDay.of(10, 7)); // 国庆节
// 其他假日可以继续添加
}
private Set<RepeatCycle> repeatCycles;
public SchedulerTaskUtil(String repeatCyclesStr) {
this.repeatCycles = Arrays.stream(repeatCyclesStr.split(","))
.map(String::trim)
.map(String::toUpperCase)
.map(RepeatCycle::valueOf)
.collect(Collectors.toSet());
}
public boolean shouldExecuteToday() {
LocalDate today = LocalDate.now();
DayOfWeek dayOfWeek = today.getDayOfWeek();
MonthDay monthDay = MonthDay.from(today);
if (repeatCycles.contains(RepeatCycle.DAILY)) {
return true;
}
if (repeatCycles.contains(RepeatCycle.MONTHLY) && today.getDayOfMonth() == 1) {
return true;
}
if (repeatCycles.contains(RepeatCycle.HOLIDAYS) && HOLIDAYS.contains(monthDay)) {
return true;
}
if (repeatCycles.contains(RepeatCycle.WORKDAYS) && !HOLIDAYS.contains(monthDay)
&& dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY) {
return true;
}
if (repeatCycles.contains(RepeatCycle.MONDAY) && dayOfWeek == DayOfWeek.MONDAY) {
return true;
}
if (repeatCycles.contains(RepeatCycle.TUESDAY) && dayOfWeek == DayOfWeek.TUESDAY) {
return true;
}
if (repeatCycles.contains(RepeatCycle.WEDNESDAY) && dayOfWeek == DayOfWeek.WEDNESDAY) {
return true;
}
if (repeatCycles.contains(RepeatCycle.THURSDAY) && dayOfWeek == DayOfWeek.THURSDAY) {
return true;
}
if (repeatCycles.contains(RepeatCycle.FRIDAY) && dayOfWeek == DayOfWeek.FRIDAY) {
return true;
}
if (repeatCycles.contains(RepeatCycle.SATURDAY) && dayOfWeek == DayOfWeek.SATURDAY) {
return true;
}
if (repeatCycles.contains(RepeatCycle.SUNDAY) && dayOfWeek == DayOfWeek.SUNDAY) {
return true;
}
return false;
}
public static void main(String[] args) {
// 示例:任务在周一和周三执行
String repeatCyclesStr = "MONDAY,WEDNESDAY";
SchedulerTaskUtil scheduler = new SchedulerTaskUtil(repeatCyclesStr);
if (scheduler.shouldExecuteToday()) {
System.out.println("Today is a repeat day, generate the task.");
// 生成任务的逻辑
} else {
System.out.println("Today is not a repeat day.");
}
}
}
执行一下测试方法
显示今天不是需要重复的一天,因为今天星期四
给它加上周四
再执行就对了
剩下的就好说了,我们只需要加一个定时器就可以
import com.yokea.pro.task.mapper.TaskMapper;
import com.yokea.pro.task.model.po.Task;
import com.yokea.pro.task.util.SchedulerTaskUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author Sakura
* @date 2024/06/20 15:24
*/
@Component
@EnableScheduling
@Slf4j
public class ScheduledTask {
// 每隔1分钟执行一次:0 */1 * * * ?
// 每天22点执行一次:0 0 22 * * ?
// 每月1号凌晨1点执行一次:0 0 1 1 * ?
// 每月最后一天23点执行一次:0 0 23 L * ?
// 每周周六凌晨3点实行一次:0 0 3 ? * L
// 在24分、30分执行一次:0 24,30 * * * ?
@Autowired
private TaskMapper taskMapper;
/**
* @description: 每天凌晨开始生成周期循环任务
* @author: Sakura
* @date: 2024/06/20 16:27
*/
@Scheduled(cron = "0 0 0 * * ?") // 0 0 0 * * ? 每天0点启动
@Async
public void recurrentTasks() {
log.info("定时生成周期循环任务程序启动——————————————————————————————————————————");
try {
// 先获取需要循环启动的周期任务
List<Task> periodicTaskList = taskMapper.getPeriodicTaskList();
for (Task task : periodicTaskList) {
// 判断当前任务当天是否需要重复执行
SchedulerTaskUtil schedulerTask = new SchedulerTaskUtil(task.getCycle());
if (schedulerTask.shouldExecuteToday()) {
log.info("定时生成周期循环任务程序启动,任务ID:{}", task.getId());
}
}
} catch (Exception e) {
log.error("定时生成周期循环任务程序启动", e);
}
}
}