当前位置: 首页 > news >正文

SpringBoot整合Quartz,实现数据库方式执行定时任务

springboot整合quartz,实现数据库方式执行定时任务。把定时任务信息存进数据库,项目启动后自动执行定时任务。

1.引入依赖包:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

2.配置yml:

spring:
  # quartz
  quartz:
    #相关属性配置
    properties:
      org:
        quartz:
          scheduler:
            instanceName: DefaultQuartzScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            tablePrefix: QRTZ_
            isClustered: false
            clusterCheckinInterval: 10000
            #以指示JDBCJobStore将JobDataMaps中的所有值都作为字符串,因此可以作为名称
            #- 值对存储而不是在BLOB列中以其序列化形式存储更多复杂的对象。
            #从长远来看,这是更安全的,因为您避免了将非String类序列化为BLOB的类版本问题。
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true
 
    # 数据库方式
    job-store-type: jdbc
 
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/quartz_test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
 
server:
  port: 8080

3.后端编码:

controller层:

@Controller
@RequestMapping(value = "/job")
@Slf4j
public class JobController {
 
    @Autowired
    private IJobService jobService;
 
 
 
    @PostMapping(value = "/add")
    @ResponseBody
    public Result addJob(@RequestBody JobInfo jobInfo) {
        return jobService.addJob(jobInfo);
    }
 
    @GetMapping(value = "/getAllJobs")
    @ResponseBody
    public List<JobInfo> getAllJobs() {
        return jobService.getAllJobs();
    }
 
    @PostMapping(value = "/pause")
    @ResponseBody
    public Result pauseJob(String name, String group) {
        return jobService.pauseJob(name,group) ? Result.success() : Result.error();
    }
 
    @PostMapping(value = "/resume")
    @ResponseBody
    public Result resumeJob(String name, String group) {
        return jobService.resumeJob(name,group) ? Result.success() : Result.error();
    }
 
    @PostMapping(value = "/reschedule")
    @ResponseBody
    public Result reScheduleJob(String name, String group, String cron) {
        return jobService.reScheduleJob(name, group, cron) ? Result.success() : Result.error();
    }
 
    @PostMapping(value = "/delete")
    @ResponseBody
    public Result deleteJob(String name, String group) {
        return jobService.deleteJob(name,group) ? Result.success() : Result.error();
    }
 
    /**
     * @description 校验是否是合法cron表达式
     * @param  cron
     * @return  com.cxh.cxhquartz.common.Result
     **/
    @PostMapping(value = "/checkCron")
    @ResponseBody
    public Result checkCron(String cron) {
        boolean valide = false;
        try {
            valide = CronExpression.isValidExpression(cron);
        }catch (Exception e){
            log.error(e.getMessage());
        }
        return valide ? Result.success() : Result.error();
    }
}

service层:

public interface IJobService {
 
    /**
     * @description 查询所有任务
     * @param
     * @return  java.util.List<com.cxh.cxhquartz.quartz.JobInfo>
     **/
     List<JobInfo> getAllJobs();
    /**
     * @description 恢复任务
     * @param  jobName
     * @Param  jobGroup
     * @return  boolean
     **/
     boolean resumeJob(String jobName,String jobGroup);
    /**
     * @description 停止任务
     * @param  jobName
     * @Param  jobGroup
     * @return  boolean
     **/
     boolean pauseJob(String jobName,String jobGroup);
    /**
     * @description 修改任务执行周期表达式
     * @param  jobName
     * @Param  jobGroup
     * @Param  cronExpression
     * @return  boolean
     **/
     boolean reScheduleJob(String jobName,String jobGroup,String cronExpression);
    /**
     * @description 删除任务
     * @param  jobName
     * @Param  jobGroup
     * @return  boolean
     **/
     boolean deleteJob(String jobName,String jobGroup);
    /**
     * @description 新增任务
     * @param  jobInfo
     * @return  int
     **/
    Result addJob(JobInfo jobInfo);
     /**
      * @description 判断任务是否存在
      * @param  jobKey
      * @return  int
      **/
     int isJobExist(JobKey jobKey);
}

@Slf4j
@Service
public class JobServiceImpl implements IJobService {
 
    @Autowired
    private Scheduler scheduler;
 
