1.下载quartz的sql文件

quartz下载链接

直接download,后解压找到  table_mysql.sql    数据库使用的是mysql数据库 

2.将sql文件导入到需要链接的数据库,得到以下文件

3. 引入quartz的maven依赖

lombok我在代码中有用到,一起加上了

<!-- Lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>
<!-- quartz -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

4.配置 application.properties


spring.datasource.url= jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root



# Quartz
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=never
spring.quartz.properties.scheduler.instanceName=clusteredScheduler
spring.quartz.properties.scheduler.instanceId=AUTO
spring.quartz.properties.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.jobStore.tablePrefix=qrtz_
spring.quartz.properties.jobStore.isClustered=true
spring.quartz.properties.jobStore.clusterCheckinInterval=10000
spring.quartz.properties.jobStore.useProperties=false
spring.quartz.properties.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.threadPool.threadCount=10
spring.quartz.properties.threadPool.threadPriority=5
spring.quartz.properties.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true

5.controller层


@RestController
@RequestMapping("/quartz")
public class QuartzController {

    private final IJobService jobService;

    @Autowired
    public QuartzController(IJobService jobService) {
        this.jobService = jobService;
    }

    @GetMapping("/all")
    public JsonResult queryAllJobs() {
        List<ScheduleJobDTO> list = jobService.listAllJob();
        return JsonResult.ok(list);
    }

    @GetMapping("/running")
    public JsonResult queryRunningJobs() {
        List<ScheduleJobDTO> list = jobService.listRunningJob();
        return JsonResult.ok(list);
    }

    @PostMapping("")
    public JsonResult addJob(@RequestBody ScheduleJobParam param) {
        boolean flag = jobService.addJob(param);
        return flag ? JsonResult.ok() : JsonResult.error("添加失败");
    }

    @PutMapping("/pause")
    public JsonResult<String> pauseJob(@RequestBody ScheduleJobParam param) {
        boolean flag = jobService.pauseJob(param.getJobName(), param.getJobGroup());
        return flag ? JsonResult.ok() : JsonResult.error("停止失败");
    }

    @PutMapping("/resume")
    public JsonResult<String> resumeJob(@RequestBody ScheduleJobParam param) {
        boolean flag = jobService.resumeJob(param.getJobName(), param.getJobGroup());
        return flag ? JsonResult.ok() : JsonResult.error("停止失败");
    }

    @DeleteMapping("")
    public JsonResult<String> deleteJob(@RequestBody ScheduleJobParam param) {
        boolean flag = jobService.deleteJob(param.getJobName(), param.getJobGroup());
        return flag ? JsonResult.ok() : JsonResult.error("删除失败");
    }
}

6.service接口


public interface IJobService {

    /**
     * 查询所有任务列表
     * @return
     */
    List<ScheduleJobDTO> listAllJob();

    /**
     * 获取正在运行的任务列表
     * @return
     */
    List<ScheduleJobDTO> listRunningJob();

    /**
     * 新增任务
     * @param job job
     * @return
     */
    boolean addJob(ScheduleJobParam job);

    /**
     * 执行 job
     * @param jobName jobName
     * @param jobGroupName jobGroupName
     * @return
     */
    boolean triggerJob(String jobName, String jobGroupName);

    /**
     * 启动所有定时任务
     * @return
     */
    boolean startJobs();

    /**
     * 删除任务
     * @param jobName jobName
     * @param jobGroupName jobGroupName
     * @return
     */
    boolean deleteJob(String jobName, String jobGroupName);

    /**
     * 暂停任务
     * @param jobName jobName
     * @param jobGroupName jobGroupName
     * @return
     */
    boolean pauseJob(String jobName, String jobGroupName);

    /**
     * 恢复任务
     * @param jobName jobName
     * @param jobGroupName jobGroupName
     * @return
     */
    boolean resumeJob(String jobName, String jobGroupName);
}

7.service实现


@Service("jobService")
@Slf4j
public class JobServiceImpl implements IJobService {

