springboot整合quartz,实现数据库方式执行定时任务。把定时任务信息存进数据库,项目启动后自动执行定时任务。
1.引入依赖包:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
2.配置yml:
spring: # quartz quartz: #相关属性配置 properties: org: quartz: scheduler: instanceName: DefaultQuartzScheduler instanceId: AUTO jobStore: class: org.quartz.impl.jdbcjobstore.JobStoreTX driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate tablePrefix: QRTZ_ isClustered: false clusterCheckinInterval: 10000 #以指示JDBCJobStore将JobDataMaps中的所有值都作为字符串,因此可以作为名称 #- 值对存储而不是在BLOB列中以其序列化形式存储更多复杂的对象。 #从长远来看,这是更安全的,因为您避免了将非String类序列化为BLOB的类版本问题。 useProperties: false threadPool: class: org.quartz.simpl.SimpleThreadPool threadCount: 10 threadPriority: 5 threadsInheritContextClassLoaderOfInitializingThread: true # 数据库方式 job-store-type: jdbc datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/quartz_test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver server: port: 8080
3.后端编码:
controller层:
@Controller @RequestMapping(value = "/job") @Slf4j public class JobController { @Autowired private IJobService jobService; @PostMapping(value = "/add") @ResponseBody public Result addJob(@RequestBody JobInfo jobInfo) { return jobService.addJob(jobInfo); } @GetMapping(value = "/getAllJobs") @ResponseBody public List<JobInfo> getAllJobs() { return jobService.getAllJobs(); } @PostMapping(value = "/pause") @ResponseBody public Result pauseJob(String name, String group) { return jobService.pauseJob(name,group) ? Result.success() : Result.error(); } @PostMapping(value = "/resume") @ResponseBody public Result resumeJob(String name, String group) { return jobService.resumeJob(name,group) ? Result.success() : Result.error(); } @PostMapping(value = "/reschedule") @ResponseBody public Result reScheduleJob(String name, String group, String cron) { return jobService.reScheduleJob(name, group, cron) ? Result.success() : Result.error(); } @PostMapping(value = "/delete") @ResponseBody public Result deleteJob(String name, String group) { return jobService.deleteJob(name,group) ? Result.success() : Result.error(); } /** * @description 校验是否是合法cron表达式 * @param cron * @return com.cxh.cxhquartz.common.Result **/ @PostMapping(value = "/checkCron") @ResponseBody public Result checkCron(String cron) { boolean valide = false; try { valide = CronExpression.isValidExpression(cron); }catch (Exception e){ log.error(e.getMessage()); } return valide ? Result.success() : Result.error(); } }
service层:
public interface IJobService { /** * @description 查询所有任务 * @param * @return java.util.List<com.cxh.cxhquartz.quartz.JobInfo> **/ List<JobInfo> getAllJobs(); /** * @description 恢复任务 * @param jobName * @Param jobGroup * @return boolean **/ boolean resumeJob(String jobName,String jobGroup); /** * @description 停止任务 * @param jobName * @Param jobGroup * @return boolean **/ boolean pauseJob(String jobName,String jobGroup); /** * @description 修改任务执行周期表达式 * @param jobName * @Param jobGroup * @Param cronExpression * @return boolean **/ boolean reScheduleJob(String jobName,String jobGroup,String cronExpression); /** * @description 删除任务 * @param jobName * @Param jobGroup * @return boolean **/ boolean deleteJob(String jobName,String jobGroup); /** * @description 新增任务 * @param jobInfo * @return int **/ Result addJob(JobInfo jobInfo); /** * @description 判断任务是否存在 * @param jobKey * @return int **/ int isJobExist(JobKey jobKey); }
@Slf4j @Service public class JobServiceImpl implements IJobService { @Autowired private Scheduler scheduler; @Override public List<JobInfo> getAllJobs() { List<JobInfo> jobInfoList = new ArrayList<>(); try{ List<String> groupList = scheduler.getJobGroupNames(); for(String group : groupList){ GroupMatcher<JobKey> groupMatcher = GroupMatcher.groupEquals(group); Set<JobKey> jobKeySet = scheduler.getJobKeys(groupMatcher); for(JobKey jobKey : jobKeySet){ JobInfo jobInfo = new JobInfo(); JobDetail jobDetail = scheduler.getJobDetail(jobKey); jobInfo.setJobname(jobKey.getName()); jobInfo.setJobgroup(jobKey.getGroup()); jobInfo.setJobclassname(jobDetail.getJobClass().getName()); Trigger trigger = scheduler.getTrigger(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup())); if(trigger != null){ Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup())); jobInfo.setTriggername(jobKey.getName()); jobInfo.setTriggergroup(jobKey.getGroup()); try{ CronTrigger cronTrigger = (CronTrigger) trigger; jobInfo.setCronexpression(cronTrigger.getCronExpression()); } catch (Exception e){ log.error(e.getMessage()); } if(trigger.getNextFireTime() != null){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); jobInfo.setNextfiretime(sdf.format(trigger.getNextFireTime())); } jobInfo.setDescription(jobDetail.getDescription()); jobInfo.setState(state.name()); jobInfo.setId(UUID.randomUUID().toString()); jobInfoList.add(jobInfo); } else { jobInfo.setState("OVER"); jobInfo.setId(UUID.randomUUID().toString()); jobInfoList.add(jobInfo); } } } } catch (Exception e){ log.error(e.getMessage()); } return jobInfoList; } @Override public boolean resumeJob(String jobName, String jobGroup) { boolean flag = true; try{ scheduler.resumeJob(JobKey.jobKey(jobName, jobGroup)); } catch (Exception e){ flag = false; log.error(e.getMessage()); } return flag; } @Override public boolean pauseJob(String jobName, String jobGroup) { boolean flag = true; try{ scheduler.pauseJob(JobKey.jobKey(jobName, jobGroup)); } catch (Exception e){ flag = false; log.error(e.getMessage()); } return flag; } @Override public boolean reScheduleJob(String jobName, String jobGroup, String cronExpression) { boolean flag = true; try{ Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(jobName, jobGroup)); CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(TriggerKey.triggerKey(jobName, jobGroup)); if(cronTrigger != null && cronExpression != null && !cronTrigger.getCronExpression().equals(cronExpression)){ CronTrigger cronTriggerNew = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build(); scheduler.rescheduleJob(TriggerKey.triggerKey(jobName, jobGroup), cronTriggerNew); if(state.name().equals("PAUSED")){ this.pauseJob(jobName, jobGroup); } } } catch (Exception e){ flag = false; log.error(e.getMessage()); } return flag; } @Override public boolean deleteJob(String jobName, String jobGroup) { boolean flag = true; try{ List<? extends Trigger> triggerList = scheduler.getTriggersOfJob(JobKey.jobKey(jobName, jobGroup)); if(triggerList.size() > 0){ if(!"PAUSED".equals(scheduler.getTriggerState(TriggerKey.triggerKey(jobName, jobGroup)).name())){ scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, jobGroup)); } scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, jobGroup)); } scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup)); } catch (Exception e){ flag = false; log.error(e.getMessage()); } return flag; } @Override public Result addJob(JobInfo jobInfo) { int isJobExist = this.isJobExist(JobKey.jobKey(jobInfo.getJobname(), jobInfo.getJobgroup())); if(isJobExist == 1){ return Result.error("任务已存在!"); } try{ JobDetail jobDetail = null; if(isJobExist == 0){ jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobInfo.getJobname(), jobInfo.getJobgroup())); } else if(isJobExist == -1){ jobDetail = JobBuilder.newJob( (Class<? extends Job>) Class.forName(jobInfo.getJobclassname())) .withIdentity(jobInfo.getJobname(), jobInfo.getJobgroup()) .withDescription(jobInfo.getDescription()) .storeDurably().build(); } //如果jobInfo的cron表达式为空,则创建常规任务,反之创建周期任务 if(jobInfo.getCronexpression() != null){ CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobInfo.getTriggername(), jobInfo.getTriggergroup()) .withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCronexpression())) .build(); scheduler.scheduleJob(jobDetail, cronTrigger); } else { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobInfo.getJobname(), jobInfo.getJobgroup()) .startAt(sdf.parse(jobInfo.getNextfiretime())) .withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0)) .build(); scheduler.scheduleJob(jobDetail, trigger); } } catch (SchedulerException e){ log.error(e.getMessage()); return Result.error("添加任务失败!"); } catch (ParseException e){ log.error(e.getMessage()); return Result.error("时间转换出错!"); } catch (Exception e){ log.error(e.getMessage()); return Result.error(e.getMessage()); } return Result.success("添加任务成功!"); } @Override public int isJobExist(JobKey jobKey) { int flag = -1; try{ JobDetail jobDetail = scheduler.getJobDetail(jobKey); List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey); if(jobDetail != null && triggers.size() > 0){ flag = 1; } else if(jobDetail != null && triggers.size() == 0){ flag = 0; } } catch (Exception e){ flag = -1; log.error(e.getMessage()); } return flag; } }
entity层:
@Data public class JobInfo implements Serializable { private String id; private String jobname; private String jobgroup; private String jobclassname; private String triggername; private String triggergroup; private String cronexpression; private String description; private String prefiretime; private String nextfiretime; private String state; }
定时任务:
@Slf4j public class DemoJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDetail jobDetail = jobExecutionContext.getJobDetail(); log.info("任务名:" + jobDetail.getKey().getName() + ",组名:" + jobDetail.getKey().getGroup() + "------执行的定时任务工作内容!"); } }
4.创建数据库表:quartz保存定时任务信息表
5.运行项目,打开postman发起请求:
6.运行结果:
7.下载项目代码demo: springboot整合quartz,实现数据库方式执行定时任务-Java文档类资源-CSDN下载
dbTables.rar里面提供数据库sql,根据不同数据库运行对应sql,我采用mysql,运行tables_mysql_innodb.sql文件创建数据表。