Springboot项目,动态配置定时任务简单代码示例(代码均已测试)

Springboot项目,动态配置定时任务代码示例

一、基于ThreadPoolTaskScheduler动态配置定时任务

ThreadPoolTaskScheduler 是 Spring 框架中的一个特殊的 TaskScheduler 实现,它使用线程池来执行定时任务。

在 Spring 框架中,TaskScheduler 接口提供了一种方便的方式来执行定时任务。ThreadPoolTaskSchedulerTaskScheduler 接口的一个具体实现,它使用线程池来管理任务的执行。使用线程池可以有效地管理任务的执行,避免每个任务都创建一个新的线程,从而降低了系统的开销。

ThreadPoolTaskScheduler 具有以下特点:

  1. 线程池管理: 它使用一个线程池来执行任务,可以配置线程池的大小、线程池的类型(如固定大小的线程池、可缓存的线程池等)等参数。
  2. 并发执行: 它可以同时执行多个任务,提高了任务的并发性能。
  3. 任务调度: 它支持在指定的时间间隔、固定的延迟或者特定的时间点执行任务,提供了灵活的任务调度功能。
  4. 异常处理: 它提供了异常处理机制,可以处理任务执行过程中抛出的异常,保证任务的稳定执行。
  5. Spring 集成: 作为 Spring 框架的一部分,ThreadPoolTaskScheduler 可以与其他 Spring 组件(如 @Scheduled 注解、TaskExecutor 接口等)无缝集成,方便地管理和调度任务。

使用 ThreadPoolTaskScheduler 可以轻松地实现在 Spring 应用中的定时任务调度,提高了系统的可靠性和性能。

示例代码:

java 复制代码
package com.jlstest.threadPoolTaskSchedulerDemo.service;
​
import com.jlstest.threadPoolTaskSchedulerDemo.entity.CronEntity;
​
/**
 * @className: CronService
 * @Description: TODO
 * @author: JLS
 * @date: 2023/2/3 9:39
 */
public interface CronService {
​
    /**
     * 开始定时任务
     * 
     * @param cron
     *            定时任务信息
     */
    void startCron(CronEntity cron);
​
    /**
     * 结束定时任务
     * 
     * @param cron
     *            定时任务信息
     */
    void stopCron(CronEntity cron);
​
    /**
     * 修改定时任务
     */
    void changeCron(CronEntity cron);
}
​
java 复制代码
package com.jlstest.threadPoolTaskSchedulerDemo.service.impl;
​
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
​
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
​
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
​
import com.alibaba.fastjson.JSON;
import com.example.common.exception.ServiceException;
import com.jlstest.threadPoolTaskSchedulerDemo.dao.CronManagementDao;
import com.jlstest.threadPoolTaskSchedulerDemo.entity.CronEntity;
import com.jlstest.threadPoolTaskSchedulerDemo.service.CronService;
import com.jlstest.threadPoolTaskSchedulerDemo.utils.CronUtils;
​
import lombok.extern.slf4j.Slf4j;
​
/**
 * @author JLS
 * @description:
 * @since 2023-02-03 09:40
 */
@Service
@Slf4j
public class CronServiceImpl implements CronService {
​
    @Resource
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
​
    @Resource
    private CronManagementDao cronManagementDao;
​
    private final Map<Long, ScheduledFuture<?>> futureMap = new HashMap<>();
​
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        return new ThreadPoolTaskScheduler();
    }
​
    // 初始化,当服务重启则重启对应的定时任务
    @PostConstruct
    public void init() {
        List<CronEntity> cronEntityList = cronManagementDao.selectCronManagementAll();
​
        // 校验是否有定时任务,如果有则启动
        if (CollectionUtils.isEmpty(cronEntityList)) {
            return;
        }
        // 遍历每个定时任务
        cronEntityList.forEach(cron -> {
            if (LocalDateTime.now().isAfter(cron.getDeadTime())) {
                cronManagementDao.deleteCronManagement(cron.getId());
                log.info("删除过期定时任务成功,任务id:{},任务标题:{},任务开始时间:{},任务截止时间:{}", cron.getId(), cron.getTitle(), cron.getStartTime(), cron.getDeadTime());
            } else {
                // 启动任务
                startCron(cron);
            }
        });
    }