    public static final String TRIGGER_IDENTITY_PREFIX = "trigger_";


    /**
     * 调度器
     */
    private final Scheduler scheduler;

    @Autowired
    public JobServiceImpl(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    @Override
    public List<ScheduleJobDTO> listAllJob(){
        List<ScheduleJobDTO> result = new ArrayList<>();
        try {
            GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            for (JobKey jobKey : jobKeys) {
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    ScheduleJobDTO scheduleJob = new ScheduleJobDTO();
                    scheduleJob.setJobName(jobKey.getName())
                            .setJobGroup(jobKey.getGroup())
                            .setJobDescription(trigger.getDescription())
                            .setTriggerStatus(scheduler.getTriggerState(trigger.getKey()).ordinal())
                            .setTriggerStatusName(scheduler.getTriggerState(trigger.getKey()).name());

                    result.add(scheduleJob);
                }
            }
        } catch (SchedulerException e) {
            log.error("获取所有任务列表失败,错误:{}", e.getMessage());
        }
        return result;
    }

    @Override
    public List<ScheduleJobDTO> listRunningJob() {
        List<ScheduleJobDTO> result = new ArrayList<>();
        try {
            // 获取列表
            List<JobExecutionContext> executingJobs =  scheduler.getCurrentlyExecutingJobs();

            result = getJobListData(executingJobs);

        } catch (SchedulerException e) {
            log.error("获取运行任务列表失败,错误:{}", e.getMessage());
        }
        return result;
    }

    @Override
    public boolean addJob(ScheduleJobParam jobParam) {
        try {
            // 加载执行类
            Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobParam.getJobClass());
            clazz.newInstance();

            // 1. 创建 job
            JobDetail job = JobBuilder.newJob(clazz)
                    .withIdentity(jobParam.getJobName(), jobParam.getJobGroup())
                    .withDescription(jobParam.getJobDescription())
                    .build();

            JobDataMap jobDataMap = job.getJobDataMap();

            List<Map<String, Object>> data = jobParam.getJobMapData();
            if (data != null && data.size() > 0) {
                data.forEach(jobDataItem -> {
                    jobDataItem.keySet().forEach((key) -> {
                        jobDataMap.put(key, jobDataItem.get(key));
                    });
                });
            }

            // 配置cron运行规则,即执行时间
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobParam.getCronExpression());

            // 2. 创建 Trigger
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(TRIGGER_IDENTITY_PREFIX + jobParam.getJobName(), jobParam.getJobGroup())
                    .startNow()
                    .withSchedule(cronScheduleBuilder)
                    .build();

