spring boot 中使用quartz

发布时间:2021-10-21 18:08:19
修改时间:2022-07-20 14:53:07
总阅读数:1315
今日阅读数:0
昨日日阅读数:0
字数:16367

spring boot 中使用持久化quartz(与mybatis plus数据源分开)

[TOC]

增加依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.4</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

<!--mysql连接-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<!--druid连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

<!--jdbc依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!--quartz定时调度依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

配置文件

spring:
  quartz:
    job-store-type: jdbc #持久化到数据库
    properties:
      org:
        quartz:
#          quartz的MySQL数据源配置
          datasource:
            # 新版驱动从com.mysql.jdbc.Driver变更为com.mysql.cj.jdbc.Driver
            driver-class-name: com.mysql.cj.jdbc.Driver
            # 数据源需要添加时间标准和指定编码格式解决乱码 You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
            url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
            username: zzq
            password: 123
          scheduler:
            instancName: clusteredScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #StdJDBCDelegate说明支持集群
            tablePrefix: QRTZ_
            isClustered: true
            clusterCheckinInterval: 1000
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 20
            threadPriority: 5

#mybatis plus的数据源配置
  datasource:
    url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
    username: zzq
    password: 123
    driver-class-name: com.mysql.cj.jdbc.Driver


mybatis-plus:
  mapper-locations: classpath:mapper/**.xml
  global-config:
    db-config:
      id-type: auto

创建quartz数据库

创建数据库后执行建表语句

#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
    IS_DURABLE VARCHAR(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    NEXT_FIRE_TIME BIGINT(13) NULL,
    PREV_FIRE_TIME BIGINT(13) NULL,
    PRIORITY INTEGER NULL,
    TRIGGER_STATE VARCHAR(16) NOT NULL,
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
    START_TIME BIGINT(13) NOT NULL,
    END_TIME BIGINT(13) NULL,
    CALENDAR_NAME VARCHAR(200) NULL,
    MISFIRE_INSTR SMALLINT(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    REPEAT_COUNT BIGINT(7) NOT NULL,
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    CRON_EXPRESSION VARCHAR(200) NOT NULL,
    TIME_ZONE_ID VARCHAR(80),
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    BLOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    CALENDAR_NAME  VARCHAR(200) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_GROUP  VARCHAR(200) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    ENTRY_ID VARCHAR(95) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    FIRED_TIME BIGINT(13) NOT NULL,
    SCHED_TIME BIGINT(13) NOT NULL,
    PRIORITY INTEGER NOT NULL,
    STATE VARCHAR(16) NOT NULL,
    JOB_NAME VARCHAR(200) NULL,
    JOB_GROUP VARCHAR(200) NULL,
    IS_NONCONCURRENT VARCHAR(1) NULL,
    REQUESTS_RECOVERY VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    LOCK_NAME  VARCHAR(40) NOT NULL,
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);


commit;

 

数据源配置

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

/**
 * @author :zzq
 * @version :1.0
 * @date :Created in 2021/10/21 16:26
 * @description:
 * @modified By:
 */
@Configuration
public class DatasourceConfig {
    
    /** 
     * 功能描述: quartz数据源配置
     * @Author: zzq
     * @Date: 2021/10/22 10:58
     * @Param:  
     * @Return: javax.sql.DataSource
     */
    @Bean
    @QuartzDataSource
    @ConfigurationProperties(prefix = "spring.quartz.properties.org.quartz.datasource")
    DataSource quartzDataSource(){
        return DruidDataSourceBuilder.create().build();
    }


    /** 
     * 功能描述: mybatis plus数据源配置 
     * @Author: zzq
     * @Date: 2021/10/22 10:58
     * @Param:  
     * @Return: com.alibaba.druid.pool.DruidDataSource
     */
    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    DruidDataSource druidDataSource(){
        return DruidDataSourceBuilder.create().build();
    }


}

使用案例

modal层

mport com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.util.Date;

/**
 * @author :zzq
 * @version :1.0
 * @date :Created in 2021/10/21 16:31
 * @description:
 * @modified By:
 */
@Data
public class NoticeSettingVo {

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date time;
    private String msg;
    private String cron;

}

 

controller层

import com.example.quartzTest.pojo.vo.NoticeSettingVo;
import com.example.quartzTest.service.NoticeSettingService;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @author :zzq
 * @version :1.0
 * @date :Created in 2021/10/22 9:19
 * @description:
 * @modified By:
 */
@RestController
public class NoticeSettingController {

    @Autowired
    private NoticeSettingService noticeSettingService;


    /**
     * 功能描述: 设定通知任务的执行时间
     * @Author: zzq
     * @Date: 2021/10/22 9:54
     * @Param: noticeSettingVo
     * @Return: java.lang.String
     */
    @PostMapping("noticeSetting")
    public String setNoticeSetting(@RequestBody NoticeSettingVo noticeSettingVo){
        try {
            return noticeSettingService.setNoticeSetting(noticeSettingVo);
        } catch (SchedulerException e) {
            e.printStackTrace();
            return "faille,"+e.getMessage();
        }
    }