    @Override
    public List<JobInfo> getAllJobs() {
        List<JobInfo> jobInfoList = new ArrayList<>();
        try{
            List<String> groupList = scheduler.getJobGroupNames();
            for(String group : groupList){
                GroupMatcher<JobKey> groupMatcher = GroupMatcher.groupEquals(group);
                Set<JobKey> jobKeySet = scheduler.getJobKeys(groupMatcher);
                for(JobKey jobKey : jobKeySet){
                    JobInfo jobInfo = new JobInfo();
                    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                    jobInfo.setJobname(jobKey.getName());
                    jobInfo.setJobgroup(jobKey.getGroup());
                    jobInfo.setJobclassname(jobDetail.getJobClass().getName());
                    Trigger trigger = scheduler.getTrigger(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup()));
                    if(trigger != null){
                        Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup()));
                        jobInfo.setTriggername(jobKey.getName());
                        jobInfo.setTriggergroup(jobKey.getGroup());
                        try{
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            jobInfo.setCronexpression(cronTrigger.getCronExpression());
                        } catch (Exception e){
                            log.error(e.getMessage());
                        }
                        if(trigger.getNextFireTime() != null){
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            jobInfo.setNextfiretime(sdf.format(trigger.getNextFireTime()));
                        }
                        jobInfo.setDescription(jobDetail.getDescription());
                        jobInfo.setState(state.name());
                        jobInfo.setId(UUID.randomUUID().toString());
                        jobInfoList.add(jobInfo);
                    } else {
                        jobInfo.setState("OVER");
                        jobInfo.setId(UUID.randomUUID().toString());
                        jobInfoList.add(jobInfo);
                    }
                }
            }
        } catch (Exception e){
            log.error(e.getMessage());
        }
        return jobInfoList;
    }
 
    @Override
    public boolean resumeJob(String jobName, String jobGroup) {
        boolean flag = true;
        try{
            scheduler.resumeJob(JobKey.jobKey(jobName, jobGroup));
        } catch (Exception e){
            flag = false;
            log.error(e.getMessage());
        }
        return flag;
    }
 
    @Override
    public boolean pauseJob(String jobName, String jobGroup) {
        boolean flag = true;
        try{
            scheduler.pauseJob(JobKey.jobKey(jobName, jobGroup));
        } catch (Exception e){
            flag = false;
            log.error(e.getMessage());
        }
        return flag;
    }
 
    @Override
    public boolean reScheduleJob(String jobName, String jobGroup, String cronExpression) {
        boolean flag = true;
        try{
           Trigger.TriggerState state = scheduler.getTriggerState(TriggerKey.triggerKey(jobName, jobGroup));
           CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(TriggerKey.triggerKey(jobName, jobGroup));
           if(cronTrigger != null && cronExpression != null && !cronTrigger.getCronExpression().equals(cronExpression)){
               CronTrigger cronTriggerNew = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();
               scheduler.rescheduleJob(TriggerKey.triggerKey(jobName, jobGroup), cronTriggerNew);
               if(state.name().equals("PAUSED")){
                   this.pauseJob(jobName, jobGroup);
               }
           }
        } catch (Exception e){
            flag = false;
            log.error(e.getMessage());
        }
        return flag;
    }
 
    @Override
    public boolean deleteJob(String jobName, String jobGroup) {
        boolean flag = true;
        try{
            List<? extends Trigger> triggerList = scheduler.getTriggersOfJob(JobKey.jobKey(jobName, jobGroup));
            if(triggerList.size() > 0){
                if(!"PAUSED".equals(scheduler.getTriggerState(TriggerKey.triggerKey(jobName, jobGroup)).name())){
                    scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, jobGroup));
                }
                scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, jobGroup));
            }
            scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup));
        } catch (Exception e){
            flag = false;
            log.error(e.getMessage());
        }
        return flag;
    }
 
    @Override
    public Result addJob(JobInfo jobInfo) {
        int isJobExist = this.isJobExist(JobKey.jobKey(jobInfo.getJobname(), jobInfo.getJobgroup()));
        if(isJobExist == 1){
            return Result.error("任务已存在!");
        }
        try{
            JobDetail jobDetail = null;
            if(isJobExist == 0){
                jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobInfo.getJobname(), jobInfo.getJobgroup()));
            } else if(isJobExist == -1){
                jobDetail = JobBuilder.newJob(
                        (Class<? extends Job>) Class.forName(jobInfo.getJobclassname()))
                        .withIdentity(jobInfo.getJobname(), jobInfo.getJobgroup())
                        .withDescription(jobInfo.getDescription())
                        .storeDurably().build();
            }
            //如果jobInfo的cron表达式为空,则创建常规任务,反之创建周期任务
            if(jobInfo.getCronexpression() != null){
                CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(jobInfo.getTriggername(), jobInfo.getTriggergroup())
                        .withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCronexpression()))
                        .build();
                scheduler.scheduleJob(jobDetail, cronTrigger);
 
            } else {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobInfo.getJobname(), jobInfo.getJobgroup())
                        .startAt(sdf.parse(jobInfo.getNextfiretime()))
                        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0))
                        .build();
                scheduler.scheduleJob(jobDetail, trigger);
            }
        } catch (SchedulerException e){
            log.error(e.getMessage());
            return Result.error("添加任务失败!");
        } catch (ParseException e){
            log.error(e.getMessage());
            return Result.error("时间转换出错!");
        } catch (Exception e){
            log.error(e.getMessage());
            return Result.error(e.getMessage());
        }
        return Result.success("添加任务成功!");
    }
 
    @Override
    public int isJobExist(JobKey jobKey) {
       int flag = -1;
       try{
           JobDetail jobDetail = scheduler.getJobDetail(jobKey);
           List<? extends  Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
           if(jobDetail != null && triggers.size() > 0){
               flag = 1;
           } else if(jobDetail != null && triggers.size() == 0){
                flag = 0;
           }
       } catch (Exception e){
           flag = -1;
           log.error(e.getMessage());
       }
       return flag;
    }
}

