SpringBoot2.x集成Quartz实现定时任务管理(持久化到数据库)
阅读原文时间:2023年07月10日阅读:4

1. Quartz简介

  Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目。

  Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。

  Quartz可以与J2EE与J2SE应用程序相结合也可以单独使用。

  Quartz允许程序开发人员根据时间的间隔来调度作业。

  Quartz实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。

  Quartz官网:http://www.quartz-scheduler.org/

2. Quartz核心概念

  • Job

      Job表示一个工作,要执行的具体内容。

  • JobDetail

      JobDetail表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail还包含了这个任务调度的方案和策略。

  • Trigger

      Trigger代表一个调度参数的配置,什么时候去调。

  • Scheduler

      Scheduler代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。

3. 初始化数据库

  Quartz采用持久化到数据库方式,需要创建官网提供的11张表。因此,可以在官网下载对应的版本,根据路径src\org\quartz\impl\jdbcjobstore找到对应数据库类型的脚本,例如Mysql为:tables_mysql.sql

  Mysql相关的表及系统需要的表脚本如下,请先创建数据库:quartzdemo,并初始化数据库表结构及数据。

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_qrtz_blob_triggers
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_blob_triggers`;
CREATE TABLE `t_qrtz_blob_triggers`  (
  `sched_name` varchar(120) NOT NULL,
  `trigger_name` varchar(190) NOT NULL,
  `trigger_group` varchar(190) NOT NULL,
  `blob_data` blob NULL,
  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
  INDEX `sched_name`(`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
  CONSTRAINT `t_qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `t_qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
);

-- ----------------------------
-- Records of t_qrtz_blob_triggers
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_calendars
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_calendars`;
CREATE TABLE `t_qrtz_calendars`  (
  `sched_name` varchar(120) NOT NULL,
  `calendar_name` varchar(190) NOT NULL,
  `calendar` blob NOT NULL,
  PRIMARY KEY (`sched_name`, `calendar_name`) USING BTREE
);

-- ----------------------------
-- Records of t_qrtz_calendars
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_cron_triggers
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_cron_triggers`;
CREATE TABLE `t_qrtz_cron_triggers`  (
  `sched_name` varchar(120) NOT NULL,
  `trigger_name` varchar(190) NOT NULL,
  `trigger_group` varchar(190) NOT NULL,
  `cron_expression` varchar(120) NOT NULL,
  `time_zone_id` varchar(80) NULL DEFAULT NULL,
  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
  CONSTRAINT `t_qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `t_qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
);

-- ----------------------------
-- Records of t_qrtz_cron_triggers
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_fired_triggers
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_fired_triggers`;
CREATE TABLE `t_qrtz_fired_triggers`  (
  `sched_name` varchar(120) NOT NULL,
  `entry_id` varchar(95) NOT NULL,
  `trigger_name` varchar(190) NOT NULL,
  `trigger_group` varchar(190) NOT NULL,
  `instance_name` varchar(190) NOT NULL,
  `fired_time` bigint(0) NOT NULL,
  `sched_time` bigint(0) NOT NULL,
  `priority` int(0) NOT NULL,
  `state` varchar(16) NOT NULL,
  `job_name` varchar(190) NULL DEFAULT NULL,
  `job_group` varchar(190) NULL DEFAULT NULL,
  `is_nonconcurrent` varchar(1) NULL DEFAULT NULL,
  `requests_recovery` varchar(1) NULL DEFAULT NULL,
  PRIMARY KEY (`sched_name`, `entry_id`) USING BTREE,
  INDEX `idx_qrtz_ft_trig_inst_name`(`sched_name`, `instance_name`) USING BTREE,
  INDEX `idx_qrtz_ft_inst_job_req_rcvry`(`sched_name`, `instance_name`, `requests_recovery`) USING BTREE,
  INDEX `idx_qrtz_ft_j_g`(`sched_name`, `job_name`, `job_group`) USING BTREE,
  INDEX `idx_qrtz_ft_jg`(`sched_name`, `job_group`) USING BTREE,
  INDEX `idx_qrtz_ft_t_g`(`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
  INDEX `idx_qrtz_ft_tg`(`sched_name`, `trigger_group`) USING BTREE
);

-- ----------------------------
-- Records of t_qrtz_fired_triggers
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_job_details
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_job_details`;
CREATE TABLE `t_qrtz_job_details`  (
  `sched_name` varchar(120) NOT NULL,
  `job_name` varchar(190) NOT NULL,
  `job_group` varchar(190) NOT NULL,
  `description` varchar(250) NULL DEFAULT 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`) USING BTREE,
  INDEX `idx_qrtz_j_req_recovery`(`sched_name`, `requests_recovery`) USING BTREE,
  INDEX `idx_qrtz_j_grp`(`sched_name`, `job_group`) USING BTREE
);