    /** 
     * 功能描述: 获取通知任务的执行时间
     * @Author: zzq
     * @Date: 2021/10/22 10:51
     * @Param:  
     * @Return: java.util.Map
     */
    @GetMapping("noticeSetting")
    public Map getNoticeSetting(){
        try {
            return noticeSettingService.getNoticeSetting();
        } catch (SchedulerException e) {
            e.printStackTrace();
            return null;
        }
    }


}

service层

import com.example.quartzTest.pojo.vo.NoticeSettingVo;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author :zzq
 * @version :1.0
 * @date :Created in 2021/10/22 9:19
 * @description:
 * @modified By:
 */
@Service
public class NoticeSettingService {

    @Autowired
    private Scheduler scheduler;


    /**
     * 功能描述: 设定通知任务的执行时间
     * @Author: zzq
     * @Date: 2021/10/22 9:35
     * @Param: noticeAddVo
     * @Return: java.lang.String
     */
    public String setNoticeSetting(NoticeSettingVo noticeSettingVo) throws SchedulerException {

        if (noticeSettingVo.getTime()==null&& noticeSettingVo.getCron()==null) {
//            如果没有输入时间和表达式,则返回错误
            return "faille";
        }

        if (noticeSettingVo.getCron() != null) {
//            如果输入了cron表达式,则进行格式校验
            if (!CronExpression.isValidExpression(noticeSettingVo.getCron())) {
                return "faille,Illegal cron expression";
            }
        }

        TriggerBuilder<Trigger> triggerTriggerBuilder = TriggerBuilder.newTrigger().withIdentity("notice","system");


        if (noticeSettingVo.getCron()!=null) {
//            如果corn不为空,则根据cron表达式设定任务执行时间
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(noticeSettingVo.getCron()).withMisfireHandlingInstructionDoNothing();


            if (noticeSettingVo.getTime() != null) {
//                如果指定了时间,则从指定时间开始执行任务
                triggerTriggerBuilder.withSchedule(scheduleBuilder).startAt(noticeSettingVo.getTime());
            }else {
//                如果未指定时间,则立刻开始执行
                triggerTriggerBuilder.withSchedule(scheduleBuilder).startNow();
            }

        }else {
//            如果没有corn表达式,则按指定时间执行一次任务
            triggerTriggerBuilder.startAt(noticeSettingVo.getTime()).withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0));
        }

        Trigger trigger = triggerTriggerBuilder.build();

        if (noticeSettingVo.getMsg() != null) {
//            如果存在msg,则将msg存入dataMap中
            trigger.getJobDataMap().put("msg", noticeSettingVo.getMsg());
        }


        JobKey jobKey = new JobKey("notice","system");
        TriggerKey triggerKey = TriggerKey.triggerKey("notice","system");
        JobDetail oldJobDetail = scheduler.getJobDetail(jobKey);
        if (oldJobDetail != null&&scheduler.checkExists(triggerKey)) {
//            如果该任务已存在,则进行更新操作
            scheduler.rescheduleJob(triggerKey,trigger);
        }else {

            JobDetail jobDetail = JobBuilder.newJob(new Job() {
                @Override
                public void execute(JobExecutionContext context) throws JobExecutionException {

                    System.out.println("当前时间:"+new Date()+",执行了任务Notice,msg为:"+context.getTrigger().getJobDataMap().get("msg"));

                }
            }.getClass()).withIdentity("notice","system").build();

//            任务不存在则进行添加操作
            scheduler.scheduleJob(jobDetail,trigger);
        }


        return "success";
    }

    /**
     * 功能描述: 获取定时任务的执行时间
     * @Author: zzq
     * @Date: 2021/10/22 10:52
     * @Param:
     * @Return: java.util.Map
     */
    public Map getNoticeSetting() throws SchedulerException {
        
        TriggerKey triggerKey = TriggerKey.triggerKey("notice","system");
//        获取触发器trigger
        Trigger trigger = scheduler.getTrigger(triggerKey);

        if (trigger == null) {
//            如果任务不存,则返回空
            return null;
        }

        Map<String,Object> res = new HashMap(8);

        
        if (trigger instanceof CronTriggerImpl) {
//            如果是使用cron表达式设定的任务,则返回cron表达式
            CronTriggerImpl cronTrigger= (CronTriggerImpl) trigger;
            String cronExpression = cronTrigger.getCronExpression();
            System.out.println(cronExpression);
            res.put("cron",cronExpression);
        }

//        返回开始时间
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        res.put("time", df.format(trigger.getStartTime()));

//        返回描述信息
        res.put("description",trigger.getDescription());
//        返回dataMap
        res.put("dataMap",trigger.getJobDataMap());

        return res;
    }
}