上篇动态定时任务文章
SpringBoot动态定时任务的动态配置处理(动态实时读取数据库配置,支持不重启服务下动态修改和新增任务).
这种方式实现起来是简单,但是会有好多弊端,自己可以网上搜搜看看,也许是自己还没搞明白,所以觉得不好用,所以推荐大家使用今天要介绍的Quartz框架,当然根据自己所需进行选择
推荐一篇很不错的文章,大家可以看看,本文也就不介绍了,待会儿直接上案例,想了解详细一点的,可以看看下面文章,对刚接触的童鞋还是非常友好的讲解。





dog_play_plan 这个表是根据业务逻辑自己创建,后面介绍
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

spring:
quartz:
# 参见 org.springframework.boot.autoconfigure.quartz.QuartzProperties
job-store-type: jdbc
wait-for-jobs-to-complete-on-shutdown: true
scheduler-name: SpringBootDemoScheduler
properties:
org.quartz.threadPool.threadCount: 5
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 5000
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 在调度流程的第一步,也就是拉取待即将触发的triggers时,是上锁的状态,即不会同时存在多个线程拉取到相同的trigger的情况,也就避免的重复调度的危险。参考:https://segmentfault.com/a/1190000015492260
org.quartz.jobStore.acquireTriggersWithinLock: true
# org.quartz.jobStore.tablePrefix: sys_



















SendMessageJob有一个,但是有的2分钟发一次有的5分钟发一次,所以你可以弄成同一个组sendMessage但是不同的任务名2分钟一次 和 5分钟一次,但是你需要处理一下哪些业务数据是2分钟一次,哪些要5分钟一次,当然我这计划表可能不是更合理的,所以需要根据自己需要优化