​
    /**
     * 开始定时任务
     *
     * @param cron
     *            定时任务信息
     */
    @Override
    public void startCron(CronEntity cron) {
        if (futureMap.containsKey(cron.getId())) {
            log.warn("已经存在重复任务,任务id:{},任务标题:{},任务开始时间:{},任务截止时间:{}", cron.getId(), cron.getTitle(), cron.getStartTime(), cron.getDeadTime());
            return;
        }
​
        // 校验cron表达式是否合法
        if (CronUtils.isValid(cron.getCronExp())) {
            log.error("cron表达式不合法,报文:{}", JSON.toJSONString(cron));
            throw new ServiceException("cron表达式不合法");
        }
​
        // 校验时间,通过后开始设置定时任务
        if (LocalDateTime.now().isBefore(cron.getDeadTime()) || cron.getDeadTime() == null) {
​
            // 校验cron表达式是否合法
            CronUtils.isValid(cron.getCronExp());
            ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(new MyRunnable(cron), new CronTrigger(cron.getCronExp()));
            // 插入数据库
            if (cron.getId() == null) {
                cronManagementDao.insertCronManagement(cron);
            }
            futureMap.put(cron.getId(), future);
            log.info("启动定时任务成功,任务id:{},任务标题:{},任务开始时间:{},任务截止时间:{}", cron.getId(), cron.getTitle(), cron.getStartTime(), cron.getDeadTime());
        }
    }
​
    /**
     * 结束定时任务
     *
     * @param cron
     *            定时任务信息
     */
    @Override
    public void stopCron(CronEntity cron) {
        ScheduledFuture<?> future = futureMap.get(cron.getId());
        if (future != null) {
            future.cancel(true);
            futureMap.remove(cron.getId());
            log.info("关闭定时任务成功,任务id:{},任务标题:{},任务开始时间:{},任务截止时间:{}", cron.getId(), cron.getTitle(), cron.getStartTime(), cron.getDeadTime());
            cronManagementDao.deleteCronManagement(cron.getId());
        }
    }
​
    /**
     * 修改定时任务
     *
     * @param cron
     *            定时任务信息
     */
    @Override
    public void changeCron(CronEntity cron) {
        // 先停止,在开启.
        stopCron(cron);
        cron.setId(null);
        startCron(cron);
    }
​
    private class MyRunnable implements Runnable {
        private CronEntity cron;
​
        public MyRunnable(CronEntity cron) {
            this.cron = cron;
        }
​
        @Override
        public void run() {
            // 检查当前时间是否已经到了任务的截止时间
            if (LocalDateTime.now().isEqual(cron.getDeadTime()) || LocalDateTime.now().isAfter(cron.getDeadTime())) {
                // 如果已经到了截止时间,那么停止任务
                stopCron(cron);
            }
            // 校验当前时间是否已经到了任务指定的开始执行时间,没到则不指定定时任务
            if (LocalDateTime.now().isBefore(cron.getStartTime())) {
                log.info("任务还未到开始时间,任务id:{}", cron.getTitle());
                return;
            }
​
            // 定义任务要做的事,完成任务逻辑
            log.info("定时任务测试,定时任务id:{},当前时间为:{}", cron.getTitle(), LocalDateTime.now());
            // todo 可以根据任务id编写对应的定时任务逻辑
        }
    }
​
    public static void main(String[] args) {
        System.out.println(LocalDateTime.now());
    }
}
​

代码较为简单,主要包括了新建定时任务,暂停定时任务,修改定时任务的功能;

实体类:

java 复制代码
package com.jlstest.threadPoolTaskSchedulerDemo.entity;
​
import java.io.Serializable;
import java.time.LocalDateTime;
​
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
​
/**
 * @author JLS
 * @description:
 * @since 2023-02-03 09:32
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class CronEntity implements Serializable {
​
    private static final long serialVersionUID = 1L;
​
    /**
     * 主键id
     */
    private Long id;
​
    /**
     * 标题
     */
    private String title;
​
    /**
     * 截止时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime deadTime;
​
    /**
     * 开始时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime startTime;
​
    /**
     * cron表达式
     */
    private String cronExp;
}

数据库操作方法:

java 复制代码
package com.jlstest.threadPoolTaskSchedulerDemo.dao;
​
import com.jlstest.threadPoolTaskSchedulerDemo.entity.CronEntity;
import org.apache.ibatis.annotations.Mapper;
​
import java.util.List;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-19 14:41
 */