            // 3. 注册任务和定时器
            scheduler.scheduleJob(job, trigger);
            scheduler.start();
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | SchedulerException e) {
            log.error("添加任务 {} 失败,错误: {}", jobParam.getJobName(), e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public boolean triggerJob(String jobName, String jobGroupName) {
        JobKey key = new JobKey(jobName, jobGroupName);
        try {
            scheduler.triggerJob(key);
        } catch (SchedulerException e) {
            log.error("任务 {} 触发失败", jobName);
            return false;
        }
        return true;
    }

    @Override
    public boolean startJobs() {
        try {
            scheduler.start();
        } catch (SchedulerException e) {
            log.error("启动所有任务失败:", e);
            return false;
        }
        return true;
    }

    @Override
    public boolean deleteJob(String jobName, String jobGroupName) {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
        try {
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 删除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
        } catch (SchedulerException e) {
            log.error("删除任务 {} 失败,错误:{}", jobName, e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public boolean pauseJob(String jobName, String jobGroupName) {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
        try {
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            log.error("停止任务 {} 失败,错误:{}", jobName, e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public boolean resumeJob(String jobName, String jobGroupName) {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            log.error("恢复任务 {} 失败,错误:{}", jobName, e.getMessage());
            return false;
        }
        return true;
    }

    private List<ScheduleJobDTO> getJobListData(List<JobExecutionContext> executingJobs) {
        List<ScheduleJobDTO> result = new ArrayList<>();
        try {
            for (JobExecutionContext jobItem : executingJobs) {
                ScheduleJobDTO  scheduleJobItem = getJobDataByJobExecutionContext(jobItem);
                result.add(scheduleJobItem);
            }
        } catch (SchedulerException e) {
            log.error("获取任务状态失败,错误:{}", e.getMessage());
        }
        return result;
    }

    /**
     * 从 JobExecutionContext 中解析获取数据
     * @param jobContext JobExecutionContext
     * @return
     * @throws SchedulerException
     */
    private ScheduleJobDTO getJobDataByJobExecutionContext(JobExecutionContext jobContext) throws SchedulerException {
        JobDetail jobDetail = jobContext.getJobDetail();
        JobKey jobKey = jobDetail.getKey();
        Trigger trigger = jobContext.getTrigger();
        // 封装 ScheduleJobDTO 返回,想要获取更多的数据(如 JobDataMap)可自行添加
        ScheduleJobDTO scheduleJob = new ScheduleJobDTO();
        scheduleJob.setJobName(jobKey.getName())
                .setJobGroup(jobKey.getGroup())
                .setJobDescription(trigger.getDescription())
                .setTriggerStatus(scheduler.getTriggerState(trigger.getKey()).ordinal())
                .setTriggerStatusName(scheduler.getTriggerState(trigger.getKey()).name());
        return scheduleJob;
    }
}

8.实体类,与数据库和前端页面交互使用

@Data
@Accessors(chain = true)
public class ScheduleJobDTO {

    private String jobName;
    private String jobGroup;
    private String jobDescription;
    private Integer triggerStatus;
    private String triggerStatusName;
}

@Data
@Accessors(chain = true)
public class ScheduleJobParam {

    private String jobName;
    private String jobGroup;
    private String jobClass;
    private String cronExpression;
    private String jobDescription;
    /**
     * 额外的数据
     */
    private List<Map<String, Object>> jobMapData;
}

/**
 * 返回结果对象工具类
 */
public class JsonResult<T> extends HashMap<String, Object> {
    private static final long serialVersionUID = 1L;

    private JsonResult() {
    }

    /**
     * 返回成功
     */
    public static JsonResult ok() {
        return ok("操作成功");
    }

    /**
     * 返回成功
     */
    public static JsonResult ok(Object message) {
        return ok(200, message);
    }

    /**
     * 返回成功
     */
    public static JsonResult ok(int code, Object message) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.put("code", code);
        jsonResult.put("msg", message);
        return jsonResult;
    }


    public static JsonResult<String> error(String message) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.put("code", 500);
        jsonResult.put("msg", message);
        return jsonResult;
    }
}

9.两个测试任务类

public class EatJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        System.out.println(DateUtil.now() + " 这是 吃吃吃 的逻辑执行部分。。。。。。");
    }
}
public class RunJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        System.out.println(DateUtil.now() + " 这是跑跑跑的逻辑执行部分。。。。。。");
    }
}

10.测试

添加 http://127.0.0.1:8900/quartz

 查询 http://127.0.0.1:8900/quartz/all

 停止 http://127.0.0.1:8900/quartz/pause

 恢复/启动  http://127.0.0.1:8900/quartz/resume

请求报文:

注意  jobclass 配置为EatJob的全路径

{
    "jobName": "eat",
    "jobGroup": "dosomething",
    "jobDescription": "吃吃吃",
    "jobClass": "com.seage.demo.quartz.job.EatJob",
    "cronExpression": "0/10 * * * * ? *"
}

 

后台可以看到打印台打印的日志

在添加、停止、重启时都看一下控制台打印,如果不打印或者重新打印说明成功了。

11.遇到的问题

控制台打印找不到类路径,说明  jobClass没找到任务类

查看数据库表  qrtz_job_details 的JOB_CLASS_NAME配置错误

org.quartz.JobPersistenceException: Couldn't retrieve job because a required class was not found: com.seage.demo.quartz.job1.EatJob

 

 

更多推荐