SpringBoot 整合quartz 并图形化显示

最终效果图

 前端页面只需要选择后端的逻辑类,就可以控制定时任务的开启与关闭

下面是整合步骤:
首先从官网中
http://www.quartz-scheduler.org/

点击Downloads
下载quartz-2.2.3-distribution.tar
下载后在目录\docs\dbTables下有常用数据库创建quartz表的脚本

 

 

table_mysql.sql
table_mysql_innodb.sql

上述两者所有的数据库引擎不一样

MySQL 选择table_mysql.sql 就可以

表的介绍

QRTZ_BLOB_TRIGGERS

作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)

QRTZ_CALENDARS

Blob 类型存储 Quartz Calendar 信息

QRTZ_CRON_TRIGGERS

存储 Cron Trigger,包括 Cron 表达式和时区信息

QRTZ_FIRED_TRIGGERS

存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息

QRTZ_JOB_DETAILS

存储每一个已配置的 Job 的详细信息

QRTZ_LOCKS

存储程序的非观锁的信息(假如使用了悲观锁)

QRTZ_PAUSED_TRIGGER_GRPS

存储已暂停的 Trigger 组的信息

QRTZ_SCHEDULER_STATE

存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)

QRTZ_SIMPLE_TRIGGERS

存储简单的 Trigger,包括重复次数,间隔,以及已触的次数

QRTZ_SIMPROP_TRIGGERS

简单的出发器详细信息。

QRTZ_TRIGGERS

存储已配置的 Trigger 的信息

准备好定时器表的构建之后,下面项目中整合

在pom.xml 中引入依赖

        <!-- 引入quartz框架-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>

新增一个properties 文件

org.quartz.scheduler.instanceName = MyScheduler
#开启集群,多个Quartz实例使用同一组数据库表
org.quartz.jobStore.isClustered = false
#分布式节点ID自动生成
org.quartz.scheduler.instanceId = AUTO
#分布式节点有效性检查时间间隔,单位:毫秒
org.quartz.jobStore.clusterCheckinInterval = 10000
#配置线程池线程数量,默认10个
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadPriority = 5
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#使用QRTZ_前缀
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.txIsolationLevelReadCommitted = true

org.quartz.jobStore.tablePrefix = QRTZ_  如果你更改了表的名称,这里请对应更改

新建一个核心配置类 ScheduleConfiguration

@Configuration
public class ScheduleConfiguration {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private MyJobFactory myJobFactory;

     @Bean
     public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
         SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
         schedulerFactoryBean.setSchedulerName("gbcom");
         schedulerFactoryBean.setDataSource(dataSource);
         schedulerFactoryBean.setApplicationContextSchedulerContextKey("application");
         schedulerFactoryBean.setQuartzProperties(quartzProperties());
         schedulerFactoryBean.setTaskExecutor(schedulerThreadPool());
         schedulerFactoryBean.setStartupDelay(0);
         schedulerFactoryBean.setJobFactory(myJobFactory);
         return schedulerFactoryBean;
     }

     @Bean
     public Properties quartzProperties() throws IOException {
         PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
         propertiesFactoryBean.setLocation(new ClassPathResource("/spring-quartz.properties"));
         propertiesFactoryBean.afterPropertiesSet();
         return propertiesFactoryBean.getObject();
     }
     @Bean
     public Executor schedulerThreadPool(){
         ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
         threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
         threadPoolTaskExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors());
         threadPoolTaskExecutor.setQueueCapacity(Runtime.getRuntime().availableProcessors());
         return threadPoolTaskExecutor;
     }

     @Bean
     public Scheduler scheduler() throws IOException {
      return schedulerFactoryBean().getScheduler();
     }
}

 如果job类需要注入spring容器对象还需要添加一个配置类MyJobFactory

@Component
public class MyJobFactory extends AdaptableJobFactory {
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        // 进行注入
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }

在核心配置类配置

 在编写一个QuartzManager 通用类

@Service
public class QuartzManager {
    @Autowired
    private Scheduler scheduler;