@Mapper
public interface CronManagementDao {
​
    /**
     * 新增定时任务
     */
    void insertCronManagement(CronEntity cronEntity);
​
    /**
     * 修改定时任务
     */
    int updateCronManagement(CronEntity cronEntity);
​
    /**
     * 删除定时任务
     */
    int deleteCronManagement(Long id);
​
    /**
     * 查询定时任务
     */
    CronEntity selectCronManagement(Long id);
​
    /**
     * 查询所有定时任务
     */
    List<CronEntity> selectCronManagementAll();
​
}
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jlstest.threadPoolTaskSchedulerDemo.dao.CronManagementDao">
​
    <resultMap id="map" type="com.jlstest.threadPoolTaskSchedulerDemo.entity.CronEntity">
        <id column="id" property="id"/>
        <result column="title" property="title"/>
        <result column="dead_time" property="deadTime"/>
        <result column="start_time" property="startTime"/>
        <result column="cron_exp" property="cronExp"/>
    </resultMap>
​
    <select id="selectCronManagementAll" resultMap="map">
        select * from cron_management
    </select>
​
    <select id="selectCronManagement" resultMap="map">
        select * from cron_management where id = #{id}
    </select>
​
    <insert id="insertCronManagement" parameterType="com.jlstest.threadPoolTaskSchedulerDemo.entity.CronEntity" useGeneratedKeys="true" keyProperty="id">
        insert into cron_management (title, dead_time, start_time, cron_exp) values (#{title}, #{deadTime}, #{startTime}, #{cronExp})
    </insert>
​
    <update id="updateCronManagement" parameterType="com.jlstest.threadPoolTaskSchedulerDemo.entity.CronEntity">
        update cron_management
        <set>
            <if test="title != null and title != ''">
                title = #{title},
            </if>
            <if test="deadTime != null">
                dead_time = #{deadTime},
            </if>
            <if test="startTime != null">
                start_time = #{startTime},
            </if>
            <if test="cronExp != null and cronExp != ''">
                cron_exp = #{cronExp},
            </if>
        </set>
        where id = #{id}
    </update>
​
    <delete id="deleteCronManagement" parameterType="Long">
        delete from cron_management where id = #{id}
    </delete>
</mapper>
​
<!-- 数据库建表语句
create table if not exists cron_management
(
    id          BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键id',
    title       VARCHAR(255) COMMENT '标题',
    dead_time    datetime COMMENT '截止时间',
    start_time   datetime COMMENT '开始时间',
    cron_exp     VARCHAR(255) COMMENT 'cron表达式',
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
    comment 'cron任务信息调度记录表';
-->

具体的实际使用示例:

kotlin 复制代码
package com.jlstest.threadPoolTaskSchedulerDemo.controller;
​
import javax.annotation.Resource;
​
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
import com.example.common.response.JlsTestResponse;
import com.jlstest.threadPoolTaskSchedulerDemo.entity.CronEntity;
import com.jlstest.threadPoolTaskSchedulerDemo.service.CronService;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-20 10:16
 */
@RestController
@RequestMapping("/threadPoolTaskTest")
public class ThreadPoolTaskTestController {
​
    @Resource
    private CronService cronService;
​
    /**
     * 新建定时任务
     */
    @PutMapping("/addCron")
    public JlsTestResponse<Object> addCron(@RequestBody CronEntity cronEntity) {
        // 新建定时任务
        cronService.startCron(cronEntity);
        return JlsTestResponse.sendSuccess("新建定时任务成功");
    }
​
    /**
     * 停止定时任务
     */
    @DeleteMapping("/stopCron")
    public JlsTestResponse<Object> stopCron(@RequestBody CronEntity cronEntity) {
        // 停止定时任务
        cronService.stopCron(cronEntity);
        return JlsTestResponse.sendSuccess("停止定时任务成功");
    }
​
    /**
     * 修改定时任务
     */
    @PostMapping("/updateCron")
    public JlsTestResponse<Object> updateCron(@RequestBody CronEntity cronEntity) {
        // 修改定时任务
        cronService.changeCron(cronEntity);
        return JlsTestResponse.sendSuccess("修改定时任务成功");
    }
}
1.定时间段定时任务示例:

接口:/threadPoolTaskTest/addCron

请求参数:

json 复制代码
{
  "title": "定时任务测试1",
  "deadTime": "2024-02-20 10:51:00",
  "startTime": "2024-02-20 10:50:00",
  "cronExp": "* * * * *"
}

设置定时任务,名称为定时任务测试1,从2024-02-20 14:50:00开始执行定时任务2024-02-20 14:51:00终止定时任务,期间每秒执行一次

,控制台显示的内容

开始执行定时任务:

定时任务执行结束:

2.其他定时任务功能展示

开始执行定时任务:

数据库内容展示:

然后在接口: /threadPoolTaskTest/stopCron

参数:

json 复制代码
{
  "id": 23,
  "title": "定时任务测试1",
  "deadTime": "2024-02-21 10:36:59",
  "startTime": "2024-02-20 10:36:59",
  "cronExp": "* * * * * *"
}

暂停定时任务

接口返回:

控制台显示,结束后数据库的定时任务也会删除,

总结

实际应用中,也可以根据业务需要设置对应的定时任务状态以及其他的一些改造。

二、基于quartz包的动态配置定时任务

Quartz 是一个功能强大的开源调度框架,它允许你基于 Cron 表达式或者固定的时间间隔执行任务。使用 Quartz,你可以轻松地实现动态配置和管理定时任务。

  • scheduleTask 方法用于添加新的定时任务,它接受任务的唯一标识符(taskId)、任务类(实现了 Job 接口的类)和 Cron 表达式作为参数,并将任务调度添加到 Quartz 调度器中。
  • updateTask 方法用于更新现有的定时任务,它首先获取任务的触发器(Trigger),然后更新触发器的 Cron 表达式,最后重新调度任务。
  • removeTask 方法用于移除指定的定时任务,它暂停任务的触发器、移除触发器,并删除任务。

你需要在 Spring 应用中将这个类作为一个组件(Component)进行管理,这样就可以通过注入的方式来使用它,并在需要的时候添加、更新或删除定时任务。

示例代码

1.config包下

kotlin 复制代码
package com.jlstest.sysJobDemo.config;
​
import org.quartz.Scheduler;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-20 11:18
 */
​
@Configuration
public class QuartzConfiguration {
​
    @Bean
    public Scheduler scheduler() throws Exception {
        return StdSchedulerFactory.getDefaultScheduler();
    }
}

2.constant包下

arduino 复制代码
package com.jlstest.sysJobDemo.constant;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 15:00
 */
public class ScheduleConstants {
​
    public static enum Status {
        /**
         * 正常
         */
        NORMAL("0"),
        /**
         * 暂停
         */
        PAUSE("1");
​
        private final String value;
​
        Status(String value) {
            this.value = value;
        }
​
        public String getValue() {
            return value;
        }
    }
​
    public static final String TASK_PROPERTIES = "job";
}

3.dao包下

java 复制代码
package com.jlstest.sysJobDemo.dao;
​
import com.jlstest.sysJobDemo.entity.SysJob;
import org.apache.ibatis.annotations.Mapper;
​
import java.util.List;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 15:32
 */
@Mapper
public interface SysJobMapper {
​
    List<SysJob> selectJobAll();
​
    List<SysJob> selectJobList(SysJob job);
​
    SysJob selectJobById(Long jobId);
​
    int updateJob(SysJob job);
​
    int deleteJobById(Long jobId);
​
    int insertJob(SysJob job);
​
}

对应的xml:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jlstest.sysJobDemo.dao.SysJobMapper">
​
    <resultMap id="sysJobResultMap" type="com.jlstest.sysJobDemo.entity.SysJob">
        <result column="job_id" property="jobId" />
        <result column="job_name" property="jobName" />
        <result column="job_group" property="jobGroup" />
        <result column="method_name" property="methodName" />
        <result column="method_params" property="methodParams" />
        <result column="cron_expression" property="cronExpression" />
        <result column="status" property="status" />
        <result column="remark" property="remark" />
        <result column="create_by" property="createBy" />
        <result column="create_time" property="createTime" />
        <result column="update_by" property="updateBy" />
        <result column="update_time" property="updateTime" />
    </resultMap>
​
    <select id="selectJobAll" resultMap="sysJobResultMap">
        select * from sys_job
    </select>
​
    <select id="selectJobList" resultMap="sysJobResultMap">
        select * from sys_job
        <where>
            <if test="jobName != null and jobName != ''">
                and job_name like concat('%',#{jobName},'%')
            </if>
            <if test="jobGroup != null and jobGroup != ''">
                and job_group = #{jobGroup}
            </if>
            <if test="status != null and status != ''">
                and status = #{status}
            </if>
        </where>
    </select>
​
    <select id="selectJobById" resultMap="sysJobResultMap">
        select * from sys_job where job_id = #{jobId}
    </select>
​
    <update id="updateJob">
        update sys_job
        <set>
            <if test="jobName != null and jobName != ''">
                job_name = #{jobName},
            </if>
            <if test="jobGroup != null and jobGroup != ''">
                job_group = #{jobGroup},
            </if>
            <if test="methodName != null and methodName != ''">
                method_name = #{methodName},
            </if>
            <if test="methodParams != null and methodParams != ''">
                method_params = #{methodParams},
            </if>
            <if test="cronExpression != null and cronExpression != ''">
                cron_expression = #{cronExpression},
            </if>
            <if test="status != null and status != ''">
                status = #{status},
            </if>
            <if test="remark != null and remark != ''">
                remark = #{remark},
            </if>
            <if test="updateBy != null and updateBy != ''">
                update_by = #{updateBy},
            </if>
            update_time = now()
        </set>
        where job_id = #{jobId}
    </update>
​
    <delete id="deleteJobById">
        delete from sys_job where job_id = #{jobId}
    </delete>
​
    <insert id="insertJob">
        insert into sys_job (job_name, job_group, method_name, method_params, cron_expression, status, remark, create_by, create_time, update_by, update_time)
        values (#{jobName}, #{jobGroup}, #{methodName}, #{methodParams}, #{cronExpression}, #{status}, #{remark}, #{createBy}, now(), #{updateBy}, now())
    </insert>
​
<!--    建表语句:
create table if not exists sys_job
(
    job_id          BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '任务ID',
    job_name        VARCHAR(100) NOT NULL COMMENT '任务名称',
    job_group       VARCHAR(100) NOT NULL COMMENT '任务组名',
    method_name     VARCHAR(100) NOT NULL COMMENT '任务方法',
    method_params   VARCHAR(255) COMMENT '方法参数',
    cron_expression VARCHAR(100) NOT NULL COMMENT 'CRON表达式',
    status          CHAR(1)      NOT NULL COMMENT '任务状态(0正常 1暂停)',
    remark          VARCHAR(255) COMMENT '备注',
    create_by       VARCHAR(50) COMMENT '创建者',
    create_time     TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_by       VARCHAR(50) COMMENT '更新者',
    update_time     TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4
    comment 'job任务调度信息记录表';
    -->
</mapper>

4.entity实体类

typescript 复制代码
package com.jlstest.sysJobDemo.entity;
​
import java.io.Serializable;
import java.util.Date;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 14:44
 */
public class SysJob implements Serializable {
    private static final long serialVersionUID = 1L;
​
    /** 任务ID */
    private Long jobId;
​
    /** 任务名称 */
    private String jobName;
​
    /** 任务组名 */
    private String jobGroup;
​
    /** 任务方法 */
    private String methodName;
​
    /** 方法参数 */
    private String methodParams;
​
    /** CRON表达式 */
    private String cronExpression;
​
    /** 任务状态(0正常 1暂停) */
    private String status;
​
    /** 备注 */
    private String remark;
​
    /** 创建者 */
    private String createBy;
​
    /** 创建时间 */
    private Date createTime;
​
    /** 更新者 */
    private String updateBy;
​
    /** 更新时间 */
    private Date updateTime;
​
    // Getters and setters
    public Long getJobId() {
        return jobId;
    }
​
    public void setJobId(Long jobId) {
        this.jobId = jobId;
    }
​
    public String getJobName() {
        return jobName;
    }
​
    public void setJobName(String jobName) {
        this.jobName = jobName;
    }
​
    public String getJobGroup() {
        return jobGroup;
    }
​
    public void setJobGroup(String jobGroup) {
        this.jobGroup = jobGroup;
    }
​
    public String getMethodName() {
        return methodName;
    }
​
    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }
​
    public String getMethodParams() {
        return methodParams;
    }
​
    public void setMethodParams(String methodParams) {
        this.methodParams = methodParams;
    }
​
    public String getCronExpression() {
        return cronExpression;
    }
​
    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }
​
    public String getStatus() {
        return status;
    }
​
    public void setStatus(String status) {
        this.status = status;
    }
​
    public String getRemark() {
        return remark;
    }
​
    public void setRemark(String remark) {
        this.remark = remark;
    }
​
    public String getCreateBy() {
        return createBy;
    }
​
    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }
​
    public Date getCreateTime() {
        return createTime;
    }
​
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
​
    public String getUpdateBy() {
        return updateBy;
    }
​
    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }
​
    public Date getUpdateTime() {
        return updateTime;
    }
​
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
}

5.service包

arduino 复制代码
package com.jlstest.sysJobDemo.service;
​
import com.jlstest.sysJobDemo.entity.SysJob;
import org.quartz.SchedulerException;
​
import java.util.List;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 14:43
 */
public interface SysJobService {
​
    /**
     * 获取quartz调度器的计划任务列表
     */
    List<SysJob> selectJobList(SysJob job);
​
    /**
     * 通过调度任务ID查询调度信息
     */
    SysJob selectJobById(Long jobId);
​
    /**
     * 暂停任务
     */
    int pauseJob(SysJob job) throws SchedulerException;
​
    /**
     * 恢复任务
     */
    int resumeJob(SysJob job) throws SchedulerException;
​
    /**
     * 删除任务后,所对应的trigger也将被删除
     */
    int deleteJob(SysJob job) throws SchedulerException;
​
    /**
     * 批量删除调度信息
     */
    void deleteJobByIds(Long[] jobIds) throws SchedulerException;
​
    /**
     * 任务调度状态修改
     */
    int changeStatus(SysJob job) throws SchedulerException;
​
    /**
     * 立即运行任务
     */
    boolean run(SysJob job) throws SchedulerException;
​
    /**
     * 新增任务
     */
    int insertJob(SysJob job) throws SchedulerException;
​
    /**
     * 更新任务的时间表达式
     */
    int updateJob(SysJob job) throws SchedulerException;
​
    /**
     * 更新任务
     */
    void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException;
​
    /**
     * 校验cron表达式是否有效
     */
    boolean checkCronExpressionIsValid(String cronExpression);
​
}
ini 复制代码
package com.jlstest.sysJobDemo.service.Impl;
​
import java.util.List;
​
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
​
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.TriggerKey;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
​
import com.jlstest.sysJobDemo.constant.ScheduleConstants;
import com.jlstest.sysJobDemo.dao.SysJobMapper;
import com.jlstest.sysJobDemo.entity.SysJob;
import com.jlstest.sysJobDemo.service.SysJobService;
import com.jlstest.sysJobDemo.utils.CronUtils;
import com.jlstest.sysJobDemo.utils.ScheduleUtils;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 14:54
 */
@Service
public class SysJobServiceImpl implements SysJobService {
​
    @Resource
    private Scheduler scheduler;
​
    @Resource
    private SysJobMapper jobMapper;
​
    /**
     * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
     */
    @PostConstruct
    public void init() throws SchedulerException {
        scheduler.clear();
        // 启动调度器 这个一定要写
        scheduler.start();
        List<SysJob> jobList = jobMapper.selectJobAll();
        for (SysJob job : jobList) {
            ScheduleUtils.createScheduleJob(scheduler, job);
        }
    }
​
    /**
     * 获取quartz调度器的计划任务列表
     *
     * @param job
     *            调度信息
     * @return
     */
    @Override
    public List<SysJob> selectJobList(SysJob job) {
        return jobMapper.selectJobList(job);
    }
​
    /**
     * 通过调度任务ID查询调度信息
     *
     * @param jobId
     *            调度任务ID
     * @return 调度任务对象信息
     */
    @Override
    public SysJob selectJobById(Long jobId) {
        return jobMapper.selectJobById(jobId);
    }
​
    /**
     * 暂停任务
     *
     * @param job
     *            调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int pauseJob(SysJob job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        int rows = jobMapper.updateJob(job);
        if (rows > 0) {
            JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
            System.out.println("JobKey: " + jobKey);
​
            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
​
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
            System.out.println("Trigger state: " + triggerState);
        }
​
        // 获取作业的状态
        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (jobDetail != null) {
            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                System.out.println("Trigger state for job " + jobKey + ": " + triggerState);
            }
        } else {
            System.out.println("Job " + jobKey + " not found.");
        }
​
        return rows;
    }
​
    /**
     * 恢复任务
     *
     * @param job
     *            调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int resumeJob(SysJob job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
        int rows = jobMapper.updateJob(job);
        if (rows > 0) {
​
            JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
            System.out.println("JobKey: " + jobKey);
​
            scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
​
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
            System.out.println("Trigger state: " + triggerState);
​
        }
        return rows;
    }
​
    /**
     * 删除任务后,所对应的trigger也将被删除
     *
     * @param job
     *            调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteJob(SysJob job) throws SchedulerException {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        int rows = jobMapper.deleteJobById(jobId);
        if (rows > 0) {
            scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return rows;
    }
​
    /**
     * 批量删除调度信息
     *
     * @param jobIds
     *            需要删除的任务ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteJobByIds(Long[] jobIds) throws SchedulerException {
        for (Long jobId : jobIds) {
            SysJob job = jobMapper.selectJobById(jobId);
            deleteJob(job);
        }
    }
​
    /**
     * 任务调度状态修改
     *
     * @param job
     *            调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int changeStatus(SysJob job) throws SchedulerException {
        int rows = 0;
        String status = job.getStatus();
        if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) {
            rows = resumeJob(job);
        } else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) {
            rows = pauseJob(job);
        }
        return rows;
    }
​
    /**
     * 立即运行任务
     *
     * @param job
     *            调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean run(SysJob job) throws SchedulerException {
        boolean result = false;
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        SysJob properties = selectJobById(job.getJobId());
        // 参数
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
        if (scheduler.checkExists(jobKey)) {
            result = true;
            scheduler.triggerJob(jobKey, dataMap);
        }
        return result;
    }
​
    /**
     * 新增任务
     *
     * @param job
     *            调度信息 调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertJob(SysJob job) throws SchedulerException {
        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
        // 写入数据库
        int rows = jobMapper.insertJob(job);
        // 写入成功后开始添加定时任务
        if (rows > 0) {
            ScheduleUtils.createScheduleJob(scheduler, job);
        }
        return rows;
    }
​
    /**
     * 更新任务的时间表达式
     *
     * @param job
     *            调度信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateJob(SysJob job) throws SchedulerException {
        SysJob properties = selectJobById(job.getJobId());
        int rows = jobMapper.updateJob(job);
        if (rows > 0) {
            updateSchedulerJob(job, properties.getJobGroup());
        }
        return rows;
    }
​
    /**
     * 更新任务
     *
     * @param job
     *            任务对象
     * @param jobGroup
     *            任务组名
     */
    public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException {
        Long jobId = job.getJobId();
        // 判断是否存在
        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
        if (scheduler.checkExists(jobKey)) {
            // 防止创建时存在数据问题 先移除,然后在执行创建操作
            scheduler.deleteJob(jobKey);
        }
        ScheduleUtils.createScheduleJob(scheduler, job);
    }
​
    /**
     * 校验cron表达式是否有效
     *
     * @param cronExpression
     *            表达式
     * @return 结果
     */
    @Override
    public boolean checkCronExpressionIsValid(String cronExpression) {
        return CronUtils.isValid(cronExpression);
    }
​
}
​

6.具体的任务:

java 复制代码
package com.jlstest.sysJobDemo.task;
​
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 14:50
 */
public class Task1Job implements Job {
​
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 编写任务1的具体逻辑
        System.out.println("任务1执行中...");
    }
}

