implementation 'org.springframework.boot:spring-boot-starter-web'
compile group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.3.2'
compile group: 'com.baomidou', name: 'mybatis-plus-generator', version: '3.3.2'
implementation group: 'org.springframework', name: 'spring-context-support', version: '5.2.12.RELEASE'
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
implementation group: 'org.quartz-scheduler', name: 'quartz', version: '2.3.2'
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs
implementation group: 'org.quartz-scheduler', name: 'quartz-jobs', version: '2.3.0'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.4version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.4version>
dependency>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
<version>${quartz.version}version>
dependency>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartz-jobsartifactId>
<version>${quartz.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
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)
);
commit;
编写quartz.properties配置类
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
#设置默认调度程序的名称,如正在使用群集功能,则必须对群集中“逻辑上”相同的调度程序的每个实例使用相同的名称,重新赋值该值。
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
#如果您希望Quartz Scheduler通过RMI作为服务器导出本身,则为true。
org.quartz.scheduler.rmi.export = false
#如果要连接(使用)远程服务的调度程序,则为true。还必须指定RMI注册表进程的主机和端口 - 通常是“localhost”端口1099
org.quartz.scheduler.rmi.proxy = false
#org.quartz.scheduler.rmi.registryHost
#org.quartz.scheduler.rmi.registryPort
#设置这项为true使我们在调用job的execute()之前能够开始一个UserTransaction。
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
#指定的线程池
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#线程数量
org.quartz.threadPool.threadCount = 10
#优先级
org.quartz.threadPool.threadPriority = 5
#自创建父线程
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#作业最大延迟时间毫秒
org.quartz.jobStore.misfireThreshold = 60000
#数据保存方式为持久化
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
application.yml配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/Test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: root
password: 123456
jpa:
hibernate:
ddl-auto: update #ddl-auto:设为update表示每次都不会重新建表
show-sql: true
application:
name: quartz_demo
server:
port: 8081
# 打印日志
logging:
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
com.springms: DEBUG
mybatis:
mapper-locations: classpath:mapper/*.xml
DynamicJob
package com.example.df.quartz.job;
import com.example.df.util.QuartzreflectUtil;
import com.example.df.util.SpringContextUtil;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.stereotype.Component;
/**
* @Author: xu
* @Description: TODO 定时任务需要实现的接口
* @Date: 2021/11/29 15:39
*/
public interface DynamicJob<T> extends Job
{
/**
* 需要执行任务的方法体
* @param args 可变参数,前端传递
* @return object
*/
T task(Object... args);
@Override
default void execute(JobExecutionContext context) {
QuartzreflectUtil quartzreflectUtil = SpringContextUtil.getBean(QuartzreflectUtil.class);
quartzreflectUtil.reflect(context);
}
}
package com.example.df.quartz.entry;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Params {
@NotNull(message = "任务名必填!")
private String jobName;
@NotNull(message = "分组名必填!")
private String jobGroupName;
@NotNull(message = "类名不能为空")
private String className;
@NotNull(message = "执行cron必填!")
private String cron;
private String method;
private List<Map<String,Object>> paramData;
private Object[] finalMethodParam;
}
package com.example.df.conf;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import javax.sql.DataSource;
/**
* @author xu
* @Description
* @createTime 2021年03月08日 17:31:00
*/
@Configuration
@EnableScheduling
public class QuartzConfiguration {
/**
* 继承org.springframework.scheduling.quartz.SpringBeanJobFactory
* 实现任务实例化方式
*/
public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
/**
* 将job实例交给spring ioc托管
* 我们在job实例实现类内可以直接使用spring注入的调用被spring ioc管理的实例
*
* @param bundle
* @return
* @throws Exception
*/
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
/**
* 将job实例交付给spring ioc
*/
beanFactory.autowireBean(job);
return job;
}
}
/**
* 配置任务工厂实例
*
* @return
*/
@Bean
public JobFactory jobFactory() {
/**
* 采用自定义任务工厂 整合spring实例来完成构建任务*/
return new AutowiringSpringBeanJobFactory();
}
/**
* 配置任务调度器
* 使用项目数据源作为quartz数据源
*
* @param jobFactory 自定义配置任务工厂
* @param dataSource 数据源实例
* @return
* @throws Exception
*/
@Bean(destroyMethod = "destroy", autowire = Autowire.NO)
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, DataSource dataSource) throws Exception {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
//将spring管理job自定义工厂交由调度器维护
schedulerFactoryBean.setJobFactory(jobFactory);
//设置覆盖已存在的任务
schedulerFactoryBean.setOverwriteExistingJobs(true);
//项目启动完成后,等待2秒后开始执行调度器初始化
schedulerFactoryBean.setStartupDelay(2);
//设置调度器自动运行
schedulerFactoryBean.setAutoStartup(true);
//设置数据源,使用与项目统一数据源
schedulerFactoryBean.setDataSource(dataSource);
//设置上下文spring bean name
schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
//设置配置文件位置
schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
return schedulerFactoryBean;
}
}
以上操作环境准备完成
package com.example.df.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.df.quartz.job.DynamicJob;
import com.example.df.quartz.service.QuartzService;
import com.example.df.quartz.entry.Params;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* @author xu
* @Description
* @createTime 2021年03月09日 14:14:00
*/
@Component
public class QuartzreflectUtil {
@SuppressWarnings("all")
@Autowired
QuartzService quartzService;
static Logger logger = LoggerFactory.getLogger(QuartzreflectUtil.class);
/**
* 定时任务执行的方法,通过反射调用该类中的方法
* @param context
*/
@SuppressWarnings("all")
public void reflect(JobExecutionContext context){
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String method = null;
String cla = null;
String jobName = null;
String jobGroupName = null;
Object[] finalMethodParam = new Object[0];
try {
cla = jobDataMap.getString("class");
jobName = jobDataMap.get("jobName").toString();
jobGroupName = jobDataMap.get("jobGroupName").toString();
finalMethodParam = JSONObject.parseObject(JSON.toJSONString(jobDataMap.get("finalMethodParam")),Object[].class);
}catch (Exception e){
if (jobName!=null && jobGroupName!=null){
quartzService.deleteJob(jobName, jobGroupName);
logger.warn("定时任务方法调用异常,已停止任务 jobName:"+jobName+";\tjobGroupName:"+jobGroupName);
}else {
logger.error("定时任务执行错误,无法停止任务,请手动停止任务");
}
e.printStackTrace();
}
DynamicJob bean = SpringContextUtil.getBean(cla, DynamicJob.class);
bean.task(finalMethodParam);
}
/**
* 调用定时任务时,需要封装成obj[]才可以使用,工具类整合数据为obj[]
* @param list 传递过来的list对象数据
* @param obj 一个限定长度的obj[]对象
* @param parameterCount 参数长度
* @return
*/
@SuppressWarnings("all")
public static void setObjelement(List list,Object[] obj){
for (int i = 0; i < list.size(); i++) { //通过遍历,往obj2对象数组赋值
String listClass = list.get(i).getClass().toString(); //得到list当前值的类型
if (listClass.equals(HashMap.class.toString())) { //判断类型是否相等。类型相等时,强转类型后复制obj
obj[i] = (HashMap) list.get(i);
logger.info("map赋值成功,索引位置:" + i);
} else if (listClass.equals(String.class.toString())) {
obj[i] = (String) list.get(i);
logger.info("String赋值成功,索引位置:" + i);
} else if (listClass.equals(Integer.class.toString())) {
obj[i] = (Integer) list.get(i);
logger.info("Integer赋值成功,索引位置:" + i);
} else if (listClass.equals(Long.class.toString())) {
obj[i] = (Long) list.get(i);
logger.info("Long赋值成功,索引位置:" + i);
}else if (listClass.equals(HttpServletRequest.class.toString())) {
obj[i] = (HttpServletRequest) list.get(i);
logger.info("HttpServletRequest赋值成功,索引位置:" + i);
}else if (listClass.equals(HttpServletResponse.class.toString())) {
obj[i] = (HttpServletResponse) list.get(i);
logger.info("HttpServletResponse赋值成功,索引位置:" + i);
}else if (listClass.equals(Map.class.toString())) {
obj[i] = (Map) list.get(i);
logger.info("Map赋值成功,索引位置:" + i);
} else if (listClass.equals(LinkedHashMap.class.toString())) {
obj[i] = (LinkedHashMap) list.get(i);
logger.info("Map赋值成功,索引位置:" + i);
}
}
}
/**
* 传入参数解析
* @param paramSize 参数长度
* @param param map参数
* @param response 响应对象
* @param request 请求对象
* @return 返回的需要调用定时器
*/
@SuppressWarnings("all")
public static List inputParamList(Integer paramSize,Map param,HttpServletResponse response,HttpServletRequest request){
List<Object> list = new ArrayList();
Map o;
if (paramSize==0){
return null;
}
for (int i = 1; i <= paramSize; i++) {
o=(Map) param.get(i+"");
if (o.containsKey("String")){
String string = o.get("String").toString();
list.add(string);
}else if (o.containsKey("Map")){
Map map = (Map) o.get("Map");
list.add(map);
} else if (o.containsKey("HttpServletResponse")){
list.add(response);
}else if (o.containsKey("HttpServletRequest")){
list.add(request);
}else if (o.containsKey("Long")){
Long aLong = Long.valueOf(o.get("Long").toString());
list.add(aLong);
}else if (o.containsKey("Integer")){
Integer integer = Integer.valueOf(o.get("Integer").toString());
list.add(integer);
}
}
return list;
}
/**
* 传入参数解析
* @param paramSize 参数长度
* @param param map参数
* @param response 响应对象
* @param request 请求对象
* @return 返回的需要调用定时器
*/
@SuppressWarnings("all")
public static List inputParamListOptimize(Params param, HttpServletResponse response, HttpServletRequest request){
List data = null;
List<Object> list = new ArrayList();
if(param.getParamData()==null || param.getParamData().size()<=0){
return null;
}else {
data= param.getParamData();
}
for (int i = 0; i < data.size(); i++) {
Map o = (Map) data.get(i);
if (o.containsKey("String")){
String string = o.get("String").toString();
list.add(string);
}else if (o.containsKey("Map")){
Map map = (Map) o.get("Map");
list.add(map);
} else if (o.containsKey("HttpServletResponse")){
list.add(response);
}else if (o.containsKey("HttpServletRequest")){
list.add(request);
}else if (o.containsKey("Long")){
Long aLong = Long.valueOf(o.get("Long").toString());
list.add(aLong);
}else if (o.containsKey("Integer")){
Integer integer = Integer.valueOf(o.get("Integer").toString());
list.add(integer);
}
}
return list;
}
}
package com.example.df.quartz.service;
import com.alibaba.fastjson.JSONObject;
import com.example.df.quartz.entry.Params;
import com.example.df.util.QuartzreflectUtil;
import com.example.df.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author xu
* @Description
* @createTime 2021年03月08日 17:32:00
*/
@Service
@Slf4j
public class QuartzService {
@Qualifier("schedulerFactoryBean")
@Autowired
private Scheduler scheduler;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
@PostConstruct
public void startScheduler() {
try {
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@SuppressWarnings("all")
@Transactional
public Map startaddJob(HttpServletRequest request, HttpServletResponse response, Params param){
Map<String,Object> res = new HashMap();
String className = param.getClassName(); //获取需要执行方法的类名
String jobName = param.getJobName();
String jobGroupName = param.getJobGroupName();
String cron = param.getCron();
if(param.getParamData()!=null && param.getParamData().size()>0){
param = integratedData(param, response, request);
}
Map map = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class);
map.put("finalMethodParam",param.getFinalMethodParam());
map.put("class", className);
Class<?> bean = null;
try {
bean = Class.forName(SpringContextUtil.getBean(className).getClass().getCanonicalName());
} catch (ClassNotFoundException e) {
log.error("找不到当前类");
e.printStackTrace();
}
String date = addJob(bean, jobName, jobGroupName, cron, map);
log.info("任务添加成功");
res.put("msg", date);
return res;
}
/**
* 增加一个job
*
* @param jobClass
* 任务实现类
* @param jobName
* 任务名称
* @param jobGroupName
* 任务组名
* @param jobTime
* 时间表达式 (这是每隔多少秒为一次任务)
* @param jobTimes
* 运行的次数 (<0:表示不限次数)
*/
@SuppressWarnings("all")
public String addJob(Class <? extends Job> jobClass, String jobName, String jobGroupName, int jobTime,
int jobTimes) {
String date = null;
try {
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)// 任务名称和组构成任务key
.build();
// 使用simpleTrigger规则
Trigger trigger = null;
if (jobTimes < 0) {
trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime))
.startNow().build();
} else {
trigger = TriggerBuilder
.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(SimpleScheduleBuilder
.repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes))
.startNow().build();
}
Date date1 = scheduler.scheduleJob(jobDetail, trigger);
date = sdf.format(date1);
} catch (SchedulerException e) {
e.printStackTrace();
}
return date;
}
@SuppressWarnings("all")
public String addJob(Class jobClass, String jobName, String jobGroupName, String jobTime,Map param) {
String date = null;
try {
// 创建jobDetail实例,绑定Job实现类
// 指明job的名称,所在组的名称,以及绑定job类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)
.usingJobData(new JobDataMap(param))// 任务名称和组构成任务key
.build();
// 定义调度触发规则
// 使用cornTrigger规则
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)// 触发器key
.startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
.usingJobData(new JobDataMap(param))
.withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).startNow().build();
// 把作业和触发器注册到任务调度中
Date date1 = scheduler.scheduleJob(jobDetail, trigger);
date = sdf.format(date1);
} catch (Exception e) {
date = e.getMessage();
e.printStackTrace();
}
return date;
}
/**
* 增加一个job
*
* @param jobClass
* 任务实现类
* @param jobName
* 任务名称
* @param jobGroupName
* 任务组名
* @param jobTime
* 时间表达式 (如:0/5 * * * * ? )
*/
@SuppressWarnings("all")
public String addJob(Class <? extends Job> jobClass, String jobName, String jobGroupName, String jobTime) {
String date = null;
try {
// 创建jobDetail实例,绑定Job实现类
// 指明job的名称,所在组的名称,以及绑定job类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)// 任务名称和组构成任务key
.build();
// 定义调度触发规则
// 使用cornTrigger规则
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)// 触发器key
.startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
.withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).startNow().build();
// 把作业和触发器注册到任务调度中
Date date1 = scheduler.scheduleJob(jobDetail, trigger);
date = sdf.format(date1);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
/**
* 修改 一个job的 时间表达式
*
* @param jobName 任务名
* @param jobGroupName 分组名
* @param jobTime 执行时间
*/
public void updateJob(String jobName, String jobGroupName, String jobTime) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();
// 重启触发器
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 删除任务一个job
*
* @param jobName
* 任务名称
* @param jobGroupName
* 任务组名
*/
public void deleteJob(String jobName, String jobGroupName) {
try {
scheduler.deleteJob(new JobKey(jobName, jobGroupName));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 暂停一个job
*
* @param jobName 任务名
* @param jobGroupName 分组名
*/
public void pauseJob(String jobName, String jobGroupName) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 恢复一个job
*
* @param jobName 任务名
* @param jobGroupName 分组名
*/
public void resumeJob(String jobName, String jobGroupName) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 立即执行一个job
*
* @param jobName 任务名
* @param jobGroupName 分组名
*/
public void runAJobNow(String jobName, String jobGroupName) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
scheduler.triggerJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 获取所有计划中的任务列表
*
* @return
*/
@SuppressWarnings("all")
public List<Map<String, Object>> queryAllJob() {
List<Map<String, Object>> jobList = null;
try {
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
jobList = new ArrayList<Map<String, Object>>();
for (JobKey jobKey : jobKeys) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
Map<String, Object> map = new HashMap<>();
map.put("jobName", jobKey.getName());
map.put("jobGroupName", jobKey.getGroup());
map.put("description", "触发器:" + trigger.getKey());
map.put("className", trigger.getJobDataMap().getString("className"));
map.put("classMethod", trigger.getJobDataMap().getString("method"));
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
map.put("jobStatus", triggerState.name());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
map.put("jobTime", cronExpression);
}
jobList.add(map);
}
}
} catch (SchedulerException e) {
e.printStackTrace();
}
return jobList;
}
/**
* 获取所有正在运行的job
*
* @return
*/
@SuppressWarnings("all")
public List<Map<String, Object>> queryRunJob() {
List<Map<String, Object>> jobList = null;
try {
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
jobList = new ArrayList<Map<String, Object>>(executingJobs.size());
for (JobExecutionContext executingJob : executingJobs) {
Map<String, Object> map = new HashMap<String, Object>();
JobDetail jobDetail = executingJob.getJobDetail();
JobKey jobKey = jobDetail.getKey();
Trigger trigger = executingJob.getTrigger();
map.put("jobName", jobKey.getName());
map.put("jobGroupName", jobKey.getGroup());
map.put("description", "触发器:" + trigger.getKey());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
map.put("jobStatus", triggerState.name());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
map.put("jobTime", cronExpression);
}
jobList.add(map);
}
} catch (SchedulerException e) {
e.printStackTrace();
}
return jobList;
}
@SuppressWarnings("all")
public Params integratedData(Params param, HttpServletResponse response,HttpServletRequest request){ //填充全类名
List list = QuartzreflectUtil.inputParamListOptimize(param, response, request);
if (list!=null && list.size()>0){
Object[] obj2 = new Object[list.size()]; //创建一个以参数长度一样的对象数组
QuartzreflectUtil.setObjelement(list, obj2);
param.setFinalMethodParam(obj2);
}
return param;
}
}
package com.example.df.quartz.controller;
import com.example.df.quartz.service.QuartzService;
import com.example.df.quartz.entry.Params;
import com.example.df.util.BaseControllerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Map;
/**
* @author xu
* @Description
* @createTime 2021年03月08日 17:34:00
*/
@RestController
@RequestMapping(value = "/quartz")
public class QuartController{
Logger logger = LoggerFactory.getLogger(this.getClass());
@SuppressWarnings("all")
@Autowired
QuartzService quartzService;
@SuppressWarnings("all")
@RequestMapping("/addjob")
public void startJob(@Valid @RequestBody Params param, HttpServletResponse response, HttpServletRequest request) {
Map map = quartzService.startaddJob(request, response, param);
BaseControllerUtil.renderResult(response, map);
}
@SuppressWarnings("all")
@RequestMapping("/updatejob")
public void updatejob(@RequestBody Map param, HttpServletResponse response) {
logger.info("更新任务");
String jobName = param.get("jobName").toString();
String jobGroupName = param.get("jobGroupName").toString();
String cron = param.get("cron").toString();
quartzService.updateJob(jobName, jobGroupName, cron);
BaseControllerUtil.renderResult(response, "更新成功");
}
@SuppressWarnings("all")
@RequestMapping("/deletejob")
public void deletejob(@RequestBody Map param, HttpServletResponse response) {
logger.info("任务删除");
String jobName = param.get("jobName").toString();
String jobGroupName = param.get("jobGroupName").toString();
quartzService.deleteJob(jobName, jobGroupName);
BaseControllerUtil.renderResult(response, "删除成功");
}
@SuppressWarnings("all")
@RequestMapping("/pauseJob")
public void pauseJob(@RequestBody Map param, HttpServletResponse response) {
logger.info("任务暂停");
String jobName = param.get("jobName").toString();
String jobGroupName = param.get("jobGroupName").toString();
quartzService.pauseJob(jobName, jobGroupName);
BaseControllerUtil.renderResult(response, "暂停成功");
}
@SuppressWarnings("all")
@RequestMapping("/resumeJob")
public void resumeJob(@RequestBody Map param, HttpServletResponse response) {
logger.info("重新开始任务");
String jobName = param.get("jobName").toString();
String jobGroupName = param.get("jobGroupName").toString();
quartzService.resumeJob(jobName, jobGroupName);
BaseControllerUtil.renderResult(response, "重新开始任务");
}
@SuppressWarnings("all")
@RequestMapping("/queryAllJob")
public Object queryAllJob() {
logger.info("查询所有任务");
return quartzService.queryAllJob();
}
@SuppressWarnings("all")
@RequestMapping("/queryRunJob")
public Object queryRunJob() {
logger.info("查询运行中的任务");
return quartzService.queryRunJob();
}
@SuppressWarnings("all")
@RequestMapping("/RunOnec")
public void RunOnec(@RequestBody Map param, HttpServletResponse response) {
logger.info("运行一次任务");
String jobName = param.get("jobName").toString();
String jobGroupName = param.get("jobGroupName").toString();
quartzService.runAJobNow(jobName,jobGroupName);
BaseControllerUtil.renderResult(response, "运行一次任务");
}
}
**
1、创建一个类实现job接口
package com.example.df.quartz.service;
import com.example.df.mapper.UserMapper;
import com.example.df.quartz.job.DynamicJob;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author xu
* @Description
* @createTime 2021年03月11日 14:37:00
*/
@Component
public class TestService implements DynamicJob<String>
{
@Autowired
UserMapper userMapper;
/**
* 定时任务执行的方法
* @param args 可变参数,前端传递,当时无参时为null
* @return
*/
@Override
public String task(Object... args)
{
String a =(String) args[0];
Integer cc =(Integer) args[1];
Map<String,Object> map = (Map<String,Object>) args[2];
for (String o : map.keySet()) {
System.out.println(o+"\t"+map.get(o));
}
System.out.println(cc);
System.out.println(a);
Integer count = userMapper.getCount();
System.out.println(count);
return count.toString();
}
}
添加有参数的方法任务。前端或请求参数格式如下
{
"className":"testService", 需要执行方法的类名(首字母小写,根据spring容器获取对象)
"jobName":"job2", 任务名(随意,可自定义。)
"jobGroupName":"test", 任务分组名(随意,可自定义。) 任务的暂停、执行、删除。。。都是根据任务名和分组名来确定任务
"cron":"0/5 * * * * ?", 执行时间(cron时间表达式)
"paramdata":[ 该方法需要接收的参数,根据方法传递
"String":"test",
"Map":{"cc":"ss","count":5},
"Integer":5
] 方法参数数据,"String表示数据类型" value为具体数据
}
添加无参方法任务。前端或请求参数格式如下
{
"className":"test",
"jobName":"job2",
"jobGroupName":"test",
"cron":"0/5 * * * * ?", 每五秒执行一次
}
定时任务所需要的所有代码已全部贴上。如有什么问题欢迎评论!
获取最新demo,可前往
giee地址demo