-- ----------------------------
-- Records of t_qrtz_job_details
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_locks
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_locks`;
CREATE TABLE `t_qrtz_locks`  (
  `sched_name` varchar(120) NOT NULL,
  `lock_name` varchar(40) NOT NULL,
  PRIMARY KEY (`sched_name`, `lock_name`) USING BTREE
);

-- ----------------------------
-- Records of t_qrtz_locks
-- ----------------------------
INSERT INTO `t_qrtz_locks` VALUES ('clusteredScheduler', 'STATE_ACCESS');
INSERT INTO `t_qrtz_locks` VALUES ('clusteredScheduler', 'TRIGGER_ACCESS');

-- ----------------------------
-- Table structure for t_qrtz_paused_trigger_grps
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_paused_trigger_grps`;
CREATE TABLE `t_qrtz_paused_trigger_grps`  (
  `sched_name` varchar(120) NOT NULL,
  `trigger_group` varchar(190) NOT NULL,
  PRIMARY KEY (`sched_name`, `trigger_group`) USING BTREE
);

-- ----------------------------
-- Records of t_qrtz_paused_trigger_grps
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_scheduler_state
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_scheduler_state`;
CREATE TABLE `t_qrtz_scheduler_state`  (
  `sched_name` varchar(120) NOT NULL,
  `instance_name` varchar(190) NOT NULL,
  `last_checkin_time` bigint(0) NOT NULL,
  `checkin_interval` bigint(0) NOT NULL,
  PRIMARY KEY (`sched_name`, `instance_name`) USING BTREE
);

-- ----------------------------
-- Records of t_qrtz_scheduler_state
-- ----------------------------
INSERT INTO `t_qrtz_scheduler_state` VALUES ('clusteredScheduler', 'C3Stones-PC', 1600918524362, 10000);

-- ----------------------------
-- Table structure for t_qrtz_simple_triggers
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_simple_triggers`;
CREATE TABLE `t_qrtz_simple_triggers`  (
  `sched_name` varchar(120) NOT NULL,
  `trigger_name` varchar(190) NOT NULL,
  `trigger_group` varchar(190) NOT NULL,
  `repeat_count` bigint(0) NOT NULL,
  `repeat_interval` bigint(0) NOT NULL,
  `times_triggered` bigint(0) NOT NULL,
  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
  CONSTRAINT `t_qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `t_qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
);

-- ----------------------------
-- Records of t_qrtz_simple_triggers
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_simprop_triggers
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_simprop_triggers`;
CREATE TABLE `t_qrtz_simprop_triggers`  (
  `sched_name` varchar(120) NOT NULL,
  `trigger_name` varchar(190) NOT NULL,
  `trigger_group` varchar(190) NOT NULL,
  `str_prop_1` varchar(512) NULL DEFAULT NULL,
  `str_prop_2` varchar(512) NULL DEFAULT NULL,
  `str_prop_3` varchar(512) NULL DEFAULT NULL,
  `int_prop_1` int(0) NULL DEFAULT NULL,
  `int_prop_2` int(0) NULL DEFAULT NULL,
  `long_prop_1` bigint(0) NULL DEFAULT NULL,
  `long_prop_2` bigint(0) NULL DEFAULT NULL,
  `dec_prop_1` decimal(13, 4) NULL DEFAULT NULL,
  `dec_prop_2` decimal(13, 4) NULL DEFAULT NULL,
  `bool_prop_1` varchar(1) NULL DEFAULT NULL,
  `bool_prop_2` varchar(1) NULL DEFAULT NULL,
  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
  CONSTRAINT `t_qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `t_qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
);

-- ----------------------------
-- Records of t_qrtz_simprop_triggers
-- ----------------------------

-- ----------------------------
-- Table structure for t_qrtz_triggers
-- ----------------------------
DROP TABLE IF EXISTS `t_qrtz_triggers`;
CREATE TABLE `t_qrtz_triggers`  (
  `sched_name` varchar(120) NOT NULL,
  `trigger_name` varchar(190) NOT NULL,
  `trigger_group` varchar(190) NOT NULL,
  `job_name` varchar(190) NOT NULL,
  `job_group` varchar(190) NOT NULL,
  `description` varchar(250) NULL DEFAULT NULL,
  `next_fire_time` bigint(0) NULL DEFAULT NULL,
  `prev_fire_time` bigint(0) NULL DEFAULT NULL,
  `priority` int(0) NULL DEFAULT NULL,
  `trigger_state` varchar(16) NOT NULL,
  `trigger_type` varchar(8) NOT NULL,
  `start_time` bigint(0) NOT NULL,
  `end_time` bigint(0) NULL DEFAULT NULL,
  `calendar_name` varchar(190) NULL DEFAULT NULL,
  `misfire_instr` smallint(0) NULL DEFAULT NULL,
  `job_data` blob NULL,
  PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE,
  INDEX `idx_qrtz_t_j`(`sched_name`, `job_name`, `job_group`) USING BTREE,
  INDEX `idx_qrtz_t_jg`(`sched_name`, `job_group`) USING BTREE,
  INDEX `idx_qrtz_t_c`(`sched_name`, `calendar_name`) USING BTREE,
  INDEX `idx_qrtz_t_g`(`sched_name`, `trigger_group`) USING BTREE,
  INDEX `idx_qrtz_t_state`(`sched_name`, `trigger_state`) USING BTREE,
  INDEX `idx_qrtz_t_n_state`(`sched_name`, `trigger_name`, `trigger_group`, `trigger_state`) USING BTREE,
  INDEX `idx_qrtz_t_n_g_state`(`sched_name`, `trigger_group`, `trigger_state`) USING BTREE,
  INDEX `idx_qrtz_t_next_fire_time`(`sched_name`, `next_fire_time`) USING BTREE,
  INDEX `idx_qrtz_t_nft_st`(`sched_name`, `trigger_state`, `next_fire_time`) USING BTREE,
  INDEX `idx_qrtz_t_nft_misfire`(`sched_name`, `misfire_instr`, `next_fire_time`) USING BTREE,
  INDEX `idx_qrtz_t_nft_st_misfire`(`sched_name`, `misfire_instr`, `next_fire_time`, `trigger_state`) USING BTREE,
  INDEX `idx_qrtz_t_nft_st_misfire_grp`(`sched_name`, `misfire_instr`, `next_fire_time`, `trigger_group`, `trigger_state`) USING BTREE,
  CONSTRAINT `t_qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `t_qrtz_job_details` (`sched_name`, `job_name`, `job_group`) ON DELETE RESTRICT ON UPDATE RESTRICT
);