7.utils工具包

typescript 复制代码
package com.jlstest.sysJobDemo.utils;
​
import org.quartz.CronExpression;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 15:17
 */
public class CronUtils {
​
    /**
     * 验证给定的CRON表达式是否有效
     * 
     * @param cronExpression
     *            CRON表达式
     * @return 如果有效返回true,否则返回false
     */
    public static boolean isValid(String cronExpression) {
        try {
            // 使用Quartz提供的CronExpression类解析CRON表达式
            new CronExpression(cronExpression);
            return true;
        } catch (Exception e) {
            // 解析失败则说明不是有效的CRON表达式
            return false;
        }
    }
}
java 复制代码
package com.jlstest.sysJobDemo.utils;
​
import com.jlstest.sysJobDemo.entity.SysJob;
import com.jlstest.sysJobDemo.task.Task1Job;
import org.quartz.CronScheduleBuilder;
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.TriggerBuilder;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-18 14:46
 */
public class ScheduleUtils {
​
    /**
     * 创建定时任务
     * 
     * @param scheduler
     *            调度器
     * @param job
     *            定时任务信息
     * @throws SchedulerException
     */
    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException {
        // 构建定时任务的触发器
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
                .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())).build();
​
        // 构建定时任务的JobDetail 如果有多种任务选择,则根据不同任务创建不同的JobDetail
        JobDetail jobDetail = JobBuilder.newJob(Task1Job.class).withIdentity(job.getJobId().toString(), job.getJobGroup()).build();