    /**
     * 功能: 添加一个定时任务
     *
     * @param jobName
     *            任务名
     * @param jobGroupName
     *            任务组名
     * @param triggerName
     *            触发器名
     * @param triggerGroupName
     *            触发器组名
     * @param jobClass
     *            任务的类类型 eg:TimedMassJob.class
     * @param cron
     *            时间设置 表达式,参考quartz说明文档
     * //@param objects
     *            可变参数需要进行传参的值
     */
    public  void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
                        Class jobClass, String cron, String description,String i) {
        try {

            // 任务名,任务组,任务执行类
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).withDescription(description).storeDurably().requestRecovery().build();
            //System.out.println("jobDetail.getKey:"+jobDetail.getKey());
            // 触发器
//            if (objects != null) {
//                for (int i = 0; i < objects.length; i++) {
//                    // 该数据可以通过Job中的JobDataMap dataMap =
//                    // context.getJobDetail().getJobDataMap();来进行参数传递值
//                    Map<String,Object> mapParams = new HashMap<>();
//
//                    jobDetail.getJobDataMap().put("name","admin");
//                }
//            }
            jobDetail.getJobDataMap().put("mi",i);
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(triggerName, triggerGroupName);
            triggerBuilder.startNow();
            triggerBuilder.withDescription(description);
            // 触发器时间设定
            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
            // 创建Trigger对象
            CronTrigger trigger = (CronTrigger) triggerBuilder.build();
            // 调度容器设置JobDetail和Trigger
            scheduler.scheduleJob(jobDetail, trigger);
            // 启动
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
    public  void addJobs(QrtzTriggers qrtzTriggers1, QrtzTriggers qrtzTriggers2,Object... objects) {

        try {
            String jobClassName = qrtzTriggers1.getJobClassName();
            ClassLoader loader = ClassLoader.getSystemClassLoader();
            Class jobClass = loader.loadClass(jobClassName);
            String jobName = qrtzTriggers1.getJobName();
            String jobGroupName = qrtzTriggers1.getJobGroup();
            // 任务名,任务组,任务执行类
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).storeDurably().requestRecovery().build();
            List<QrtzTriggers> qrtzTriggersList = new ArrayList<>();
            qrtzTriggersList.add(qrtzTriggers1);
            qrtzTriggersList.add(qrtzTriggers2);
            List<CronTrigger> cronTriggers = new ArrayList<>();
            for (QrtzTriggers qrtzTrigger :
                    qrtzTriggersList) {
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(qrtzTrigger.getTriggerName(), qrtzTrigger.getTriggerGroup());
                triggerBuilder.startNow();
                triggerBuilder.withDescription(qrtzTrigger.getDescription());
                // 触发器时间设定
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(qrtzTrigger.getCron()));
                triggerBuilder.forJob(jobDetail);
                // 创建Trigger对象
                CronTrigger trigger = (CronTrigger) triggerBuilder.build();
                cronTriggers.add(trigger);
            }

            //System.out.println("jobDetail.getKey:"+jobDetail.getKey());
            // 触发器
            if (objects != null) {
                for (int i = 0; i < objects.length; i++) {
                    // 该数据可以通过Job中的JobDataMap dataMap =
                    // context.getJobDetail().getJobDataMap();来进行参数传递值
                    jobDetail.getJobDataMap().put("name","admin");
                }
            }
            // 调度容器设置JobDetail和Trigger
            scheduler.addJob(jobDetail,true);
            scheduler.scheduleJob(cronTriggers.get(0));
            scheduler.scheduleJob(cronTriggers.get(1));
            // 启动
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 功能:修改一个任务的触发时间
     *
     * @param triggerName
     *            触发器名
     * @param triggerGroupName
     *            触发器组名
     * @param cron
     *            时间设置,参考quartz说明文档
     */
    public  void modifyJobTime(String triggerName, String triggerGroupName,
                               String cron,String description) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            String oldTime = trigger.getCronExpression();
            if (!oldTime.equalsIgnoreCase(cron)) {
                // 触发器
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(triggerName, triggerGroupName);
                triggerBuilder.startNow();
                triggerBuilder.withDescription(description);
                // 触发器时间设定
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
                // 创建Trigger对象
                trigger = (CronTrigger) triggerBuilder.build();
                // 方式一 :修改一个任务的触发时间
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 功能: 移除一个任务
     *
     * @param jobName
     * @param jobGroupName
     * @param triggerName
     * @param triggerGroupName
     */
    public  void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
        try {

            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));

            System.out.println("removeJob:"+JobKey.jobKey(jobName));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public void pauseJob(String triggerName, String triggerGroupName){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            scheduler.pauseTrigger(triggerKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void startJob(String triggerName, String triggerGroupName){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            scheduler.resumeTrigger(triggerKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * 功能:启动所有定时任务
     */
    public  void startJobs() {
        try {
            scheduler.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 功能:关闭所有定时任务
     */
    public  void shutdownJobs() {
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

业务类 写上你需要的业务逻辑

然后去页面配置定时任务即可

后端 定时任务开启,暂停,添加的api接口代码

@RestController
@RequestMapping("/quartz")
public class QuartzTriggersController {
    @Autowired
    private QrtzTriggersService qrtzTriggersService;
    @Autowired
    private QrtzCronTriggersService qrtzCronTriggersService;
    @Autowired
    private QuartzManager quartzManager;
    @Autowired
    private QrtzJobDetailsService qrtzJobDetailsService;

    @GetMapping("/triggers")
    public RS getAllTriggers(PagePostVo pagePostVo){
        PageHelper.startPage(pagePostVo.getPageNumber(),pagePostVo.getPageSize());
        List<QrtzTriggers> triggersList = qrtzTriggersService.getAllTriggers();
        List<QrtzCronTriggers> qrtzCronTriggersList = qrtzCronTriggersService.getAllCronTriggers();
        List<QrtzJobDetails> qrtzJobDetailsList = qrtzJobDetailsService.getAllJobDetails();
        for (QrtzTriggers qrtzTriggers:
                triggersList) {
            for (QrtzCronTriggers qrtzCronTriggers:
                    qrtzCronTriggersList) {
                if(qrtzCronTriggers.getTriggerGroup().equals(qrtzTriggers.getTriggerGroup())&& qrtzCronTriggers.getTriggerName().equals(qrtzTriggers.getTriggerName())){
                    qrtzTriggers.setCron(qrtzCronTriggers.getCronExpression());
                }
            }
            for (QrtzJobDetails qrtzJobDetails:
                    qrtzJobDetailsList) {
                if(qrtzJobDetails.getJobGroup().equals(qrtzTriggers.getJobGroup())&& qrtzJobDetails.getJobName().equals(qrtzTriggers.getJobName())){
                    qrtzTriggers.setJobClassName(qrtzJobDetails.getJobClassName());
                }
            }
        }
        PageInfo pageInfo = new PageInfo(triggersList);
        long total = pageInfo.getTotal();
        return new RS().ok().addResult("data",triggersList).addResult("total",total).addResult("pageNumber",pageInfo.getPageNum())
                .addResult("pageSize",pageInfo.getPageSize());
    }
    @ApiOperation("暂停定时任务")
    @PostMapping("/pauseTriggers")
    public RS pauseJob(@RequestBody QrtzTriggers qrtzTriggers){
        String triggerGroup = qrtzTriggers.getTriggerGroup();
        String triggerName = qrtzTriggers.getTriggerName();
        String triggerState = qrtzTriggers.getTriggerState();
        if(triggerState.equals("PAUSED")){
            throw  new MyException(1,"请勿重复暂停定时任务");
        }
        quartzManager.pauseJob(triggerName,triggerGroup);
        return new RS().ok();
    }
    @ApiOperation("开启定时任务")
    @PostMapping("/startTriggers")
    public RS startJob(@RequestBody QrtzTriggers qrtzTriggers){
        String triggerGroup = qrtzTriggers.getTriggerGroup();
        String triggerName = qrtzTriggers.getTriggerName();
        String triggerState = qrtzTriggers.getTriggerState();
        if(triggerState.equals("WAITING")||triggerState.equals("ACQUIRED")){
            throw  new MyException(1,"请勿重复开启定时任务");
        }
        quartzManager.startJob(triggerName,triggerGroup);
        return new RS().ok();
    }
    @ApiOperation("移除定时任务")
    @DeleteMapping("/triggers/{triggersNames}")
    public RS removeJob(@PathVariable String triggersNames){
        String[] split = triggersNames.split(",");
        for (String triggersName :
                split) {
            QrtzTriggers qrtzTriggers = qrtzTriggersService.getTriggersByName(triggersName);
            String triggerGroup = qrtzTriggers.getTriggerGroup();
            String triggerName = qrtzTriggers.getTriggerName();
            String jobGroup = qrtzTriggers.getJobGroup();
            String jobName = qrtzTriggers.getJobName();
            quartzManager.removeJob(jobName,jobGroup,triggerName,triggerGroup);
        }
        return new RS().ok();
    }
    @GetMapping("/jobClassName")
    public RS getAllJobClassName(){
        List<String> jobClassNameList = new ArrayList<>();
        try {
            PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
            CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
            Resource[] resources = new Resource[0];
            resources = pathMatchingResourcePatternResolver.getResources("classpath*:com/gbcom/wvp/job/*.class");
            for (Resource resource : resources) {

                MetadataReader reader = cachingMetadataReaderFactory.getMetadataReader(resource);
                String className = reader.getClassMetadata().getClassName();
                jobClassNameList.add(className);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new RS().ok().addResult("data",jobClassNameList);
    }
    @ApiOperation("添加定时任务")
    @PostMapping("/triggers")
    public  RS addJob(@RequestBody QrtzTriggers qrtzTriggers) throws ClassNotFoundException {
        String cron = qrtzTriggers.getCron();
        String description = qrtzTriggers.getDescription();
        String jobClassName = qrtzTriggers.getJobClassName();
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class jobClass = loader.loadClass(jobClassName);
        String jobName = qrtzTriggers.getJobName();
        String jobGroup = qrtzTriggers.getJobGroup();
        String triggerName = qrtzTriggers.getTriggerName();
        String triggerGroup = qrtzTriggers.getTriggerGroup();
        //进行一下判断
        List<QrtzTriggers> qrtzTriggersList = qrtzTriggersService.getTriggersByNames(triggerName,jobName);
        if(qrtzTriggersList!=null && qrtzTriggersList.size()!=0){
            throw new MyException(1,"任务名,触发器名不能相同");
        }
        quartzManager.addJob(jobName,jobGroup,triggerName,triggerGroup,jobClass,cron,description,null);
        return new RS().ok();
    }
    @ApiOperation("修改定时任务")
    @PatchMapping("/triggers/{triggersName}")
    public RS updateJob(@RequestBody QrtzTriggers qrtzTriggers,@PathVariable String triggersName){
        QrtzTriggers triggers = qrtzTriggersService.getTriggersByName(triggersName);
        List<QrtzCronTriggers> qrtzCronTriggersList = qrtzCronTriggersService.getAllCronTriggers();
        for (QrtzCronTriggers qrtzCronTriggers:
                qrtzCronTriggersList) {
            if(qrtzCronTriggers.getTriggerGroup().equals(triggers.getTriggerGroup())&& qrtzCronTriggers.getTriggerName().equals(triggers.getTriggerName())){
                triggers.setCron(qrtzCronTriggers.getCronExpression());
            }
        }
        String cron = qrtzTriggers.getCron();
        String triggerName = qrtzTriggers.getTriggerName();
        String triggerGroup = qrtzTriggers.getTriggerGroup();
        String description = qrtzTriggers.getDescription();
        if(!triggers.getTriggerGroup().equals(triggerGroup)||!triggers.getTriggerName().equals(triggerName)){
            //新增一个job
            quartzManager.removeJob(triggers.getJobName(),triggers.getJobGroup(),triggers.getTriggerName(),triggers.getTriggerGroup());
            quartzManager.addJobs(qrtzTriggers,triggers,null);

        }else {
            quartzManager.modifyJobTime(triggerName, triggerGroup, cron, description);
        }
        return new RS().ok();
    }

前端页面 写好页面调对应的api接口即可 

重启项目时启动定时任务

@Component
public class QueTaskRunner implements ApplicationRunner {
    @Autowired
    private QrtzTriggersService qrtzTriggersService;
    @Autowired
    private QuartzManager quartzManager;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<QrtzTriggers> triggersList = qrtzTriggersService.getAllTriggers();
        for (QrtzTriggers qrtzTriggers:
                triggersList) {
            String triggerState = qrtzTriggers.getTriggerState();
            if(!triggerState.equals("WAITING")||!triggerState.equals("ACQUIRED")){
                //项目重启查询出数据库没启动的定时任务
                String triggerGroup = qrtzTriggers.getTriggerGroup();
                String triggerName = qrtzTriggers.getTriggerName();
                quartzManager.startJob(triggerName,triggerGroup);
            }
        }
    }
}

 至此,job 已经被我们成功持久化到数据库

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值