-- ----------------------------
-- Records of t_qrtz_triggers
-- ----------------------------

-- ----------------------------
-- Table structure for t_sys_job
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_job`;
CREATE TABLE `t_sys_job`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `job_name` varchar(100) NULL DEFAULT NULL COMMENT '任务名称',
  `cron_expression` varchar(255) NULL DEFAULT NULL COMMENT 'cron表达式',
  `bean_class` varchar(255) NULL DEFAULT NULL COMMENT '任务执行类(包名+类名)',
  `status` varchar(10) NULL DEFAULT NULL COMMENT '任务状态',
  `job_group` varchar(50) NULL DEFAULT NULL COMMENT '任务分组',
  `job_data_map` varchar(1000) NULL DEFAULT NULL COMMENT '参数',
  `create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建人ID',
  `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_user_id` int(0) NULL DEFAULT NULL COMMENT '更新人ID',
  `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  `remarks` varchar(255) NULL DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`) USING BTREE
) AUTO_INCREMENT = 3 COMMENT = '定时任务';

-- ----------------------------
-- Records of t_sys_job
-- ----------------------------
INSERT INTO `t_sys_job` VALUES (1, 'TestJob', '0/5 * * * * ?', 'com.c3stones.job.biz.TestJob', 'NONE', 'default', '{\"username\":\"zhangsan\", \"age\":18}', 1, '2020-09-25 15:22:32', 1, '2020-09-25 15:22:32', '测试定时任务1');
INSERT INTO `t_sys_job` VALUES (2, 'Test2Job', '0 * * * * ?', 'com.c3stones.job.biz.Test2Job', 'NONE', 'default', '{\"username\":\"lisi\", \"age\":20}', 1, '2020-09-25 15:22:54', 1, '2020-09-25 15:22:54', '测试定时任务2');