​
        // 将任务信息设置到JobDataMap中,传递给任务的执行方法
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        jobDataMap.put("job", job);
​
        // 调度器中添加触发器和JobDetail
        scheduler.scheduleJob(jobDetail, trigger);
    }
​
    /**
     * 根据任务ID和任务组名创建唯一的JobKey
     * 
     * @param jobId
     *            任务ID
     * @param jobGroup
     *            任务组名
     * @return 创建的JobKey对象
     */
    public static JobKey getJobKey(Long jobId, String jobGroup) {
        return new JobKey(String.valueOf(jobId), jobGroup);
    }
}
​

8.pom中的依赖

在pom中记得要加上依赖

xml 复制代码
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.5.0-rc1</version>
        </dependency>

具体代码的作用代码注释中都有写。

9.测试用controller

kotlin 复制代码
package com.jlstest.sysJobDemo.controller;
​
import javax.annotation.Resource;
​
import org.quartz.SchedulerException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
import com.example.common.response.JlsTestResponse;
import com.jlstest.sysJobDemo.entity.SysJob;
import com.jlstest.sysJobDemo.service.SysJobService;
​
/**
 * @author JLS
 * @description:
 * @since 2024-02-20 10:16
 */
@RestController
@RequestMapping("/sysJobTest")
public class SysJobTestController {
​
    @Resource
    private SysJobService sysJobService;
​
    /**
     * 新增任务
     */
    @PutMapping("/insertJob")
    public JlsTestResponse<Object> insertJob(@RequestBody SysJob job) throws SchedulerException {
        int i = sysJobService.insertJob(job);
        if (i > 0) {
            return JlsTestResponse.sendSuccess("新增成功");
        } else {
            return JlsTestResponse.sendFailure("新增失败");
        }
    }
​
    /**
     * 暂停任务
     */
    @PostMapping("/pauseJob")
    public JlsTestResponse<Object> pauseJob(@RequestBody SysJob job) throws SchedulerException {
        int i = sysJobService.pauseJob(job);
        if (i > 0) {
            return JlsTestResponse.sendSuccess("暂停成功");
        } else {
            return JlsTestResponse.sendFailure("暂停失败");
        }
    }
​
    /**
     * 恢复任务
     */
    @PostMapping("/resumeJob")
    public JlsTestResponse<Object> resumeJob(@RequestBody SysJob job) throws SchedulerException {
        int i = sysJobService.resumeJob(job);
        if (i > 0) {
            return JlsTestResponse.sendSuccess("恢复成功");
        } else {
            return JlsTestResponse.sendFailure("恢复失败");
        }
    }
​
    /**
     * 删除任务
     */
    @DeleteMapping("/deleteJob")
    public JlsTestResponse<Object> deleteJob(@RequestBody SysJob job) throws SchedulerException {
        int i = sysJobService.deleteJob(job);
        if (i > 0) {
            return JlsTestResponse.sendSuccess("删除成功");
        } else {
            return JlsTestResponse.sendFailure("删除失败");
        }
    }
​
}