entity层:

@Data
public class JobInfo implements Serializable {
    private String id;
    private String jobname;
    private String jobgroup;
    private String jobclassname;
    private String triggername;
    private String triggergroup;
    private String cronexpression;
    private String description;
    private String prefiretime;
    private String nextfiretime;
    private String state;
}

定时任务:

@Slf4j
public class DemoJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        log.info("任务名:" + jobDetail.getKey().getName() + ",组名:" +
                jobDetail.getKey().getGroup() + "------执行的定时任务工作内容!");
    }
}

4.创建数据库表:quartz保存定时任务信息表

  5.运行项目,打开postman发起请求:

 6.运行结果:

相关文章:

SpringBoot整合Quartz,实现数据库方式执行定时任务

springboot整合quartz&#xff0c;实现数据库方式执行定时任务。把定时任务信息存进数据库&#xff0c;项目启动后自动执行定时任务。 1.引入依赖包&#xff1a; <dependency> <groupId>org.springframework.boot</groupId> <ar…...

java中多个list怎么用List表示?

如果你有多个List对象&#xff0c;想要将它们合并成一个List对象&#xff0c;可以使用addAll()方法来实现。addAll()方法将会把一个List中的元素逐个添加到另一个List中。 以下是一个示例&#xff0c;展示了如何将多个List对象合并为一个List对象&#xff1a; import java.ut…...

postgresql 数据排序

postgresql 常见操作 排序总结 排序 -- 排序的时候null是最大的值(看一下) select employee_id,manager_id from employeesorder by manager_id desc;-- nulls first使null值排在第一位 select employee_id,manager_id from employeesorder by manager_id nulls first;-- null…...

虚拟机 net、桥接、主机三种网络模式寻根问底

虚拟机使用物理主机上的网络适配器直接连接到物理网络中。 这意味着虚拟机就像是通过网线直接连接到路由器一样,成为物理网络中的一个独立设备。 虚拟机可以获取一个永久的IP地址,通过DHCP或手动设置。 虚拟机和物理主机都可以访问对方以及公共网络中的其他设备,比如文件服务…...

python代码——批量将PPT转换成长图

语言&#xff1a;python 3 用法&#xff1a;点击运行后&#xff0c;弹出窗口&#xff0c;选择文件夹&#xff0c;程序运行会将文件夹内的所有PPT文件全部转换成PPT长图&#xff0c;图片名称与PPT文件名称相同&#xff0c;保存位置相同。 如运行中报错&#xff0c;需要自行根据…...

C++信息学奥赛2046:【例5.15】替换字母

这段代码的功能是对输入的字符串进行处理&#xff0c;将字符串中的字符 a 替换为字符 b 后输出结果。 #include<bits/stdc.h> using namespace std; int main() {string s; // 定义字符串变量s&#xff0c;用来存储输入的字符串char a, b; // 定义字符变量a和b&#xff…...

每天一道leetcode:1306. 跳跃游戏 III(图论中等广度优先遍历)

今日份题目&#xff1a; 这里有一个非负整数数组 arr&#xff0c;你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时&#xff0c;你可以跳到 i arr[i] 或者 i - arr[i]。 请你判断自己是否能够跳到对应元素值为 0 的 **任一** 下标处。 注意&#xff0c;不管是什…...

76参考链接