CREATE TABLE `qrtz_cron_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`CRON_EXPRESSION` varchar(200) NOT NULL,
`TIME_ZONE_ID` varchar(80) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `qrtz_fired_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`ENTRY_ID` varchar(95) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`INSTANCE_NAME` varchar(200) NOT NULL,
`FIRED_TIME` bigint(20) NOT NULL,
`SCHED_TIME` bigint(20) NOT NULL,
`PRIORITY` int(11) NOT NULL,
`STATE` varchar(16) NOT NULL,
`JOB_NAME` varchar(200) DEFAULT NULL,
`JOB_GROUP` varchar(200) DEFAULT NULL,
`IS_NONCONCURRENT` bit(1) DEFAULT NULL,
`REQUESTS_RECOVERY` bit(1) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `qrtz_job_details` (
`SCHED_NAME` varchar(120) NOT NULL,
`JOB_NAME` varchar(200) NOT NULL,
`JOB_GROUP` varchar(200) NOT NULL,
`DESCRIPTION` varchar(250) DEFAULT NULL,
`JOB_CLASS_NAME` varchar(250) NOT NULL,
`IS_DURABLE` bit(1) NOT NULL,
`IS_NONCONCURRENT` bit(1) NOT NULL,
`IS_UPDATE_DATA` bit(1) NOT NULL,
`REQUESTS_RECOVERY` bit(1) NOT NULL,
`JOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `qrtz_locks` (
`SCHED_NAME` varchar(120) NOT NULL,
`LOCK_NAME` varchar(40) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `qrtz_paused_trigger_grps` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='不加启动报错';
CREATE TABLE `qrtz_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`JOB_NAME` varchar(200) NOT NULL,
`JOB_GROUP` varchar(200) NOT NULL,
`DESCRIPTION` varchar(250) DEFAULT NULL,
`NEXT_FIRE_TIME` bigint(20) DEFAULT NULL,
`PREV_FIRE_TIME` bigint(20) DEFAULT NULL,
`PRIORITY` int(11) DEFAULT NULL,
`TRIGGER_STATE` varchar(16) NOT NULL,
`TRIGGER_TYPE` varchar(8) NOT NULL,
`START_TIME` bigint(20) NOT NULL,
`END_TIME` bigint(20) DEFAULT NULL,
`CALENDAR_NAME` varchar(200) DEFAULT NULL,
`MISFIRE_INSTR` smallint(6) DEFAULT NULL,
`JOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `qrtz_simple_triggers` (
`SCHED_NAME` varchar(120) NOT NULL,
`TRIGGER_NAME` varchar(200) NOT NULL,
`TRIGGER_GROUP` varchar(200) NOT NULL,
`REPEAT_COUNT` bigint(20) NOT NULL,
`REPEAT_INTERVAL` bigint(20) NOT NULL,
`TIMES_TRIGGERED` bigint(20) NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='修改定时任务时用这个';
package com.liu.susu.task.quartz.vobo.form;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
@Data
@Accessors(chain = true)
public class JobForm {
/**
* 定时任务名
*/
@NotBlank(message = "任务名称")
private String jobName;
/**
* 任务组名
*/
@NotBlank(message = "任务组名不能为空")
private String jobGroupName;
/**
* 定时任务全类名
*/
@NotBlank(message = "定时任务全类名")
private String jobClassName;
/**
* 定时任务cron表达式
*/
@NotBlank(message = "cron表达式不能为空")
private String cronExpression;
}
package com.liu.susu.task.quartz.vobo.vo;
import lombok.Data;
import java.math.BigInteger;
@Data
public class JobAndTriggerVo {
/**
* 定时任务名称
*/
private String jobName;
/**
* 定时任务组
*/
private String jobGroup;
/**
* 定时任务全类名
*/
private String jobClassName;
/**
* 触发器名称
*/
private String triggerName;
/**
* 触发器组
*/
private String triggerGroup;
/**
* 重复间隔
*/
private BigInteger repeatInterval;
/**
* 触发次数
*/
private BigInteger timesTriggered;
/**
* cron 表达式
*/
private String cronExpression;
/**
* 时区
*/
private String timeZoneId;
/**
* 定时任务状态
*/
private String triggerState;
}
package com.liu.susu.mapper.task;
import com.liu.susu.task.quartz.vobo.vo.JobAndTriggerVo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface JobMapper {
/**
* 查询定时作业和触发器列表
*/
List<JobAndTriggerVo> list();
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liu.susu.mapper.task.JobMapper">
<select id="list" resultType="com.liu.susu.task.quartz.vobo.vo.JobAndTriggerVo">
SELECT
job_details.`JOB_NAME`,
job_details.`JOB_GROUP`,
job_details.`JOB_CLASS_NAME`,
cron_triggers.`CRON_EXPRESSION`,
cron_triggers.`TIME_ZONE_ID`,
qrtz_triggers.`TRIGGER_NAME`,
qrtz_triggers.`TRIGGER_GROUP`,
qrtz_triggers.`TRIGGER_STATE`
FROM
`QRTZ_JOB_DETAILS` job_details
LEFT JOIN `QRTZ_CRON_TRIGGERS` cron_triggers ON job_details.`JOB_NAME` = cron_triggers.`TRIGGER_NAME`
AND job_details.`JOB_GROUP` = cron_triggers.`TRIGGER_GROUP`
LEFT JOIN `QRTZ_TRIGGERS` qrtz_triggers ON qrtz_triggers.`TRIGGER_NAME` = job_details.`JOB_NAME`
AND qrtz_triggers.`TRIGGER_GROUP` = job_details.`JOB_GROUP`
select>
mapper>
package com.liu.susu.controller.task;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageInfo;
import com.liu.susu.common.ResultData;
import com.liu.susu.common.ReturnCode;
import com.liu.susu.service.task.JobService;
import com.liu.susu.task.quartz.vobo.vo.JobAndTriggerVo;
import com.liu.susu.task.quartz.vobo.form.JobForm;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequestMapping("/job")
@Slf4j
public class JobController {
private final JobService jobService;
@Autowired
public JobController(JobService jobService) {
this.jobService = jobService;
}
/**
* 保存定时任务
*/
@PostMapping
public ResultData addJob(@Valid JobForm form) {
try {
jobService.addJob(form);
return new ResultData(ReturnCode.INSERT_SUCCESS);
} catch (Exception e) {
return new ResultData(ReturnCode.FAIL_999999);
}
}
/**
* 暂停定时任务
*/
@PutMapping(params = "pause")
public ResultData pauseJob(JobForm form) throws SchedulerException {
if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobClassName())) {
return new ResultData(ReturnCode.FAIL_NO_PARAM, "参数不能为空!");
}
jobService.pauseJob(form);
return new ResultData(ReturnCode.SUCCESS_000000, "暂停成功!");
}
/**
* 恢复定时任务
*/
@PutMapping(params = "resume")
public ResultData resumeJob(JobForm form) throws SchedulerException {
if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobClassName())) {
return new ResultData(ReturnCode.FAIL_NO_PARAM, "参数不能为空!");
}
jobService.resumeJob(form);
return new ResultData(ReturnCode.SUCCESS_000000, "恢复成功!");
}
/**
* 修改定时任务,定时时间
*/
@PutMapping(params = "cron")
public ResultData cronJob(@Valid JobForm form) {
try {
jobService.cronJob(form);
return new ResultData(ReturnCode.UPDATE_SUCCESS, "修改成功!");
} catch (Exception e) {
return new ResultData(ReturnCode.FAIL_999999);
}
}
/**
* 删除定时任务
*/
@DeleteMapping
public ResultData deleteJob(JobForm form) throws SchedulerException {
if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobClassName())) {
return new ResultData(ReturnCode.FAIL_NO_PARAM, "参数不能为空!");
}
jobService.deleteJob(form);
return new ResultData(ReturnCode.DELETE_SUCCESS, "删除成功!");
}
/**
* 查询定时任务列表
* @param currentPage
* @param pageSize
* @return
*/
@RequestMapping
public ResultData jobList(Integer currentPage, Integer pageSize) {
if (ObjectUtil.isNull(currentPage)) {
currentPage = 1;
}
if (ObjectUtil.isNull(pageSize)) {
pageSize = 10;
}
PageInfo<JobAndTriggerVo> all = jobService.list(currentPage, pageSize);
return new ResultData(ReturnCode.SELECT_SUCCESS, all);
}
}
package com.liu.susu.service.task;
import com.github.pagehelper.PageInfo;
import com.liu.susu.task.quartz.vobo.vo.JobAndTriggerVo;
import com.liu.susu.task.quartz.vobo.form.JobForm;
import org.quartz.SchedulerException;
public interface JobService {
/**
* 添加并启动定时任务
*/
void addJob(JobForm form) throws Exception;
/**
* 删除定时任务
*/
void deleteJob(JobForm form) throws SchedulerException;
/**
* 暂停定时任务
*/
void pauseJob(JobForm form) throws SchedulerException;
/**
* 恢复定时任务
*/
void resumeJob(JobForm form) throws SchedulerException;
/**
* 重新配置定时任务
*/
void cronJob(JobForm form) throws Exception;
/**
* 查询定时任务列表
*/
PageInfo<JobAndTriggerVo> list(Integer currentPage, Integer pageSize);
}
package com.liu.susu.service.task.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.liu.susu.mapper.task.JobMapper;
import com.liu.susu.service.task.JobService;
import com.liu.susu.task.quartz.vobo.vo.JobAndTriggerVo;
import com.liu.susu.task.quartz.vobo.form.JobForm;
import com.liu.susu.utils.JobUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Slf4j
public class JobServiceImpl implements JobService {
private final Scheduler scheduler;
private final JobMapper jobMapper;
@Autowired
public JobServiceImpl(Scheduler scheduler, JobMapper jobMapper) {
this.scheduler = scheduler;
this.jobMapper = jobMapper;
}
/**
* 添加并启动定时任务
*/
@Override
public void addJob(JobForm form) throws Exception {
// 启动调度器
scheduler.start();
// 构建Job信息
// JobDetail jobDetail = JobBuilder.newJob(JobUtil.getClass(form.getJobClassName()).getClass()).withIdentity(form.getJobClassName(), form.getJobGroupName()).build();
JobDetail jobDetail = JobBuilder.newJob(JobUtil.getClass(form.getJobClassName()).getClass()).withIdentity(form.getJobName(), form.getJobGroupName()).build();
// Cron表达式调度构建器(即任务执行的时间)
CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(form.getCronExpression());
//根据Cron表达式构建一个Trigger
// CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(form.getJobClassName(), form.getJobGroupName()).withSchedule(cron).build();
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(form.getJobName(), form.getJobGroupName()).withSchedule(cron).build();
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
log.error("【定时任务】创建失败!", e);
throw new Exception("【定时任务】创建失败!");
}
}
/**
* 删除定时任务
*/
@Override
public void deleteJob(JobForm form) throws SchedulerException {
scheduler.pauseTrigger(TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName()));
scheduler.unscheduleJob(TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName()));
scheduler.deleteJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));
}
/**
* 暂停定时任务
*/
@Override
public void pauseJob(JobForm form) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));
}
/**
* 恢复定时任务
*/
@Override
public void resumeJob(JobForm form) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));
}
/**
* 重新配置定时任务
*/
@Override
public void cronJob(JobForm form) throws Exception {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName());
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(form.getCronExpression());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 根据Cron表达式构建一个Trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
log.error("【定时任务】更新失败!", e);
throw new Exception("【定时任务】创建失败!");
}
}
/**
* 查询定时任务列表
*/
@Override
public PageInfo<JobAndTriggerVo> list(Integer currentPage, Integer pageSize) {
PageHelper.startPage(currentPage, pageSize);
List<JobAndTriggerVo> list = jobMapper.list();
return new PageInfo<>(list);
}
}
package com.liu.susu.utils;
import com.liu.susu.task.quartz.job.base.BaseJob;
/**
* 定时任务反射工具类
*/
public class JobUtil {
/**
* 根据全类名获取Job实例
*/
public static BaseJob getClass(String classname) throws Exception {
Class<?> clazz = Class.forName(classname);
return (BaseJob) clazz.newInstance();
}
}
package com.liu.susu.task.quartz.job.base;
import org.quartz.*;
public interface BaseJob extends Job {
@Override
void execute(JobExecutionContext context) throws JobExecutionException;
}
package com.liu.susu.task.quartz.job;
import com.liu.susu.task.quartz.job.base.BaseJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import java.time.LocalDateTime;
@Slf4j
public class HelloJob implements BaseJob {
@Override
public void execute(JobExecutionContext context) {
JobKey key = context.getJobDetail().getKey();
if ("bb".equals(key.getName())){
log.info("处理bb定时任务的业务…… 执行时间-->: {}", LocalDateTime.now());
}
if ("aa".equals(key.getName())){
log.info("处理aa定时任务的业务…… 执行时间-->: {}",LocalDateTime.now());
}
log.info("处理aa、bb外的定时任务,执行时间-->: {}",LocalDateTime.now());
}
}
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>spring-boot-demo-task-quartztitle>
<link href="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.4.9/theme-chalk/index.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/vue/2.5.17/vue.min.js">script>
<script src="https://cdn.bootcss.com/vue-resource/1.5.1/vue-resource.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.4.9/index.js">script>
<style>
#top {
/*background: #20A0FF;*/
padding: 5px;
/*overflow: hidden*/
}
style>
head>
<body>
<div id="job">
<div id="top">
<el-button size="small" type="primary" plain @click="search" :loading="loading" icon="el-icon-search">查询
el-button>
<el-button size="small" type="primary" plain @click="handleadd" icon="el-icon-plus">添加el-button>
div>
<br/>
<div>
<el-table ref="jobTable" :data="tableData" style="width:100%" border center>
<el-table-column prop="jobName" label="任务名称" show-overflow-tooltip align="center">el-table-column>
<el-table-column prop="jobGroup" label="任务所在组" sortable align="center">el-table-column>
<el-table-column prop="jobClassName" label="任务类名" align="center">el-table-column>
<el-table-column prop="triggerName" label="触发器名称" align="center">el-table-column>
<el-table-column prop="triggerGroup" label="触发器所在组" sortable align="center">el-table-column>
<el-table-column prop="cronExpression" label="表达式" align="center">el-table-column>
<el-table-column prop="timeZoneId" label="时区" align="center">el-table-column>
<el-table-column prop="triggerState" label="状态" align="center" :formatter="formatState">el-table-column>
<el-table-column label="操作" width="300" align="center">
<template scope="scope">
<el-button size="small" type="warning" @click="handlePause(scope.$index, scope.row)">
暂停
el-button>
<el-button size="small" type="info" @click="handleResume(scope.$index, scope.row)">
恢复
el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)">
删除
el-button>
<el-button size="small" type="success" @click="handleUpdate(scope.$index, scope.row)">
修改
el-button>
template>
el-table-column>
el-table>
<div align="center">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="totalCount">
el-pagination>
div>
div>
<el-dialog title="添加任务" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="任务名称" label-width="100px" style="width:90%">
<el-input v-model="form.jobName" auto-complete="off">el-input>
el-form-item>
<el-form-item label="任务类名称" label-width="100px" style="width:90%">
<el-input v-model="form.jobClassName" auto-complete="off">el-input>
el-form-item>
<el-form-item label="任务分组" label-width="100px" style="width:90%">
<el-input v-model="form.jobGroup" auto-complete="off">el-input>
el-form-item>
<el-form-item label="表达式" label-width="100px" style="width:90%">
<el-input v-model="form.cronExpression" auto-complete="off">el-input>
el-form-item>
el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消el-button>
<el-button type="primary" @click="add">确 定el-button>
div>
el-dialog>
<el-dialog title="修改任务" :visible.sync="updateFormVisible">
<el-form :model="updateform">
<el-form-item label="表达式" label-width="100px" style="width:90%">
<el-input v-model="updateform.cronExpression" auto-complete="off">el-input>
el-form-item>
el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="updateFormVisible = false">取 消el-button>
<el-button type="primary" @click="update">确 定el-button>
div>
el-dialog>
div>
<footer align="center">
<p>© Quartz 定时任务管理p>
footer>
<script>
var vue = new Vue({
el: "#job",
data: {
//表格当前页数据
tableData: [],
//请求的URL
url: 'job',
//默认每页数据量
pagesize: 10,
//当前页码
currentPage: 1,
//查询的页码
start: 1,
//默认数据总数
totalCount: 1000,
//添加对话框默认可见性
dialogFormVisible: false,
//修改对话框默认可见性
updateFormVisible: false,
//提交的表单
form: {
jobName: '',
jobGroup: '',
cronExpression: ''
},
updateform: {
jobName: '',
jobGroup: '',
cronExpression: ''
},
loading: false
},
methods: {
// 格式化状态
formatState: function (row, column, cellValue, index) {
if (row.triggerState === 'WAITING' || row.triggerState === 'ACQUIRED') {
return "运行中";
} else if (row.triggerState === 'PAUSED') {
return "暂停";
} else {
return "未知状态";
}
},
// 从服务器读取数据
loadData: function (currentPage, pageSize) {
this.loading = true;
this.$http.get('job?' + 'currentPage=' + currentPage + '&pageSize=' + pageSize).then(function (res) {
console.log(res);
this.tableData = res.body.data.list;
this.totalCount = res.body.data.total;
this.loading = false;
}, function () {
console.log('failed');
});
},
// 删除任务
handleDelete: function (index, row) {
this.$http.delete('job', {
params: {
"jobClassName": row.jobName,
"jobGroupName": row.jobGroup
}
}, {emulateJSON: true}).then(function (res) {
this.loadData(this.currentPage, this.pagesize);
}, function () {
console.log('failed');
});
},
// 暂停任务
handlePause: function (index, row) {
this.$http.put('job?pause', {
"jobClassName": row.jobName,
"jobGroupName": row.jobGroup
}, {emulateJSON: true}).then(function (res) {
this.loadData(this.currentPage, this.pagesize);
}, function () {
console.log('failed');
});
},
// 恢复任务
handleResume: function (index, row) {
this.$http.put('job?resume', {
"jobClassName": row.jobName,
"jobGroupName": row.jobGroup
}, {emulateJSON: true}).then(function (res) {
this.loadData(this.currentPage, this.pagesize);
}, function () {
console.log('failed');
});
},
// 搜索
search: function () {
this.loadData(this.currentPage, this.pagesize);
},
// 弹出对话框
handleadd: function () {
this.dialogFormVisible = true;
},
// 添加
add: function () {
this.$http.post('job', {
"jobName": this.form.jobName,
"jobClassName": this.form.jobClassName,
"jobGroupName": this.form.jobGroup,
"cronExpression": this.form.cronExpression
}, {emulateJSON: true}).then(function (res) {
this.loadData(this.currentPage, this.pagesize);
this.dialogFormVisible = false;
}, function () {
console.log('failed');
});
},
// 更新
handleUpdate: function (index, row) {
console.log(row);
this.updateFormVisible = true;
this.updateform.jobName = row.jobName;
this.updateform.jobGroup = row.jobGroup;
},
// 更新任务
update: function () {
this.$http.put('job?cron',
{
"jobClassName": this.updateform.jobName,
"jobGroupName": this.updateform.jobGroup,
"cronExpression": this.updateform.cronExpression
}, {emulateJSON: true}
).then(function (res) {
this.loadData(this.currentPage, this.pagesize);
this.updateFormVisible = false;
}, function () {
console.log('failed');
});
},
// 每页显示数据量变更
handleSizeChange: function (val) {
this.pagesize = val;
this.loadData(this.currentPage, this.pagesize);
},
// 页码变更
handleCurrentChange: function (val) {
this.currentPage = val;
this.loadData(this.currentPage, this.pagesize);
}
}
});
//载入数据
vue.loadData(vue.currentPage, vue.pagesize);
script>
body>
html>
package com.liu.susu.service.task;
import com.liu.susu.common.ResultData;
import com.liu.susu.pojo.entity.sys.SysJobManagerEntity;
import com.liu.susu.task.quartz.vobo.vo.JobAndTriggerVo;
import java.util.List;
public interface JobService {
/**
* 查询定时任务列表
*/
List<JobAndTriggerVo> selectAllJobList();
/**
* 添加并启动定时任务
*/
void addJob(SysJobManagerEntity form) throws Exception;
/**
* 暂停定时任务
*/
ResultData pauseJob(String jobNameKey, String jobGroupNameCode);
/**
* 恢复定时任务
*/
ResultData resumeJob(String jobNameKey, String jobGroupNameCode) ;
/**
* 重新配置定时任务
*/
ResultData updateJobCron(String jobNameKey, String jobGroupNameCode,String newCron) ;
/**
* 删除定时任务
*/
ResultData deleteJob(String jobNameKey, String jobGroupNameCode);
}
package com.liu.susu.service.task.impl;
import com.liu.susu.common.ResultData;
import com.liu.susu.common.ReturnCode;
import com.liu.susu.mapper.task.JobMapper;
import com.liu.susu.pojo.entity.sys.SysJobManagerEntity;
import com.liu.susu.service.task.JobService;
import com.liu.susu.task.quartz.vobo.vo.JobAndTriggerVo;
import com.liu.susu.utils.JobUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Slf4j
public class JobServiceImpl implements JobService {
@Autowired
private Scheduler scheduler;
@Autowired
private JobMapper jobMapper;
/**
* 查询定时任务列表
*/
@Override
public List<JobAndTriggerVo> selectAllJobList() {
return jobMapper.list();
}
/**
* 添加并启动定时任务
*/
@Override
public void addJob(SysJobManagerEntity form) throws Exception {
// 启动调度器
scheduler.start();
// 构建Job信息
JobDetail jobDetail = JobBuilder.newJob(JobUtil.getClass(form.getJobClassName()).getClass())
.withIdentity(form.getJobNameKey(), form.getJobGroupNameCode()).build();
// Cron表达式调度构建器(即任务执行的时间)
CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(form.getJobCron());
//根据Cron表达式构建一个Trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(form.getJobNameKey(), form.getJobGroupNameCode())
.withSchedule(cron).build();
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
log.error("【定时任务】创建失败!", e);
throw new Exception("【定时任务】创建失败!");
}
}
/**
* 暂停定时任务
*/
@Override
public ResultData pauseJob(String jobNameKey, String jobGroupNameCode) {
try {
scheduler.pauseJob(JobKey.jobKey(jobNameKey, jobGroupNameCode));
return new ResultData(ReturnCode.SUCCESS_000000,"暂停成功!");
} catch (SchedulerException e) {
e.printStackTrace();
return new ResultData(ReturnCode.FAIL_999999);
}
}
/**
* 恢复定时任务
*/
@Override
public ResultData resumeJob(String jobNameKey, String jobGroupNameCode) {
try {
scheduler.resumeJob(JobKey.jobKey(jobNameKey, jobGroupNameCode));
return new ResultData(ReturnCode.SUCCESS_000000,"定时任务恢复成功!");
} catch (SchedulerException e) {
e.printStackTrace();
return new ResultData(ReturnCode.FAIL_999999);
}
}
/**
* 修改定时任务
*/
@Override
public ResultData updateJobCron(String jobNameKey, String jobGroupNameCode,String newCron) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobNameKey, jobGroupNameCode);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(newCron);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 根据Cron表达式构建一个Trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
return new ResultData(ReturnCode.UPDATE_SUCCESS,"定时任务修改成功!");
} catch (SchedulerException e) {
log.error("【定时任务】更新失败!", e);
e.printStackTrace();
return new ResultData(ReturnCode.FAIL_999999);
}
}
/**
* 删除定时任务
*/
@Override
public ResultData deleteJob(String jobNameKey, String jobGroupNameCode) {
try {
scheduler.pauseTrigger(TriggerKey.triggerKey(jobNameKey, jobGroupNameCode));
scheduler.unscheduleJob(TriggerKey.triggerKey(jobNameKey, jobGroupNameCode));
scheduler.deleteJob(JobKey.jobKey(jobNameKey, jobGroupNameCode));
return new ResultData(ReturnCode.DELETE_SUCCESS,"定时任务删除成功!");
} catch (SchedulerException e) {
e.printStackTrace();
return new ResultData(ReturnCode.FAIL_999999);
}
}
}
package com.liu.susu.controller.task;
import com.github.pagehelper.PageHelper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.liu.susu.common.PageParam;
import com.liu.susu.common.ResultData;
import com.liu.susu.common.ReturnCode;
import com.liu.susu.mapper.task.SysJobManagerMapper;
import com.liu.susu.pojo.entity.sys.SysJobManagerEntity;
import com.liu.susu.service.task.JobService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Controller
@RequestMapping("/sys/quartz/task")
@Api(tags = "系统管理-->定时任务管理")
@ApiSupport(author = "乘风破浪",order = 3)
@Slf4j
public class JobController2 {
@Autowired
private JobService jobService;
@Autowired
private SysJobManagerMapper sysJobManagerMapper;
@ApiOperationSupport(author = "乘风破浪",order = 1)
@ApiOperation(value = "查询定时任务列表")
@PostMapping("/selectAllJob")
@ResponseBody
public ResultData selectAllJob(@Valid PageParam pageParam) {
if (pageParam!=null){
PageHelper.startPage(pageParam.getPageNum(),pageParam.getPageSize());
}
return ResultData.getPageBaseResultData(pageParam,jobService.selectAllJobList());
}
@ApiOperationSupport(author = "乘风破浪",order = 2)
@ApiOperation(value = "新增定时任务")
@PostMapping("/addNewJob")
@ResponseBody
public ResultData addNewJob(@RequestBody SysJobManagerEntity form) {
if (form!=null && StringUtils.isNotEmpty(form.getJobGroupNameCode())
&& StringUtils.isNotEmpty(form.getJobNameKey())){
//添加任务之前,先校验是否在可添加的列表中有维护
int count = sysJobManagerMapper.findSysJobManager(form.getJobGroupNameCode(), form.getJobNameKey());
if (count>0){
try {
jobService.addJob(form);
return new ResultData(ReturnCode.INSERT_SUCCESS);
} catch (Exception e) {
return new ResultData(ReturnCode.FAIL_999999);
}
}else {
return new ResultData(ReturnCode.FAIL_999998,"没有维护要新增的定时任务,请先找管理员维护!");
}
}
return new ResultData(ReturnCode.FAIL_NO_PARAM, "表单参数为空,请检查参数");
}
@ApiOperationSupport(author = "乘风破浪",order = 3)
@ApiOperation(value = "暂停任务")
@GetMapping("/pauseJob")
@ResponseBody
public ResultData pauseJob(@RequestParam(value = "jobNameKey",required = true) String jobNameKey,
@RequestParam(value = "jobGroupNameCode",required = true) String jobGroupNameCode){
if (StringUtils.isEmpty(jobNameKey) || StringUtils.isEmpty(jobGroupNameCode)){
return new ResultData(ReturnCode.FAIL_NO_PARAM, "参数不能为空!");
}
return jobService.pauseJob(jobNameKey,jobGroupNameCode);
}
@ApiOperationSupport(author = "乘风破浪",order = 4)
@ApiOperation(value = "恢复定时任务")
@GetMapping("/resumeJob")
@ResponseBody
public ResultData resumeJob(@RequestParam(value = "jobNameKey") String jobNameKey,
@RequestParam(value = "jobGroupNameCode") String jobGroupNameCode) {
if (StringUtils.isEmpty(jobNameKey) || StringUtils.isEmpty(jobGroupNameCode)){
return new ResultData(ReturnCode.FAIL_NO_PARAM, "参数不能为空!");
}
return jobService.resumeJob(jobNameKey,jobGroupNameCode);
}
@ApiOperationSupport(author = "乘风破浪",order = 5)
@ApiOperation(value = "修改定时任务,定时时间")
@GetMapping("/updateJobCron")
@ResponseBody
public ResultData updateJobCron(@Param("jobNameKey") String jobNameKey,
@Param("jobGroupNameCode") String jobGroupNameCode,
@Param("cron") String newCron) {
return jobService.updateJobCron(jobNameKey, jobGroupNameCode, newCron);
}
@ApiOperationSupport(author = "乘风破浪",order = 6)
@ApiOperation(value = "删除定时任务")
@GetMapping("/deleteJob")
@ResponseBody
public ResultData deleteJob(@Param("jobNameKey") String jobNameKey,
@Param("jobGroupNameCode") String jobGroupNameCode) {
jobService.deleteJob(jobNameKey,jobGroupNameCode);
return new ResultData(ReturnCode.DELETE_SUCCESS, "删除成功!");
}
}
我把这个集成到自己项目里了,优化后的代码也在,代码太多,所以就贴上面部分代码了,其他的自己根据需要可自行下载: