# boot-quartz **Repository Path**: liang-tian-yu/boot-quartz ## Basic Information - **Project Name**: boot-quartz - **Description**: quartz - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-26 - **Last Updated**: 2025-06-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## spring-boot-starter-quartz ### 设计 - 系统表设计 ``` create table sys_quartz_job ( id varchar(32) comment 'id' primary key, jobClass varchar(64) not null comment '任务类名', cron varchar(64) not null comment 'cron表达式', params varchar(512) null comment '参数', description varchar(128) null comment '任务描述', status tinyint default 0 not null comment '任务状态 0-正常 1-暂停', createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间', updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间' ) comment '定时任务'; ``` 方法设计 - 查询定时任务 - 添加定时任务 - 更新定时任务 - 暂停定时任务 - 恢复定时任务 - 删除定时任务 - 立即执行一次任务 - 启动后应该自动将正常任务注册 添加定时任务->暂停定时任务->立即执行一次任务->恢复定时任务->->删除定时任务 (测试流程) --- ### 代码实现 - 添加依赖 ``` org.springframework.boot spring-boot-starter-quartz ``` - 配置 ``` spring: # 定时任务 quartz: # 任务信息存储至数据库 job-store-type: jdbc jdbc: # 自动生成表,若已有表数据请务必关闭,第一次可选ALWAYS(ALWAYS/EMBEDDED/NEVER) initialize-schema: NEVER properties: org: quartz: scheduler: # 允许调度程序节点一次获取(触发)的最大触发器数 batchTriggerAcquisitionMaxCount: 5 jobStore: # 加锁调度 acquireTriggersWithinLock: true # “容忍”触发器经过下一次触发时间的毫秒数 misfireThreshold: 10000 ``` - 启动类加 ``` @EnableScheduling ``` - 实体类 ``` package com.lty.model.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.time.LocalDateTime; /** * 定时任务 */ @Data @TableName("sys_quartz_job") public class QuartzJob { /** * id */ @TableId(type = IdType.ASSIGN_UUID) private String id; /** * 任务类名 */ private String jobClass; /** * Cron表达式 */ private String cron; /** * 参数 */ private String params; /** * 任务描述 */ private String description; /** * 任务状态(0-正常,1-暂停) */ private Integer status; /** * 创建时间 */ private LocalDateTime createTime; /** * 更新时间 */ private LocalDateTime updateTime; } ``` - 常量 ``` package com.lty.constant; /** * 定时任务常量 */ public class QuartzJobConstant { /** * 定时任务状态-正常 */ public static final Integer JOB_STATUS_NORMAL = 0; /** * 定时任务状态-暂停 */ public static final Integer JOB_STATUS_PAUSED = 1; /** * 定时任务组-默认 */ public static final String JOB_GROUP_DEFAULT = "JOB_GROUP"; /** * 定时任务参数-任务参数key */ public static final String JOB_PARAMS_KEY = "params"; } ``` MapperXML ``` ``` Mapper ``` package com.lty.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.lty.model.entity.QuartzJob; public interface QuartzJobMapper extends BaseMapper { } ``` Service ``` package com.lty.service; import com.baomidou.mybatisplus.extension.service.IService; import com.lty.model.entity.QuartzJob; import org.quartz.SchedulerException; public interface QuartzJobService extends IService { /** * 添加定时任务 */ void addJob(QuartzJob job) throws SchedulerException; /** * 更新定时任务 */ void updateJob(QuartzJob job) throws SchedulerException; /** * 删除定时任务 */ void deleteJob(String jobId) throws SchedulerException; /** * 暂停定时任务 */ void pauseJob(String jobId) throws SchedulerException; /** * 恢复定时任务 */ void resumeJob(String jobId) throws SchedulerException; /** * 立即执行定时任务 */ void runJobNow(String jobId) throws SchedulerException; } ``` ServiceImpl ``` package com.lty.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.lty.mapper.QuartzJobMapper; import com.lty.model.entity.QuartzJob; import com.lty.service.QuartzJobService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.quartz.CronExpression; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.Job; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Objects; @Slf4j @Service @RequiredArgsConstructor @Transactional public class QuartzJobServiceImpl extends ServiceImpl implements QuartzJobService { private final Scheduler scheduler; @Override public void addJob(QuartzJob job) throws SchedulerException { // 1. 验证Cron表达式 if (!CronExpression.isValidExpression(job.getCron())) { throw new IllegalArgumentException("无效的Cron表达式: " + job.getCron()); } // 2. 创建JobDetail JobDetail jobDetail = JobBuilder.newJob(getJobClass(job.getJobClass())) .withIdentity(job.getId(), "JOB_GROUP") .withDescription(job.getDescription()) .build(); // 3. 设置参数 if (job.getParams() != null) { jobDetail.getJobDataMap().put("params", job.getParams()); } // 4. 创建CronTrigger CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(job.getId() + "_TRIGGER", "TRIGGER_GROUP") .withSchedule(CronScheduleBuilder.cronSchedule(job.getCron()) .withMisfireHandlingInstructionDoNothing()) // 错过触发的处理策略 .build(); // 5. 注册任务 scheduler.scheduleJob(jobDetail, trigger); } @Transactional(rollbackFor = Exception.class) @Override public void updateJob(QuartzJob job) throws SchedulerException { updateById(job); // 更新数据库记录 } @Override public void deleteJob(String jobId) throws SchedulerException { // 1. 暂停该任务的触发器(Trigger) scheduler.pauseTrigger(TriggerKey.triggerKey(jobId)); // 2. 解除该触发器与任务的绑定关系(从调度器中移除 Trigger) scheduler.unscheduleJob(TriggerKey.triggerKey(jobId)); // 3. 最终删除 Job 本身 scheduler.deleteJob(new JobKey(jobId, "JOB_GROUP")); // 删除数据库记录 removeById(jobId); } @Override public void pauseJob(String jobId) throws SchedulerException { // 1. 暂停任务 scheduler.pauseJob(new JobKey(jobId, "JOB_GROUP")); // 2. 更新数据库状态 QuartzJob job = getById(jobId); if (Objects.nonNull(job)) { job.setStatus(1); // 1-暂停 updateById(job); } } @Override public void resumeJob(String jobId) throws SchedulerException { // 1. 恢复任务 scheduler.resumeJob(new JobKey(jobId, "JOB_GROUP")); // 2. 更新数据库状态 QuartzJob job = getById(jobId); if (Objects.nonNull(job)) { job.setStatus(0); // 0-正常 updateById(job); } } @Override public void runJobNow(String jobId) throws SchedulerException { JobKey jobKey = new JobKey(jobId); scheduler.triggerJob(jobKey); log.info("立即执行任务: {}", jobId); } // 获取Job类 private Class getJobClass(String className) { try { return (Class) Class.forName(className); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("找不到Job类: " + className, e); } } } ``` controller ``` package com.lty.controller; import cn.hutool.core.util.IdUtil; import com.lty.model.entity.QuartzJob; import com.lty.service.QuartzJobService; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("/job") public class QuartzJobController { private final QuartzJobService jobService; public QuartzJobController(QuartzJobService jobService) { this.jobService = jobService; } /** * 获取所有任务列表 */ @PostMapping("/list") public List listJobs() { return jobService.list(); } /** * 添加任务 */ @PostMapping("/add") public String addJob(@RequestBody QuartzJob job) { try { job.setId(IdUtil.simpleUUID()); jobService.addJob(job); // 保存到数据库 jobService.save(job); return "任务添加成功"; } catch (Exception e) { return "任务添加失败: " + e.getMessage(); } } /** * 更新任务 */ @PostMapping("/update") public String updateJob(@RequestBody QuartzJob job) { try { jobService.updateJob(job); return "任务更新成功"; } catch (Exception e) { return "任务更新失败: " + e.getMessage(); } } /** * 删除任务 */ @PostMapping("/{jobId}/delete") public String deleteJob(@PathVariable String jobId) { try { jobService.deleteJob(jobId); return "任务删除成功"; } catch (Exception e) { return "任务删除失败: " + e.getMessage(); } } /** * 暂停任务 */ @PostMapping("/{jobId}/pause") public String pauseJob(@PathVariable String jobId) { try { jobService.pauseJob(jobId); return "任务暂停成功"; } catch (Exception e) { return "任务暂停失败: " + e.getMessage(); } } /** * 恢复任务 */ @PostMapping("/{jobId}/resume") public String resumeJob(@PathVariable String jobId) { try { jobService.resumeJob(jobId); return "任务恢复成功"; } catch (Exception e) { return "任务恢复失败: " + e.getMessage(); } } /** * 立即执行任务 */ @PostMapping("/{jobId}/runNow") public String runJobNow(@PathVariable String jobId) { try { jobService.runJobNow(jobId); return "任务已立即执行"; } catch (Exception e) { return "任务立即执行失败: " + e.getMessage(); } } /** * 重启定时任务 */ @PostMapping("/restart") public void restart() { try { List list = jobService.list(); for (QuartzJob job : list) { if (job.getStatus() == 0) { // 0-正常,重新添加任务 jobService.addJob(job); } else if (job.getStatus() == 1) { // 1-暂停,暂停任务 jobService.pauseJob(job.getId()); } } } catch (Exception e) { } } } ``` ----- ### 使用测试 > 专门设置一个job文件夹存放各种定时任务实现 示例定时任务 ``` package com.lty.job; import lombok.extern.slf4j.Slf4j; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; /** * 示例定时任务 * 该类实现了Quartz的Job接口,用于执行定时任务。 */ @Slf4j public class DemoJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 获取参数 String params = context.getJobDetail().getJobDataMap().getString("params"); log.info("执行定时任务: {}, 参数: {}", context.getJobDetail().getKey().getName(), params); // 执行具体业务逻辑... } } ``` 添加任务测试参数 ``` { "jobClass": "com.lty.job.DemoJob", "cron": "0/10 * * * * ?", "params": "testParam", "description": "每10秒执行一次的测试任务", "status": 0 } ``` ### Tip 需要多个“类似”任务 方案 1:使用不同的类名 方案 2:使用同一类名 + 不同参数(推荐) 方案 3:自定义 Group 分组