参考链接 官方文件综合介绍[let 和 const](https://es6.ruanyifeng.com/#docs/reference#let 和 const)解构赋值字符串正则数值数组函数对象Symbol[Set 和 Map](https://es6.ruanyifeng.com/#docs/reference#Set 和 Map)[Proxy 和 Reflect](https://es6.ruanyifeng.com/#docs/…...

浅析Linux SCSI子系统:调试方法

文章目录 SCSI日志调试功能scsi_logging_level调整SCSI日志等级 SCSI trace events使能SCSI trace events方式一&#xff1a;通过set_event接口方式二&#xff1a;通过enable 跟踪trace信息 相关参考 SCSI日志调试功能 SCSI子系统支持内核选项CONFIG_SCSI_LOGGING配置日志调试…...

【Unity3D】水面特效

1 前言 水波特效 中通过屏幕后处理实现了环形水波效果&#xff0c;本文通过 Shader Graph 实现了模拟水面特效&#xff0c;包含以下特效细节。 深水区和浅水区颜色差异&#xff1b;水面有波纹&#xff0c;并且在移动&#xff1b;水面起伏波动&#xff1b;水面边缘有水泡&#…...

CSS中的flex布局详细讲解

Flex 布局 Flex 布局是一种现代的 CSS 布局模型&#xff0c;用于实现灵活的盒子布局。它提供了强大的布局能力&#xff0c;使得元素可以自动调整大小、对齐和分布&#xff0c;适用于构建响应式和可伸缩的布局。 Flex 布局使用 flex 容器和 flex 项目的概念。容器是一个父元素…...

Python功能制作之简单的音乐播放器

需要导入的库&#xff1a; pip install PyQt5 源码&#xff1a; import os from PyQt5.QtCore import Qt, QUrl from PyQt5.QtGui import QIcon, QPixmap from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent from PyQt5.QtWidgets import QApplication, QMainWind…...

GAN生成对抗模型根据minist数据集生成手写数字图片

文章目录 1.项目介绍2相关网站3具体的代码及结果导入工具包设置超参数定义优化器&#xff0c;以及损失函数训练时的迭代过程训练结果的展示 1.项目介绍 通过用minist数据集进行训练&#xff0c;得到一个GAN模型&#xff0c;可以生成与minist数据集类似的图片。 GAN是一种生成模…...

【K8S源码之Pod漂移】整体概况分析 controller-manager 中的 nodelifecycle controller(Pod的驱逐)

参考 k8s 污点驱逐详解-源码分析 - 掘金 k8s驱逐篇(5)-kube-controller-manager驱逐 - 良凯尔 - 博客园 k8s驱逐篇(6)-kube-controller-manager驱逐-NodeLifecycleController源码分析 - 良凯尔 - 博客园 k8s驱逐篇(7)-kube-controller-manager驱逐-taintManager源码分析 - 良…...

[保研/考研机试] KY212 二叉树遍历 华中科技大学复试上机题 C++实现

题目链接&#xff1a; 二叉树遍历_牛客题霸_牛客网二叉树的前序、中序、后序遍历的定义&#xff1a; 前序遍历&#xff1a;对任一子树&#xff0c;先访问根&#xff0c;然后遍历其左子树&#xff0c;最。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/43719512169…...

CSS笔记

介绍 CSS导入方式 三种方法都将文字设置成了红色 CSS选择器 元素选择器 id选择器 图中div将颜色控制为红色&#xff0c;#name将颜色控制为蓝色&#xff0c;谁控制的范围最小&#xff0c;谁就生效&#xff0c;所以第二个div是蓝色的。id属性值要唯一&#xff0c;否则报错。 clas…...

链栈Link-Stack

0、节点结构体定义 typedef struct SNode{int data;struct SNode *next; } SNode, *LinkStack; 1、初始化 bool InitStack(LinkStack &S) //S为栈顶指针&#xff08;存数据的头节点&#xff09; {S NULL;return true; } 2、入栈 bool Push(LinkStack &S, int e) {…...

Ubuntu 20系统WIFI设置静态IP地址,以及断连问题

​最近工作需要购置了一台GPU机器&#xff0c;然后搭建了深度学习的运行环境&#xff0c;在工作中将这台机器当做深度学习的服务器来使用&#xff0c;前期已经配置好多用户以及基础环境。但最近通过xshell连接总是不间断的出现断连现象。 补充一点&#xff0c;Ubuntu系统中与网…...

(一)idea连接GitHub的全部流程(注册GitHub、idea集成GitHub、增加合作伙伴、跨团队合作、分支操作)

&#xff08;二&#xff09;Git在公司中团队内合作和跨团队合作和分支操作的全部流程&#xff08;一篇就够&#xff09;https://blog.csdn.net/m0_65992672/article/details/132336481 4.1、简介 Git是一个免费的、开源的*分布式**版本控制**系统*&#xff0c;可以快速高效地…...

-bash: java: command not found笔记

文章目录 场景解决方案找java的方法find命令进行查找根据java进程找寻具体位置 场景 linux系统执行java命令时报错&#xff1a; -bash: java: command not found。 解决方案 可能是没有安装java(这种情况比较少)或者安装了java但是没有设置环境变量(一般是这种情况)。 找ja…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...