-- ----------------------------
-- Table structure for t_sys_user
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user`;
CREATE TABLE `t_sys_user`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `username` varchar(50) NULL DEFAULT NULL COMMENT '用户名称',
  `nickname` varchar(100) NULL DEFAULT NULL COMMENT '用户昵称',
  `password` varchar(255) NULL DEFAULT NULL COMMENT '用户密码',
  PRIMARY KEY (`id`) USING BTREE
)AUTO_INCREMENT = 3 COMMENT = '系统用户';

-- ----------------------------
-- Records of t_sys_user
-- ----------------------------
INSERT INTO `t_sys_user` VALUES (1, 'user', 'C3Stones', '$2a$10$WXEPqxjMwY6d6A0hkeBtGu.acRRWUOJmX7oLUuYMHF1VWWUm4EqOC');
INSERT INTO `t_sys_user` VALUES (2, 'system', '管理员', '$2a$10$dmO7Uk9/lo1D5d1SvCGgWuB050a0E2uuBDNITEpWFiIfCg.3UbA8y');

SET FOREIGN_KEY_CHECKS = 1;

4. 示例代码

  本文在之前博客SpringBoot + Layui +Mybatis-plus实现简单后台管理系统(内置安全过滤器)的示例项目spring-boot-layui-demo基础上增加了任务调度菜单,因此请先下载相关工程。

  • 修改pom.xml

      引入依赖spring-boot-starter-quartz即可实现SpringBoot与Quartz集成。

    http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4.0.0
    com.c3stones
    spring-boot-quartz-demo
    0.0.1-SNAPSHOT
    spring-boot-quartz-demo
    Spring Boot Quartz Demo

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.8.RELEASE</version>
        <relativePath />
    </parent>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

  • 配置文件application.yml添加quartz相关配置

    server:
    port: 8080
    servlet:
    session:
    timeout: 1800s

    spring:
    jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
    datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/quartzdemo?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
    username: root
    password: 123456
    thymeleaf:
    prefix: classpath:/view/
    suffix: .html
    encoding: UTF-8
    servlet:
    content-type: text/html
    # 生产环境设置true
    cache: false
    quartz:
    properties:
    org:
    quartz:
    scheduler:
    instanceName: clusteredScheduler
    instanceId: AUTO
    jobStore:
    class: org.quartz.impl.jdbcjobstore.JobStoreTX
    driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    tablePrefix: t_qrtz_
    isClustered: false
    clusterCheckinInterval: 10000
    useProperties: false
    threadPool:
    class: org.quartz.simpl.SimpleThreadPool
    threadCount: 10
    threadPriority: 5
    threadsInheritContextClassLoaderOfInitializingThread: true
    job-store-type: jdbc

    Mybatis-plus配置

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

    configuration:

    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    日志配置

    logging:
    config: classpath:logback-spring.xml

    信息安全

    security:
    web:
    excludes:
    - /login
    - /logout
    - /images/**
    - /jquery/**
    - /layui/**
    xss:
    enable: true
    excludes:
    - /login
    - /logout
    - /images/*
    - /jquery/*
    - /layui/*
    sql:
    enable: true
    excludes:
    - /images/*
    - /jquery/*
    - /layui/*
    csrf:
    enable: true
    excludes:

  • 创建调度器配置类

    import javax.sql.DataSource;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.quartz.SchedulerFactoryBean;

    /**

    • 调度器配置类
      *

    • @author CL
      *
      */
      @Configuration
      public class SchedulerConfig implements SchedulerFactoryBeanCustomizer {

      @Autowired
      private DataSource dataSource;

      @Override
      public void customize(SchedulerFactoryBean schedulerFactoryBean) {
      // 启动延时
      schedulerFactoryBean.setStartupDelay(10);
      // 自动启动任务调度
      schedulerFactoryBean.setAutoStartup(true);
      // 是否覆盖现有作业定义
      schedulerFactoryBean.setOverwriteExistingJobs(true);
      // 配置数据源
      schedulerFactoryBean.setDataSource(dataSource);
      }

    }

  • 创建全局用户工具类

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;

    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;

    import com.c3stones.sys.entity.User;

    /**

    • 用户工具类
      *

    • @author CL
      *
      */
      public class UserUtils {

      /**

      • 获取当前用户
        *
      • @return
        */
        public static User get() {
        return (User) getSession().getAttribute("user");
        }

      /**

      • 获取session
        *
      • @return
        */
        public static HttpSession getSession() {
        return getRequest().getSession();
        }

      /**

      • 获取request
        *
      • @return
        */
        public static HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes();
        return requestAttributes.getRequest();
        }

    }

  • 创建实体

    import java.io.Serializable;
    import java.time.LocalDateTime;

    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import com.baomidou.mybatisplus.extension.activerecord.Model;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    import lombok.NoArgsConstructor;

    /**

    • 定时任务
      *

    • @author CL
      *
      */
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      @TableName(value = "t_sys_job")
      @EqualsAndHashCode(callSuper = false)
      public class Job extends Model implements Serializable {

      private static final long serialVersionUID = 1L;

      /**

      • ID
        */
        @TableId(type = IdType.AUTO)
        private Integer id;

      /**

      • 任务名称
        */
        private String jobName;

      /**

      • cron表达式
        */
        private String cronExpression;

      /**

      • 任务执行类(包名+类名)
        */
        private String beanClass;

      /**

      • 任务状态(0-停止,1-运行)
        */
        private String status;

      /**

      • 任务分组
        */
        private String jobGroup;

      /**

      • 参数
        */
        private String jobDataMap;

      /**

      • 下一次执行时间
        */
        @TableField(exist = false)
        private LocalDateTime nextfireDate;

      /**

      • 创建人ID
        */
        private Integer createUserId;

      /**

      • 创建时间
        */
        private LocalDateTime createDate;

      /**

      • 更新人ID
        */
        private Integer updateUserId;

      /**

      • 更新时间
        */
        private LocalDateTime updateDate;

      /**

      • 描述
        */
        private String remarks;

    }

  • 创建定时任务处理器

    import java.text.ParseException;
    import java.time.Instant;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;

    import org.quartz.CronExpression;
    import org.quartz.CronScheduleBuilder;
    import org.quartz.CronTrigger;
    import org.quartz.JobBuilder;
    import org.quartz.JobDataMap;
    import org.quartz.JobDetail;
    import org.quartz.JobKey;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.Trigger;
    import org.quartz.Trigger.TriggerState;
    import org.quartz.TriggerBuilder;
    import org.quartz.TriggerKey;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;

    import com.c3stones.job.entity.Job;

    import cn.hutool.core.util.StrUtil;
    import cn.hutool.json.JSONUtil;
    import lombok.extern.slf4j.Slf4j;

    /**

    • 定时任务管理器
      *

    • @author CL
      *
      */
      @Slf4j
      @Component
      public class QuartzHandler {

      @Autowired
      private Scheduler scheduler;

      /**

      • 新增定义任务
        *
      • @param job 定义任务
      • @param clazz 任务执行类
      • @return
        */
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public boolean start(Job job, Class clazz) {
        boolean result = true;
        try {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        if (null == cronTrigger) {
        // 处理参数
        Map map = new HashMap<>(5);
        String jobDataMap = job.getJobDataMap();
        if (StrUtil.isNotBlank(jobDataMap)) {
        if (JSONUtil.isJson(jobDataMap)) {
        Map parseMap = JSONUtil.toBean(jobDataMap, Map.class);
        parseMap.forEach((k, v) -> {
        map.put(String.valueOf(k), String.valueOf(v));
        });
        }
        }
        // 启动定时任务
        JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobName, jobGroup)
        .setJobData(new JobDataMap(map)).build();
        cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup)
        .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())).build();
        scheduler.scheduleJob(jobDetail, cronTrigger);
        if (!scheduler.isShutdown()) {
        scheduler.start();
        }
        } else {
        // 重启定时任务
        cronTrigger = cronTrigger.getTriggerBuilder().withIdentity(triggerKey)
        .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())).build();
        scheduler.rescheduleJob(triggerKey, cronTrigger);
        }
        } catch (SchedulerException e) {
        log.info("新增定时任务异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 暂停定时任务
        *
      • @param job 定时任务
      • @return
        */
        public boolean pasue(Job job) {
        boolean result = true;
        try {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        JobKey jobKey = trigger.getJobKey();
        scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
        log.info("暂停定时任务异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 重启定时任务
        *
      • @param job 定时任务
      • @return
        */
        public boolean restart(Job job) {
        boolean result = true;
        try {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
        log.info("重启定时任务异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 立即执行一次
        *
      • @param job 定时任务
      • @return
        */
        public boolean trigger(Job job) {
        boolean result = true;
        try {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        JobKey jobKey = trigger.getJobKey();
        scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
        log.info("立即执行一次异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 修改触发时间表达式
        *
      • @param job 定时任务
      • @param newCronExpression 新的cron表达式
      • @return
        */
        public boolean updateCronExpression(Job job, String newCronExpression) {
        boolean result = true;
        try {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        job.setCronExpression(newCronExpression);
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        cronTrigger = cronTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder)
        .build();
        scheduler.rescheduleJob(triggerKey, cronTrigger);
        } catch (SchedulerException e) {
        log.info("修改触发时间表达式异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 删除定时任务
        *
      • @param job 定时任务
      • @return
        */
        public boolean delete(Job job) {
        boolean result = true;
        try {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        JobKey jobKey = trigger.getJobKey();
        // 停止触发器
        scheduler.pauseTrigger(triggerKey);
        // 移除触发器
        scheduler.unscheduleJob(triggerKey);
        // 删除任务
        scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
        log.info("删除定时任务异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /***

      • 判断是否存在定时任务
        *
      • @param job 定时任务
      • @return
        */
        public boolean has(Job job) {
        boolean result = true;
        try {
        if (!scheduler.isShutdown()) {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        result = (trigger != null) ? true : false;
        } else {
        result = false;
        }
        } catch (SchedulerException e) {
        log.info("判断是否存在定时任务异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 获得定时任务状态
        *
      • @param job 定时任务
      • @return
        */
        public String getStatus(Job job) {
        String status = StrUtil.EMPTY;
        try {
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        TriggerState triggerState = scheduler.getTriggerState(triggerKey);
        status = triggerState.toString();
        } catch (Exception e) {
        log.info("获得定时任务状态异常:{}", e.getMessage());
        }
        return StrUtil.isNotEmpty(status) ? status : TriggerState.NONE.toString();
        }

      /**

      • 启动调度器
        *
      • @return
        */
        public boolean startScheduler() {
        boolean result = true;
        try {
        scheduler.start();
        } catch (SchedulerException e) {
        log.info("启动调度器异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 关闭调度器
        *
      • @return
        */
        public boolean standbyScheduler() {
        boolean result = true;
        try {
        if (!scheduler.isShutdown()) {
        scheduler.standby();
        }
        } catch (SchedulerException e) {
        log.info("关闭调度器异常:{}", e.getMessage());
        result = false;
        }
        return result;
        }

      /**

      • 判断调度器是否为开启状态
        *
      • @return
        */
        public boolean isStarted() {
        boolean result = true;
        try {
        result = scheduler.isStarted();
        } catch (SchedulerException e) {
        log.info("判断调度器是否为开启状态异常:{}", e.getMessage());
        }
        return result;
        }

      /**

      • 判断调度器是否为关闭状态
        *
      • @return
        */
        public boolean isShutdown() {
        boolean result = true;
        try {
        result = scheduler.isShutdown();
        } catch (SchedulerException e) {
        log.info("判断调度器是否为关闭状态异常:{}", e.getMessage());
        }
        return result;
        }

      /**

      • 判断调度器是否为待机状态
        *
      • @return
        */
        public boolean isInStandbyMode() {
        boolean result = true;
        try {
        result = scheduler.isInStandbyMode();
        } catch (SchedulerException e) {
        log.info("判断调度器是否为待机状态异常:{}", e.getMessage());
        }
        return result;
        }

      /**

      • 获得下一次执行时间
        *
      • @param cronExpression cron表达式
      • @return
        */
        public LocalDateTime nextfireDate(String cronExpression) {
        LocalDateTime localDateTime = null;
        try {
        if (StrUtil.isNotEmpty(cronExpression)) {
        CronExpression ce = new CronExpression(cronExpression);
        Date nextInvalidTimeAfter = ce.getNextInvalidTimeAfter(new Date());
        localDateTime = Instant.ofEpochMilli(nextInvalidTimeAfter.getTime()).atZone(ZoneId.systemDefault())
        .toLocalDateTime();
        }
        } catch (ParseException e) {
        log.info("获得下一次执行时间异常:{}", e.getMessage());
        }
        return localDateTime;
        }

    }

  • 创建Mapper

    import org.apache.ibatis.annotations.Mapper;

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.c3stones.job.entity.Job;

    /**

    • 定时任务Mapper
      *
    • @author CL
      *
      */
      @Mapper
      public interface JobMapper extends BaseMapper {

    }

  • 创建Service

    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.c3stones.job.entity.Job;

    /**

    • 定时任务Service
      *

    • @author CL
      *
      */
      public interface JobService extends IService {

      /**

      • 查询列表数据
        *
      • @param job 系统用户
      • @param current 当前页
      • @param size 每页显示条数
      • @return
        */
        public Page listData(Job job, long current, long size);

    }

  • 创建Service实现类

    import java.util.List;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.c3stones.job.config.QuartzHandler;
    import com.c3stones.job.entity.Job;
    import com.c3stones.job.mapper.JobMapper;
    import com.c3stones.job.service.JobService;

    import cn.hutool.core.util.StrUtil;

    /**

    • 定时任务Service实现
      *

    • @author CL
      *
      */
      @Service
      public class JobServiceImpl extends ServiceImpl implements JobService {

      @Autowired
      private QuartzHandler quartzHandler;

      /**

      • 查询列表数据
        *

      • @param job 系统用户

      • @param current 当前页

      • @param size 每页显示条数

      • @return
        */
        @Override
        public Page listData(Job job, long current, long size) {
        QueryWrapper queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(job.getJobName())) {
        queryWrapper.like("job_name", job.getJobName());
        }
        Page page = baseMapper.selectPage(new Page<>(current, size), queryWrapper);
        List records = page.getRecords();

        // 处理定时任务数据
        for (int i = 0; i < records.size(); i++) {
        Job j = records.get(i);
        // 获取下一次执行时间
        j.setNextfireDate(quartzHandler.nextfireDate(j.getCronExpression()));

        // 更新状态
        String status = quartzHandler.getStatus(j);
        if (!(status).equals(j.getStatus())) {
            j.setStatus(status);
            super.updateById(j);
        }
        
        records.set(i, j);

        }
        page.setRecords(records);
        return page;
        }
        }

  • 创建Controller

    import java.time.LocalDateTime;

    import org.quartz.Trigger.TriggerState;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.util.Assert;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;

    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    import com.c3stones.common.vo.Response;
    import com.c3stones.job.config.QuartzHandler;
    import com.c3stones.job.entity.Job;
    import com.c3stones.job.service.JobService;
    import com.c3stones.sys.entity.User;
    import com.c3stones.sys.utils.UserUtils;

    /**

    • 定时任务Controller
      *

    • @author CL
      *
      */
      @Controller
      @RequestMapping(value = "job")
      public class JobController {

      @Autowired
      private QuartzHandler quartzHandler;

      @Autowired
      private JobService jobService;

      /**

      • 查询列表
        *
      • @return
        */
        @RequestMapping(value = "list")
        public String list() {
        return "pages/job/jobList";
        }

      /**

      /**

      • 更新
        *
      • @param job 定时任务
      • @return
        */
        @RequestMapping(value = "update")
        @ResponseBody
        public Response update(Job job) {
        Assert.notNull(job.getId(), "ID不能为空");
        User user = UserUtils.get();
        if (user != null) {
        job.setUpdateUserId(user.getId());
        }
        LocalDateTime now = LocalDateTime.now();
        job.setUpdateDate(now);
        boolean result = jobService.updateById(job);
        Job queryJob = jobService.getById(job.getId());
        String status = quartzHandler.getStatus(queryJob);
        if (!(TriggerState.NONE.toString()).equals(status)) {
        result = quartzHandler.updateCronExpression(queryJob, queryJob.getCronExpression());
        }
        return Response.success("更新" + (result ? "成功" : "失败"), result);
        }

      /**

      • 删除
        *
      • @param job 定时任务
      • @return
        */
        @RequestMapping(value = "delete")
        @ResponseBody
        public Response delete(Job job) {
        Assert.notNull(job.getId(), "ID不能为空");
        Job queryJob = jobService.getById(job.getId());
        boolean result = true;
        if (!(TriggerState.NONE.toString()).equals(queryJob.getStatus())) {
        result = quartzHandler.delete(queryJob);
        }
        if (result) {
        result = jobService.removeById(job.getId());
        }
        return Response.success("删除" + (result ? "成功" : "失败"), result);
        }

      /**

      • 启动
        *
      • @param job 定时任务
      • @return
      • @throws ClassNotFoundException
        */
        @RequestMapping(value = "start")
        @ResponseBody
        public Response start(Job job) throws ClassNotFoundException {
        Assert.notNull(job.getId(), "ID不能为空");
        Job queryJob = jobService.getById(job.getId());
        Assert.notNull(queryJob, "定时任务不存在");
        Class clazz = Class.forName(queryJob.getBeanClass());
        Assert.notNull(clazz, "未找到任务执行类");
        boolean result = quartzHandler.start(queryJob, clazz);
        return Response.success("启动" + (result ? "成功" : "失败"), result);
        }

      /**

      • 暂停
        *

      • @param job 定时任务

      • @return
        */
        @RequestMapping(value = "pasue")
        @ResponseBody
        public Response pasue(Job job) {
        Assert.notNull(job.getId(), "ID不能为空");
        Job queryJob = jobService.getById(job.getId());
        Assert.notNull(queryJob, "定时任务不存在");

        String status = quartzHandler.getStatus(queryJob);
        if (!((TriggerState.NORMAL.toString()).equals(status) || (TriggerState.PAUSED.toString()).equals(status)
        || (TriggerState.BLOCKED.toString()).equals(status))) {
        return Response.success("当前状态不可暂停", false);
        }
        if ((TriggerState.PAUSED.toString()).equals(status)) {
        return Response.success("已暂停", false);
        }

        boolean result = quartzHandler.pasue(queryJob);
        return Response.success("暂停" + (result ? "成功" : "失败"), result);
        }

      /**

      • 立即执行
        *

      • @param job 定时任务

      • @return
        */
        @RequestMapping(value = "trigger")
        @ResponseBody
        public Response trigger(Job job) {
        Assert.notNull(job.getId(), "ID不能为空");
        Job queryJob = jobService.getById(job.getId());
        Assert.notNull(queryJob, "定时任务不存在");

        String status = quartzHandler.getStatus(queryJob);
        if (!((TriggerState.NORMAL.toString()).equals(status) || (TriggerState.PAUSED.toString()).equals(status)
        || (TriggerState.COMPLETE.toString()).equals(status))) {
        return Response.success("当前状态不可立即执行", false);
        }

        boolean result = quartzHandler.trigger(queryJob);
        return Response.success("立即执行" + (result ? "成功" : "失败"), result);
        }

      /**

      • 判断定时器是否为待机模式
        */
        @RequestMapping(value = "isInStandbyMode")
        @ResponseBody
        public Response isInStandbyMode() {
        boolean result = quartzHandler.isInStandbyMode();
        return Response.success(result);
        }

      /**

      • 启动定时器
        *
      • @return
        */
        @RequestMapping(value = "startScheduler")
        @ResponseBody
        public Response startScheduler() {
        boolean result = quartzHandler.startScheduler();
        return Response.success("启动定时器" + (result ? "成功" : "失败"), result);
        }

      /**

      • 待机定时器
        *
      • @return
        */
        @RequestMapping(value = "standbyScheduler")
        @ResponseBody
        public Response standbyScheduler() {
        boolean result = quartzHandler.standbyScheduler();
        return Response.success("关闭定时器" + (result ? "成功" : "失败"), result);
        }

      /**

      /**

      • 保存
        *
      • @return
        */
        @RequestMapping(value = "save")
        @ResponseBody
        public Response save(Job job) {
        User user = UserUtils.get();
        if (user != null) {
        job.setCreateUserId(user.getId());
        job.setUpdateUserId(user.getId());
        }
        LocalDateTime now = LocalDateTime.now();
        job.setCreateDate(now);
        job.setUpdateDate(now);
        boolean result = jobService.save(job);
        return Response.success(result);
        }

    }

  • 主页index.html配置菜单



    C3Stones

        <div class="layui-side custom-admin">
            <div class="layui-side-scroll">
                <div class="custom-logo">
                    <img alt="" th:src="@{/images/logo.jpg}">
                    <h1>C3Stones</h1>
                </div>
                <ul id="Nav" class="layui-nav layui-nav-tree">
                    <li class="layui-nav-item">
                        <a href="javascript:;">
                            <i class="layui-icon"></i>
                            <em>主页</em>
                        </a>
                        <dl class="layui-nav-child">
                            <dd><a th:href="@{/view}">控制台</a></dd>
                        </dl>
                    </li>
                    <li class="layui-nav-item">
                        <a href="javascript:;">
                            <i class="layui-icon"></i>
                            <em>系统管理</em>
                        </a>
                        <dl class="layui-nav-child">
                            <dd><a th:href="@{/user/list}">用户管理</a></dd>
                        </dl>
                        <dl class="layui-nav-child">
                            <dd><a th:href="@{/job/list}">任务调度</a></dd>
                        </dl>
                    </li>
                </ul>
        &lt;/div&gt;
    &lt;/div&gt;
    
    &lt;div class="layui-body"&gt;
         &lt;div class="layui-tab app-container" lay-allowClose="true" lay-filter="tabs"&gt;
            &lt;ul id="appTabs" class="layui-tab-title custom-tab"&gt;&lt;/ul&gt;
            &lt;div id="appTabPage" class="layui-tab-content"&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    
    &lt;div class="layui-footer"&gt;
        &lt;p&gt; 2020 - C3Stones Blog : &lt;a href="https://www.cnblogs.com/cao-lei/" target="_blank"&gt;https://www.cnblogs.com/cao-lei/&lt;/a&gt;&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="mobile-mask"&gt;&lt;/div&gt;
    </div>


  • 新增定时任务列表页面jobList.html




    任务调度(定时器状态:
    任务名称:

  • 新增定时任务新增页面jobAdd.html




    任务分组
    包名 + 类名,示例:com.c3stones.job.biz.TestJob
    示例:{"username":"zhangsan", "age":18}

5. 测试

  • 创建两种类型Job

    • 实现Job接口

      import java.time.LocalDateTime;

      import org.quartz.Job;
      import org.quartz.JobDataMap;
      import org.quartz.JobExecutionContext;
      import org.quartz.JobExecutionException;
      import org.springframework.beans.factory.annotation.Autowired;

      import com.c3stones.job.service.JobService;

      import lombok.extern.slf4j.Slf4j;

      /**

      • 测试定时任务
        *

      • @author CL
        *
        */
        @Slf4j
        // @DisallowConcurrentExecution //不并发执行
        public class TestJob implements Job {

        @Autowired
        private JobService jobService;

        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        log.info("定时任务1 => 定时任务定时任务数量 => {},参数值 => {},当前时间 => {}", jobService.count(),
        "{ username=" + jobDataMap.get("username") + ", age=" + jobDataMap.get("age") + " }",
        LocalDateTime.now());
        }

      }

    • 继承QuartzJobBean类

      import java.time.LocalDateTime;

      import org.quartz.JobDataMap;
      import org.quartz.JobExecutionContext;
      import org.quartz.JobExecutionException;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.scheduling.quartz.QuartzJobBean;

      import com.c3stones.job.service.JobService;

      import lombok.extern.slf4j.Slf4j;

      /**

      • 测试定时任务
        *

      • @author CL
        *
        */
        @Slf4j
        // @DisallowConcurrentExecution //不并发执行
        public class Test2Job extends QuartzJobBean {

        @Autowired
        private JobService jobService;

        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        log.info("定时任务2 => 定时任务数量 => {},参数值 => {},当前时间 => {}", jobService.count(),
        "{ username=" + jobDataMap.get("username") + ", age=" + jobDataMap.get("age") + " }",
        LocalDateTime.now());
        }

      }

  • 配置定时任务

      浏览器访问:http://127.0.0.1:8080/login,填写用户信息user/123456登录系统,点击菜单:系统管理>任务调度,通过新增页面,添加两个定时任务。配置完成页面如下:

      顶部按钮:定时器待机启动定时器为定时器操作按钮,即对所有定时任务有效。当定时器状态为启动中时,定时器待机显示,点击定时器状态变为待机中,所有定时任务待机;反之,所有定时任务可正常触发。

      右侧操作栏按钮:启动暂停立即执行删除,仅对当前定时任务有效。新增完的定时任务为未启动状态,点击启动按钮即可触发定时任务,点击暂停按钮即可暂停定时任务,点击立即执行按钮即可立即执行一次定时任务,点击删除按钮即可删除定时任务。

  • 点击操作按钮,观察控制台日志打印

6. 项目地址

  spring-boot-quartz-demo

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章