diff --git a/pom.xml b/pom.xml
index 8b41280..843a0c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.7.18
+ 2.4.5
com.bonus
@@ -61,6 +61,13 @@
lombok
provided
+
+
+
+ org.springframework.boot
+ spring-boot-starter-quartz
+
+
diff --git a/src/main/java/com/bonus/emergencyrap/constant/ScheduleConstants.java b/src/main/java/com/bonus/emergencyrap/constant/ScheduleConstants.java
index dbb566a..6cf53a3 100644
--- a/src/main/java/com/bonus/emergencyrap/constant/ScheduleConstants.java
+++ b/src/main/java/com/bonus/emergencyrap/constant/ScheduleConstants.java
@@ -3,7 +3,7 @@ package com.bonus.emergencyrap.constant;
/**
* 任务调度通用常量
*
- * @author ruoyi
+ * @author bonus
*/
public class ScheduleConstants
{
diff --git a/src/main/java/com/bonus/emergencyrap/task/config/QuartzConfig.java b/src/main/java/com/bonus/emergencyrap/task/config/QuartzConfig.java
new file mode 100644
index 0000000..a8b7eb3
--- /dev/null
+++ b/src/main/java/com/bonus/emergencyrap/task/config/QuartzConfig.java
@@ -0,0 +1,43 @@
+package com.bonus.emergencyrap.task.config;
+
+
+import org.quartz.Scheduler;
+import org.quartz.spi.JobFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.scheduling.quartz.SpringBeanJobFactory;
+
+import java.util.Properties;
+
+@Configuration
+public class QuartzConfig {
+
+ @Bean
+ public JobFactory jobFactory() {
+ return new SpringBeanJobFactory();
+ }
+
+ @Bean
+ public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {
+ SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
+ schedulerFactoryBean.setJobFactory(jobFactory);
+
+ // 配置Quartz使用内存存储
+ Properties properties = new Properties();
+ properties.setProperty("org.quartz.scheduler.instanceName", "MyScheduler");
+ properties.setProperty("org.quartz.scheduler.instanceId", "AUTO");
+ properties.setProperty("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore");
+ properties.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
+ properties.setProperty("org.quartz.threadPool.threadCount", "5");
+
+ schedulerFactoryBean.setQuartzProperties(properties);
+ return schedulerFactoryBean;
+ }
+
+ @Bean
+ public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) throws Exception {
+ return schedulerFactoryBean.getScheduler();
+ }
+}
diff --git a/src/main/java/com/bonus/emergencyrap/task/job/ActuatorJob.java b/src/main/java/com/bonus/emergencyrap/task/job/ActuatorJob.java
new file mode 100644
index 0000000..1d0e6e9
--- /dev/null
+++ b/src/main/java/com/bonus/emergencyrap/task/job/ActuatorJob.java
@@ -0,0 +1,42 @@
+package com.bonus.emergencyrap.task.job;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.bonus.emergencyrap.constant.TextConstants;
+import com.bonus.emergencyrap.utils.TextFileUtils;
+import com.bonus.emergencyrap.utils.UploadFile;
+import com.bonus.emergencyrap.vo.TaskVo;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+
+/**
+ * 执行任务定时器
+ */
+@Component
+@Slf4j
+public class ActuatorJob implements Job {
+ private static final Logger logger = LoggerFactory.getLogger(ActuatorJob.class);
+
+ @Override
+ public void execute(JobExecutionContext context) throws JobExecutionException {
+ String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+ log.info(context.getTrigger().getJobDataMap().get("taskId").toString());
+ String taskId = context.getTrigger().getJobDataMap().get("taskId").toString();
+ //文件进行解析
+ String filePtah= UploadFile.getFilePath(TextConstants.TASK);
+ Map map= TextFileUtils.readFileMaps(filePtah);
+ TaskVo vo= JSON.parseObject(map.get(taskId), TaskVo.class);
+ System.err.println(vo.getTaskName());
+ logger.info("SampleJob 执行时间: {}", currentTime);
+ logger.info("任务执行器开始执行,执行任务id=="+vo.getTaskId()+"任务名称是=="+vo.getTaskName()+"执行时间=="+vo.getCorn());
+ }
+}
diff --git a/src/main/java/com/bonus/emergencyrap/task/job/ScanJob.java b/src/main/java/com/bonus/emergencyrap/task/job/ScanJob.java
new file mode 100644
index 0000000..16b786d
--- /dev/null
+++ b/src/main/java/com/bonus/emergencyrap/task/job/ScanJob.java
@@ -0,0 +1,62 @@
+package com.bonus.emergencyrap.task.job;
+
+import com.alibaba.fastjson2.JSON;
+import com.bonus.emergencyrap.constant.TextConstants;
+import com.bonus.emergencyrap.task.service.QuartzJobService;
+import com.bonus.emergencyrap.utils.TextFileUtils;
+import com.bonus.emergencyrap.utils.UploadFile;
+import com.bonus.emergencyrap.vo.TaskVo;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobDataMap;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 定时任务扫描
+ */
+@Slf4j
+@Component
+public class ScanJob implements Job {
+
+ @Autowired
+ private QuartzJobService service;
+
+ @Override
+ public void execute(JobExecutionContext context) throws JobExecutionException {
+ try {
+ String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+ System.err.println(currentTime);
+ String filePtah= UploadFile.getFilePath(TextConstants.TASK);
+ //文件是否存在
+ boolean isCz= TextFileUtils.exists(filePtah);
+ if(isCz){
+ //文件进行解析
+ Map map=TextFileUtils.readFileMaps(filePtah);
+ for (String key : map.keySet()) {
+ TaskVo vo= JSON.parseObject(map.get(key), TaskVo.class);
+ String status=vo.getStatus();
+ //关闭直接删除
+ if("0".equals(status)){
+ service.deleteJob(vo);
+ }else{
+ //添加或者修改定时任务
+ service.addTask(vo);
+ }
+ }
+ }
+ System.err.println(context.getTrigger().getJobDataMap().get("taskId"));
+ log.info("定时任务扫描中scan....");
+ } catch (Exception e) {
+ throw new JobExecutionException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/bonus/emergencyrap/task/runner/JobInitializer.java b/src/main/java/com/bonus/emergencyrap/task/runner/JobInitializer.java
new file mode 100644
index 0000000..a5fa4a1
--- /dev/null
+++ b/src/main/java/com/bonus/emergencyrap/task/runner/JobInitializer.java
@@ -0,0 +1,27 @@
+package com.bonus.emergencyrap.task.runner;
+
+
+import com.bonus.emergencyrap.task.service.QuartzJobService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JobInitializer implements CommandLineRunner {
+ private static final Logger logger = LoggerFactory.getLogger(JobInitializer.class);
+
+ @Autowired
+ private QuartzJobService quartzJobService;
+
+ @Override
+ public void run(String... args) throws Exception {
+ try {
+ // 启动定时任务
+ quartzJobService.startSampleJob();
+ } catch (Exception e) {
+ logger.error("启动定时任务失败", e);
+ }
+ }
+}
diff --git a/src/main/java/com/bonus/emergencyrap/task/service/QuartzJobService.java b/src/main/java/com/bonus/emergencyrap/task/service/QuartzJobService.java
new file mode 100644
index 0000000..c523f91
--- /dev/null
+++ b/src/main/java/com/bonus/emergencyrap/task/service/QuartzJobService.java
@@ -0,0 +1,179 @@
+package com.bonus.emergencyrap.task.service;
+import com.alibaba.fastjson2.JSON;
+import com.bonus.emergencyrap.task.job.ActuatorJob;
+import com.bonus.emergencyrap.task.job.ScanJob;
+
+import com.bonus.emergencyrap.vo.TaskVo;
+import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+
+
+@Service
+public class QuartzJobService {
+ private static final Logger logger = LoggerFactory.getLogger(QuartzJobService.class);
+
+ @Autowired
+ private Scheduler scheduler;
+
+ // 从配置文件读取简单间隔时间(秒)
+ @Value("${task.interval.seconds}")
+ private int taskIntervalSeconds;
+
+ public static String defeatGroup="EmergencyRap";
+
+
+
+ // 固定任务 用来扫描全部的定时任务
+ public void startSampleJobWithSimpleTrigger() throws SchedulerException {
+ // 定义任务
+ JobDetail jobDetail = JobBuilder.newJob(ScanJob.class)
+ .usingJobData("taskId","555555555555")
+ .withIdentity("scanJob", "scanJobGroup")
+ .withDescription("扫描器")
+ .storeDurably()
+ .build();
+
+ // 调度任务
+ if (!scheduler.checkExists(jobDetail.getKey())) {
+ // 从配置文件获取间隔时间,创建触发器
+ Trigger trigger = TriggerBuilder.newTrigger()
+ .withIdentity("scanJobTrigger", "scanJobGroup")
+ .usingJobData("taskId","555555555555")
+ .withDescription("扫描器")
+ .startNow()
+ .withSchedule(SimpleScheduleBuilder.simpleSchedule()
+ .withIntervalInSeconds(taskIntervalSeconds)
+ .repeatForever())
+ .build();
+ scheduler.scheduleJob(jobDetail, trigger);
+ logger.info("已启动任务扫描,间隔时间: {}秒", taskIntervalSeconds);
+ } else {
+ logger.info("任务已存在,无需重复启动");
+ }
+ }
+
+
+ // 使用cron表达式调度
+ public void addTask(TaskVo vo) throws SchedulerException {
+ // 定义任务
+ JobDetail jobDetail = JobBuilder.newJob(ActuatorJob.class)
+ .withIdentity(vo.getTaskId(), defeatGroup)
+ .withDescription("Cron定时任务")
+ .storeDurably()
+ .build();
+ // 调度任务
+ if (!scheduler.checkExists(jobDetail.getKey())) {
+ Trigger trigger = TriggerBuilder.newTrigger()
+ .withIdentity(vo.getTaskId(), defeatGroup)
+ .usingJobData("taskId",vo.getTaskId())
+ .withDescription(vo.getCorn())
+ .startNow()
+ .withSchedule(CronScheduleBuilder.cronSchedule(vo.getCorn()))
+ .build();
+ scheduler.scheduleJob(jobDetail, trigger);
+ logger.info("已启动Cron任务,表达式: {}", vo.getCorn());
+ } else {
+ updateJobTime(vo);
+ logger.info("Cron任务已存在,进行定时任务时间更新");
+ }
+ }
+
+
+
+ // 启动示例任务
+ public void startSampleJob() throws SchedulerException {
+ // 可以根据需要选择启动哪种类型的任务
+ startSampleJobWithSimpleTrigger();
+ }
+
+ // 暂停任务
+ public void pauseJob(String jobName, String jobGroup) throws SchedulerException {
+ JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
+ if (scheduler.checkExists(jobKey)) {
+ scheduler.pauseJob(jobKey);
+ logger.info("已暂停任务: {}:{}", jobGroup, jobName);
+ }
+ }
+
+ // 恢复任务
+ public void resumeJob(String jobName, String jobGroup) throws SchedulerException {
+ JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
+ if (scheduler.checkExists(jobKey)) {
+ scheduler.resumeJob(jobKey);
+ logger.info("已恢复任务: {}:{}", jobGroup, jobName);
+ }
+ }
+
+ // 删除任务
+ public void deleteJob(TaskVo vo) throws SchedulerException {
+ JobKey jobKey = JobKey.jobKey(vo.getTaskId(), defeatGroup);
+ if (scheduler.checkExists(jobKey)) {
+ scheduler.deleteJob(jobKey);
+ logger.info("已删除任务: {}:{}", defeatGroup, vo.getTaskId());
+ }
+ }
+
+ // 删除任务
+ public void deleteJob(String jobName, String jobGroup) throws SchedulerException {
+ JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
+ if (scheduler.checkExists(jobKey)) {
+ scheduler.deleteJob(jobKey);
+ logger.info("已删除任务: {}:{}", jobGroup, jobName);
+ }
+ }
+
+ /**
+ * 更新当前正在运行的任务的cron时间
+ * @param
+ * @param
+ */
+ private void updateJobTime(TaskVo vo) throws SchedulerException {
+ // 获取当前触发器
+ TriggerKey triggerKey = TriggerKey.triggerKey(vo.getTaskId(), defeatGroup);
+ CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
+ String oldTime = cronTrigger.getCronExpression();
+ if (!oldTime.equalsIgnoreCase(vo.getCorn())) {
+ logger.info("定时任务已更新old和新的定时任务: {}:{}:{}", vo.getTaskName(),oldTime,vo.getCorn() );
+ Trigger trigger = TriggerBuilder.newTrigger()
+ .withIdentity(vo.getTaskId(), defeatGroup)
+ .usingJobData("taskId",vo.getTaskId())
+ .withDescription(vo.getCorn())
+ .startNow()
+ .withSchedule(CronScheduleBuilder.cronSchedule(vo.getCorn()))
+ .build();
+ //重置对应的job
+ scheduler.rescheduleJob(triggerKey, trigger);
+ }
+
+ }
+
+ // 刷新简单任务的执行间隔
+ public void refreshSimpleJob(String jobName, String jobGroup, int newIntervalSeconds) throws SchedulerException {
+ JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
+ if (!scheduler.checkExists(jobKey)) {
+ throw new SchedulerException("任务不存在: " + jobGroup + ":" + jobName);
+ }
+ // 获取当前触发器
+ TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
+ Trigger oldTrigger = scheduler.getTrigger(triggerKey);
+
+ // 创建新的触发器
+ Trigger newTrigger = TriggerBuilder.newTrigger()
+ .withIdentity(triggerKey)
+ .forJob(jobKey)
+ .startNow()
+ .withSchedule(SimpleScheduleBuilder.simpleSchedule()
+ .withIntervalInSeconds(newIntervalSeconds)
+ .repeatForever())
+ .build();
+
+ // 替换触发器
+ scheduler.rescheduleJob(triggerKey, newTrigger);
+ logger.info("已刷新简单任务 [{}:{}] 的执行间隔为 {} 秒",
+ jobGroup, jobName, newIntervalSeconds);
+ }
+}
diff --git a/src/main/java/com/bonus/emergencyrap/vo/TaskVo.java b/src/main/java/com/bonus/emergencyrap/vo/TaskVo.java
index d842601..f7a92bd 100644
--- a/src/main/java/com/bonus/emergencyrap/vo/TaskVo.java
+++ b/src/main/java/com/bonus/emergencyrap/vo/TaskVo.java
@@ -93,5 +93,15 @@ public class TaskVo {
*/
private String isLogin;
+ /**
+ * 0 关闭 1 启用
+ */
+ private String status;
+ /**
+ * 定时任务表达式
+ */
+ private String corn;
+
+
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index d0b3196..e1e6625 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -62,6 +62,10 @@ token:
# 令牌有效期(默认30分钟)
expireTime: 30
+task:
+ interval:
+ seconds: 60
+