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,实现数据库方式执行定时任务。把定时任务信息存进数据库,项目启动后自动执行定时任务。 1.引入依赖包: <dependency> <groupId>org.springframework.boot</groupId> <ar…...
java中多个list怎么用List表示?
如果你有多个List对象,想要将它们合并成一个List对象,可以使用addAll()方法来实现。addAll()方法将会把一个List中的元素逐个添加到另一个List中。 以下是一个示例,展示了如何将多个List对象合并为一个List对象: 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转换成长图
语言:python 3 用法:点击运行后,弹出窗口,选择文件夹,程序运行会将文件夹内的所有PPT文件全部转换成PPT长图,图片名称与PPT文件名称相同,保存位置相同。 如运行中报错,需要自行根据…...
C++信息学奥赛2046:【例5.15】替换字母
这段代码的功能是对输入的字符串进行处理,将字符串中的字符 a 替换为字符 b 后输出结果。 #include<bits/stdc.h> using namespace std; int main() {string s; // 定义字符串变量s,用来存储输入的字符串char a, b; // 定义字符变量a和bÿ…...
每天一道leetcode:1306. 跳跃游戏 III(图论中等广度优先遍历)
今日份题目: 这里有一个非负整数数组 arr,你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i arr[i] 或者 i - arr[i]。 请你判断自己是否能够跳到对应元素值为 0 的 **任一** 下标处。 注意,不管是什…...
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方式一:通过set_event接口方式二:通过enable 跟踪trace信息 相关参考 SCSI日志调试功能 SCSI子系统支持内核选项CONFIG_SCSI_LOGGING配置日志调试…...
【Unity3D】水面特效
1 前言 水波特效 中通过屏幕后处理实现了环形水波效果,本文通过 Shader Graph 实现了模拟水面特效,包含以下特效细节。 深水区和浅水区颜色差异;水面有波纹,并且在移动;水面起伏波动;水面边缘有水泡&#…...
CSS中的flex布局详细讲解
Flex 布局 Flex 布局是一种现代的 CSS 布局模型,用于实现灵活的盒子布局。它提供了强大的布局能力,使得元素可以自动调整大小、对齐和分布,适用于构建响应式和可伸缩的布局。 Flex 布局使用 flex 容器和 flex 项目的概念。容器是一个父元素…...
Python功能制作之简单的音乐播放器
需要导入的库: pip install PyQt5 源码: 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具体的代码及结果导入工具包设置超参数定义优化器,以及损失函数训练时的迭代过程训练结果的展示 1.项目介绍 通过用minist数据集进行训练,得到一个GAN模型,可以生成与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++实现
题目链接: 二叉树遍历_牛客题霸_牛客网二叉树的前序、中序、后序遍历的定义: 前序遍历:对任一子树,先访问根,然后遍历其左子树,最。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/43719512169…...
CSS笔记
介绍 CSS导入方式 三种方法都将文字设置成了红色 CSS选择器 元素选择器 id选择器 图中div将颜色控制为红色,#name将颜色控制为蓝色,谁控制的范围最小,谁就生效,所以第二个div是蓝色的。id属性值要唯一,否则报错。 clas…...
链栈Link-Stack
0、节点结构体定义 typedef struct SNode{int data;struct SNode *next; } SNode, *LinkStack; 1、初始化 bool InitStack(LinkStack &S) //S为栈顶指针(存数据的头节点) {S NULL;return true; } 2、入栈 bool Push(LinkStack &S, int e) {…...
Ubuntu 20系统WIFI设置静态IP地址,以及断连问题
最近工作需要购置了一台GPU机器,然后搭建了深度学习的运行环境,在工作中将这台机器当做深度学习的服务器来使用,前期已经配置好多用户以及基础环境。但最近通过xshell连接总是不间断的出现断连现象。 补充一点,Ubuntu系统中与网…...
(一)idea连接GitHub的全部流程(注册GitHub、idea集成GitHub、增加合作伙伴、跨团队合作、分支操作)
(二)Git在公司中团队内合作和跨团队合作和分支操作的全部流程(一篇就够)https://blog.csdn.net/m0_65992672/article/details/132336481 4.1、简介 Git是一个免费的、开源的*分布式**版本控制**系统*,可以快速高效地…...
-bash: java: command not found笔记
文章目录 场景解决方案找java的方法find命令进行查找根据java进程找寻具体位置 场景 linux系统执行java命令时报错: -bash: java: command not found。 解决方案 可能是没有安装java(这种情况比较少)或者安装了java但是没有设置环境变量(一般是这种情况)。 找ja…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