注意要点:

要注意创建任务的时候,选用的主键要拎清楚,也就是构建JobDetail这一步,代码在

utils.ScheduleUtils#createScheduleJob

中,不然的会容易导致任务删除,启用,停用功能失效,

这个主要是测试暂停和恢复的功能,会打印作业的主键值以及对应作业的触发器状态

Trigger state: PAUSED 为暂停,说明定时任务停止

Trigger state: NORMAL 为正常,说明任务正常执行中

三、总结:

以上的代码均为简单的demo,对于不同业务可以有不同的拓展,

具体代码哪一步怎么使用,代码注释中基本都有涵盖

相关推荐
秦淮渔火28 分钟前
Java_集合_单列集合Collection
java·开发语言
Hello Dam29 分钟前
【RocketMQ】RocketMQ发送不同类型消息
java·rocketmq·java-rocketmq·springboot
橘子海全栈攻城狮36 分钟前
【源码+文档+调试讲解】学生选课系统Python
java·开发语言·数据库·python·小程序·sqlite
何政@40 分钟前
Web后端开发原理!!!什么是自动配置???什么是起动依赖???
java·spring boot·spring
霍金的微笑41 分钟前
MYSQL(学习笔记)
java·前端·数据库
拾光师41 分钟前
Spring Cloud全解析:服务调用之OpenFeign简介
java
CopyLower1 小时前
什么东西可以当做GC Root,跨代引用如何处理?
java·jvm·算法
葡萄城技术团队1 小时前
如何借助Java批量操作Excel文件?
java·python·excel
爬山算法1 小时前
Maven(1)什么是Maven?
java·maven
计算机学姐1 小时前
基于SpringBoot+Vue的旅游攻略平台管理系统
java·vue.js·spring boot·后端·intellij-idea·mybatis·旅游