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.运行结果: