对于定时,简单点只要一个注解就可以搞定了
import org.springframework.scheduling.annotation.Scheduled;
@Scheduled(cron = "0 0 2 1 * ?")
这个注解是要引用在代码里面的,也就是说如果想要改变执行的时间就要去改代码,如果在业务改动很频繁的情况下这种方法就很不可取了,Quartz正好可以避免这个情况,可以通过前台功能来控制增删改查,执行,暂停等功能,下面就是整合的全过程
先声明一下,我的环境为springboot+mybatisplus+maven
第一步,先引入需要依赖的jar包,pom.xml中配置
<!-- Quartz定时任务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
第二步,application.yml中配置(超时忍受时间设置为100毫秒)
# 定时任务
quartz:
# 任务信息存储至数据库
job-store-type: jdbc
properties:
org:
quartz:
jobStore:
misfireThreshold: 100
第三步:创建数据库表(表名是Quartz封装好的,不能改动,创建执行有顺序,批量执行不成功可以单个执行)
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
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) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
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) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
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(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
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),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_BLOB_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_CALENDARS
(
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
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(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
(
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
(
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);
//这个表的表名可以改变,字段尽量不要去更改
CREATE TABLE `t_quartz_job` (
`id` varchar(255) NOT NULL,
`create_by` varchar(255) DEFAULT '' COMMENT '创建人',
`create_time` datetime DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',
`del_flag` int(11) DEFAULT '0' COMMENT '软删除 0正常 1删除',
`update_by` varchar(255) DEFAULT '' COMMENT '操作人',
`update_time` datetime DEFAULT '0000-00-00 00:00:00' COMMENT '操作时间',
`cron_expression` varchar(255) DEFAULT '' COMMENT 'cron表达式',
`description` varchar(255) DEFAULT '' COMMENT '备注',
`job_class_name` varchar(255) DEFAULT '' COMMENT '任务类名',
`parameter` varchar(255) DEFAULT '' COMMENT '参数',
`status` int(11) DEFAULT '0' COMMENT '状态 0正常 -1停止',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='定时任务'
第四步:功能逻辑(我这里只给出了对于Quartz调度器的增删改查,项目的实际逻辑根据项目要求来)
@RequestMapping(value = "/add",method = RequestMethod.POST)
@ApiOperation(value = "添加定时任务")
public Result<Object> addJob(@ModelAttribute QuartzJob job){
//定时类名都是唯一的,逻辑中最好加上验证(job.getJobClassName()为执行路径,需要执行的文件的项目路径)
List<QuartzJob> list = quartzJobService.findByJobClassName(job.getJobClassName());
if(list!=null&&list.size()>0){
return new ResultUtil<Object>().setErrorMsg("该定时任务类名已存在");
}
//在Quartz调度器中添加定时
add(job.getJobClassName(),job.getCronExpression(),job.getParameter());
//自己的业务逻辑
quartzJobService.save(job);
return new ResultUtil<Object>().setSuccessMsg("创建定时任务成功");
}
@RequestMapping(value = "/edit",method = RequestMethod.POST)
@ApiOperation(value = "更新定时任务")
public Result<Object> editJob(@ModelAttribute QuartzJob job){
//修改就要先把构造器中原有存储的删掉
delete(job.getJobClassName());
//删掉原有的在新增
add(job.getJobClassName(),job.getCronExpression(),job.getParameter());
//自己的业务逻辑
job.setStatus(0);//更新后默认给0
quartzJobService.update(job);
return new ResultUtil<Object>().setSuccessMsg("更新定时任务成功");
}
@RequestMapping(value = "/pause",method = RequestMethod.POST)
@ApiOperation(value = "暂停定时任务")
public Result<Object> pauseJob(@ModelAttribute QuartzJob job){
try {
//暂停构造器定时任务
scheduler.pauseJob(JobKey.jobKey(job.getJobClassName()));
} catch (SchedulerException e) {
throw new MyException("暂停定时任务失败");
}
//自己的业务逻辑
job.setStatus(-1);//状态 0正常 -1停止
quartzJobService.update(job);
return new ResultUtil<Object>().setSuccessMsg("暂停定时任务成功")
}
@RequestMapping(value = "/resume",method = RequestMethod.POST)
@ApiOperation(value = "恢复定时任务")
public Result<Object> resumeJob(@ModelAttribute QuartzJob job){
try {
//恢复构造器定时任务
scheduler.resumeJob(JobKey.jobKey(job.getJobClassName()));
} catch (SchedulerException e) {
throw new MyException("恢复定时任务失败");
}
//自己的业务逻辑
job.setStatus(0);
quartzJobService.update(job);
return new ResultUtil<Object>().setSuccessMsg("恢复定时任务成功");
}
@RequestMapping(value = "/delByIds",method = RequestMethod.POST)
@ApiOperation(value = "删除定时任务")
public Result<Object> deleteJob(String ids){
QuartzJob job = quartzJobService.get(ids);
//删除构造器定时任务
delete(job.getJobClassName());
quartzJobService.delete(job.getId());
return new ResultUtil<Object>().setSuccessMsg("删除定时任务成功");
}
/**
* 添加构造器定时任务
* @param jobClassName
* @param cronExpression
* @param parameter
*/
public void add(String jobClassName, String cronExpression, String parameter){
try {
// 启动调度器
scheduler.start();
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass())
.withIdentity(jobClassName)
.usingJobData("parameter",parameter)
.build();
//表达式调度构建器(即任务执行的时间) 使用withMisfireHandlingInstructionDoNothing() 忽略掉调度暂停过程中没有执行的调度
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName)
.withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
log.error(e.toString());
throw new MyException("创建定时任务失败");
} catch (Exception e){
throw new MyException("后台找不到该类名任务");
}
}
/**
* 删除构造器定时任务
* @param jobClassName
*/
public void delete(String jobClassName){
try {
scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName));
scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName));
scheduler.deleteJob(JobKey.jobKey(jobClassName));
} catch (Exception e) {
throw new MyException("删除定时任务失败");
}
}
public static Job getClass(String classname) throws Exception {
Class<?> class1 = Class.forName(classname);
return (Job)class1.newInstance();
}
第五步:定时执行类
package com.shangze.szxs.quartz;
import com.shangze.szxs.sever.service.MemberSignInService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
// 一定要引用job,在内置execute()方法内调用自己的定时逻辑,在添加构造器定时任务是的jobClassName 字段的值就是com.shangze.szxs.quartz.TimedEditMemberSignInContinuityDay,路径一定不要丢到,不然就找不到了
@Slf4j
public class TimedEditMemberSignInContinuityDay implements Job {
@Autowired
private MemberSignInService memberSignInService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info("*************更改会员连签天数定时开始时间************"+new Date());
System.out.println("*************更改会员连签天数定时开始时间************"+new Date());
memberSignInService.editContinuityDay();
log.info("*************更改会员连签天数定时结束时间************"+new Date());
System.out.println("*************更改会员连签天数结束开始时间************"+new Date());
}
}