springboot整合quartz定时任务( JDBC作业存储方式)
一、介绍
Quartz提供两种基本作业存储类型:RAMJobStore、JDBC作业存储。
- RAMJobStore
RAM也就是内存,默认情况下Quartz会将任务调度存在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失。
2、JDBC作业存储
存到数据库之后,可以做单点也可以做集群,当任务多了之后,可以统一进行管理。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢。
本博客使用jdbc作业存储的方式,同时实现restFul请求对任务启停实现控制,当前应用springboot版本2.4.4。
二、搭建工程
- pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>quartz-job</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.0</version>
</dependency>
<!-- <dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.32.3.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- application.yml及application-dev.yml配置文件
application.yml
server:
port: 8080
spring:
profiles:
active: dev
#数据库配置mysql数据库
syx:
database:
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
driver: com.mysql.cj.jdbc.Driver
userName: xxxx
passwd: xxx
validationQuery: select 1 from dual
initSize: 3
minIdle: 3
maxActive: 10
checkTable: false
maxWaitTime: 60000
evictionRunTime: 60000
minEvictionIdleTime: 300000
keepAlive: true
testWhileIdle: true
testOnBorrow: true
testOnReturn: false
poolPreparedStatement: true
maxPoolPreparedStatementSizePerConnection: 20
validateQueryTimeOut: 3
application-dev.yml
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml #mapper文件的路径
#showSql
logging:
level:
com:
syx:
dao: debug
- 数据库配置类,主要是为了绑定application.yml中的数据库配置
package com.syx.microapplication.base;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @date: 2022-03-10 23:04
* <p>数据源配置参数</p>
*/
@Component
@ConfigurationProperties(prefix = "syx.database")
public class DataSourceConfigProperty {
private String url;
private String driver;
private String userName;
private String passwd;
private String validationQuery = "select 1 from dual";
//连接池初始大小
private String initSize = "3";
//最小连接数
private String minIdle = "3";
//最大连接数
private String maxActive ="10";
//是否开启表的初始化检查
private boolean checkTable = false;
//获取连接的最大等待时间单位为毫秒
private long maxWaitTime;
//空闲检测时间单位为毫秒
private long evictionRunTime;
//连接在池中最小生存时间单位毫秒
private long minEvictionIdleTime;
//
private boolean keepAlive;
private boolean testWhileIdle;
//获取连接时是否检测连接有效
private boolean testOnBorrow;
//连接归还时是否检测连接有效
private boolean testOnReturn;
//是否缓存PrepareStatement
private boolean poolPreparedStatement;
//每个连接的 PrepareStatement缓存大小
private int maxPoolPreparedStatementSizePerConnection;
//连接检测超时设置
private int validateQueryTimeOut;
//getters and setters....
}
- 应用配置
package com.syx.microapplication.base;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @date: 2022-03-11 00:15
* <p></p>
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(AppConfig.COMPONENT_SCAN)
@MapperScan(AppConfig.MAPPER_SCAN)
public class AppConfig {
//包扫描路径
protected static final String COMPONENT_SCAN = "com.syx";
//mybatis的dao路径
protected static final String MAPPER_SCAN = "com.syx.**.dao";
}
- 数据源配置,本应用使用的是druid数据源
package com.syx.microapplication.base;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
/**
* @date: 2022-03-10 23:01
* <p>数据源配置</p>
*/
@Configuration
@EnableTransactionManagement
@ConditionalOnClass(DataSource.class)
public class DataSourceConfig {
@Autowired
private DataSourceConfigProperty dataSourceConfigProperty;
@Bean
@Primary
public DruidDataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(dataSourceConfigProperty.getUrl());
druidDataSource.setDriverClassName(dataSourceConfigProperty.getDriver());
druidDataSource.setUsername(dataSourceConfigProperty.getUserName());
druidDataSource.setPassword(dataSourceConfigProperty.getPasswd());
druidDataSource.setInitialSize(Integer.parseInt(dataSourceConfigProperty.getInitSize()));
druidDataSource.setMinIdle(Integer.parseInt(dataSourceConfigProperty.getMinIdle()));
druidDataSource.setMaxActive(Integer.parseInt(dataSourceConfigProperty.getMaxActive()));
druidDataSource.setMaxWait(dataSourceConfigProperty.getMaxWaitTime());
druidDataSource.setTimeBetweenEvictionRunsMillis(dataSourceConfigProperty.getEvictionRunTime());
druidDataSource.setMinEvictableIdleTimeMillis(dataSourceConfigProperty.getMinEvictionIdleTime());
druidDataSource.setTestWhileIdle(dataSourceConfigProperty.isTestWhileIdle());
druidDataSource.setTestOnBorrow(dataSourceConfigProperty.isTestOnBorrow());
druidDataSource.setTestOnReturn(dataSourceConfigProperty.isTestOnReturn());
druidDataSource.setValidationQuery(dataSourceConfigProperty.getValidationQuery());
return druidDataSource;
}
/**
* druid监控平台
* @return
*/
@Bean
public ServletRegistrationBean<StatViewServlet> servletRegistrationBean(){
ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>();
StatViewServlet servlet = new StatViewServlet();
registrationBean.setServlet(servlet);
registrationBean.setName("druidView");
registrationBean.setLoadOnStartup(2);
List<String> urlMapping = new ArrayList<>();
urlMapping.add("/druid/*");
registrationBean.setUrlMappings(urlMapping);
return registrationBean;
}
}
- quartz核心配置类QuartzConfig,该类主要是往spring容器中注入SchedulerFactoryBean,该类是quartz调度器的核心类。同时加载quartz.properyies配置文件,及维护trigger应用的xml配置文件,定义在configJobs目录下。
package com.syx.microapplication.base;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.util.List;
import java.util.Set;
/**
* @date: 2022-03-10 22:28
* <p>
* * </p>
*/
@Configuration
@AutoConfigureAfter(DataSource.class)
@ImportResource(value = {
"classpath*:configJobs/*ApplicationContext.xml"
})
@PropertySource(value = {
"classpath:quartz.properties"
})
public class QuartzConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(QuartzConfig.class);
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource,QuartzTriggers quartzTriggers){
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(){
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
//项目启动时打印任务信息
triggerMsgPrint(super.getScheduler());
}
};
//配置数据源
schedulerFactoryBean.setDataSource(dataSource);
//设置quartz.properties
schedulerFactoryBean.setConfigLocation(new ClassPathResource("quartz.properties"));
//设置任务自启动
schedulerFactoryBean.setAutoStartup(true);
//设置调度器名称
schedulerFactoryBean.setSchedulerName("SYX_SCHEDULER");
//triggers维护在configJobs/*ApplicationContext.xml的文件中
schedulerFactoryBean.setTriggers(quartzTriggers.getTriggers());
schedulerFactoryBean.setOverwriteExistingJobs(true);
return schedulerFactoryBean;
}
/**
* 打印trigger信息
* @param scheduler
*/
private void triggerMsgPrint(Scheduler scheduler) throws SchedulerException {
List<String> groupNames = scheduler.getTriggerGroupNames();
for (String groupName : groupNames) {
Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupName));
for (TriggerKey triggerKey : triggerKeys) {
Trigger trigger = scheduler.getTrigger(triggerKey);
JobDetail jobDetail = scheduler.getJobDetail(trigger.getJobKey());
//在使用java配置job时需要指定key为JobName
LOGGER.info("任务名->{}",jobDetail.getJobDataMap().getString("JobName"));
LOGGER.info("任务描述->{}",jobDetail.getDescription());
//需要指定 默认指定为0
LOGGER.info("重复执行次数->{}",jobDetail.getJobDataMap().getString("RepeatTime"));
//需要指定 默认为10ms 维护在JobDataMap
LOGGER.info("重跑时间间隔->{}",jobDetail.getJobDataMap().getString("RepeatInterval"));
if(trigger instanceof CronTrigger){
CronTrigger temp = (CronTrigger) trigger;
LOGGER.info("cron表达式->{}",temp.getCronExpression());
LOGGER.info("开始执行时间->{}",temp.getStartTime());
}
if(trigger instanceof SimpleTrigger){
SimpleTrigger temp = (SimpleTrigger) trigger;
LOGGER.info("触发时间->{}",temp.getFinalFireTime());
LOGGER.info("开始执行时间->{}",temp.getStartTime());
}
LOGGER.info("下次执行时间->{}",trigger.getNextFireTime());
}
}
}
}
- QuartzTriggers配置类与configJobs/*ApplicationContext.xml对应,用于维护triggers
package com.syx.microapplication.base;
import org.quartz.Trigger;
import java.util.List;
/**
* @date: 2022-03-11 20:49
* <p>维护triggers</p>
*/
public class QuartzTriggers {
private List<Trigger> triggers;
public Trigger[] getTriggers(){
Trigger[] arr = new Trigger[this.triggers.size()];
for (int i = 0; i < this.triggers.size(); i++) {
arr[i] = this.triggers.get(i);
}
return arr;
}
public void setTriggers(List<Trigger> triggers) {
this.triggers = triggers;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--加载任务trigger-->
<import resource="classpath*:configJobs/jobs/*ApplicationContext.xml"/>
<!--将加载的任务trigger维护到QuartzTriggers的list中-->
<bean id="triggerCollection" class="com.syx.microapplication.base.QuartzTriggers">
<property name="triggers">
<list>
<ref bean="TestJobTrigger"/>
</list>
</property>
</bean>
</beans>
- 启动类,启动类中我们要排除springboot的quartz自动配置,进而使用我们自定义的SchedulerFactoryBean 的配置。查看QuartzAutoConfiguration源码亦可知,该类的主要作用为,往容器中注入了SchedulerFactoryBean。
package com.syx.microapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
/**
- @date: 2022-03-10 23:49
- <p></p>
*/
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class,args);
}
}
三、新建 job
- 新建测试job该任务必须实现org.quartz.Job接口。
package com.syx.demon.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* @date: 2022-03-11 21:53
* <p></p>
*/
public class TestJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Hello world...");
}
}
- 新建job对应的xml(这一步非常关键)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--自定义job任务-->
<bean id="TestJob" class="com.syx.demon.job.TestJob"/>
<!--job任务纳管到JobDetailFactoryBean类中-->
<bean id="TestJobName" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="description" value="TestJob测试"/>
<property name="group" value="TestJobGroup"/>
<property name="jobClass" value="com.syx.demon.job.TestJob"/>
<property name="durability" value="true"/>
<property name="jobDataAsMap">
<map>
<entry key="JobName" value="TestJob"/>
<entry key="RepeatTime" value="0"/>
<entry key="RepeatInterval" value="10"/>
</map>
</property>
</bean>
<!--将JobDetailFactoryBean配置到CronTriggerFactoryBean中,并指定cron表达式-->
<bean id="TestJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="TestJobName"/>
<property name="cronExpression" value="*/30 * * * * ?"/>
<!--错过是否补跑 0,1是 2 否-->
<property name="misfireInstruction" value="2"/>
</bean>
</beans>
四、启动工程
控制台打印了任务信息,同时任务也执行并输出了hello world…
数据库中记录了任务名,任务组及任务的class信息。
五、quartz扩展,通过http请求控制任务启停。
- 新建quartz任务调度控制service
package com.syx.microapplication.system.service;
import com.syx.microapplication.system.bean.QuartzJobDetail;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @date: 2022-03-12 16:20
* <p></p>
*/
@Service
public class QuartzSchedulerService {
@Autowired
private Scheduler scheduler;
private static final Logger LOGGER = LoggerFactory.getLogger(QuartzSchedulerService.class);
/**
* 查询所有任务
* @return
* @throws SchedulerException
*/
public List<QuartzJobDetail> getJobDetail() throws SchedulerException {
List<QuartzJobDetail> result = new ArrayList<>();
List<String> groupNames = scheduler.getJobGroupNames();
for (String groupName : groupNames) {
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
for (JobKey jobKey : jobKeys) {
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
QuartzJobDetail jobInfo = new QuartzJobDetail();
jobInfo.setSchedulerName(scheduler.getSchedulerName());
jobInfo.setSchedulerInstanceId(scheduler.getSchedulerInstanceId());
jobInfo.setJobName(jobKey.getName());
jobInfo.setDescription(jobDetail.getDescription());
jobInfo.setDurability(jobDetail.isDurable());
jobInfo.setRecover(jobDetail.requestsRecovery());
jobInfo.setGroup(jobKey.getGroup());
jobInfo.setJobClass(jobDetail.getJobClass().getName());
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
if(triggers!=null && !triggers.isEmpty()){
for (Trigger trigger : triggers) {
jobInfo.setState(scheduler.getTriggerState(trigger.getKey()).name());
jobInfo.setTriggersNum(triggers.size());
jobInfo.setNextFireTime(trigger.getNextFireTime());
}
}else{
jobInfo.setState("NONE");
}
result.add(jobInfo);
}
}
return result;
}
/**
* 删除job
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
public void deleteJob(String jobName,String jobGroup) throws SchedulerException {
scheduler.deleteJob(JobKey.jobKey(jobName,jobGroup));
}
/**
* 重启job
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
public void resumeJob(String jobName,String jobGroup) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(jobName,jobGroup));
}
/**
* 暂停job
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
public void pause(String jobName,String jobGroup) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(jobName,jobGroup));
}
/**
* 立即执行
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
public void triggerNow(String jobName,String jobGroup) throws SchedulerException {
scheduler.triggerJob(JobKey.jobKey(jobName,jobGroup));
}
}
- 任务详情包装类
package com.syx.microapplication.system.bean;
import com.syx.utils.IDUtil;
import java.util.Date;
import java.util.Map;
/**
* @date: 2022-03-12 15:40
* <p>quartzJob的描述信息</p>
*/
public class QuartzJobDetail {
private String description;
private boolean durability;
private String group;
private String jobClass;
private Map<String,Object> jobDataMap;
private String jobName;
private Date nextFireTime;
private int triggersNum;
private String quartzInstanceId;
private String schedulerInstanceId;
private String schedulerName;
private boolean recover;
private String state;
private String uuid=IDUtil.generateId();
//getters and setters
}
- 任务调度controller
package com.syx.microapplication.system.controller;
import com.syx.microapplication.system.bean.QuartzJobDetail;
import com.syx.microapplication.system.service.QuartzSchedulerService;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @date: 2022-03-12 15:31
* <p></p>
*/
@RestController
@RequestMapping("/quartzJob")
public class QuartzJobController {
@Autowired
private QuartzSchedulerService quartzSchedulerService;
private static final Logger LOGGER = LoggerFactory.getLogger(QuartzJobController.class);
@GetMapping
public List<QuartzJobDetail> getJobDetail() throws SchedulerException {
return quartzSchedulerService.getJobDetail();
}
/**
* 删除job
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
@DeleteMapping
public void deleteJob(String jobName,String jobGroup) throws SchedulerException {
quartzSchedulerService.deleteJob(jobName,jobGroup);
LOGGER.info("删除任务{}成功",jobName);
}
/**
* 重启job
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
@GetMapping(path = "{jobName}/{jobGroup}/resume")
public void resumeJob(@PathVariable(value = "jobName") String jobName,
@PathVariable(value = "jobGroup") String jobGroup) throws SchedulerException {
quartzSchedulerService.resumeJob(jobName,jobGroup);
LOGGER.info("重启任务{}成功",jobName);
}
/**
* 暂停job
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
@GetMapping(path = "{jobName}/{jobGroup}/pause")
public void pause(@PathVariable(value = "jobName") String jobName,
@PathVariable(value = "jobGroup") String jobGroup) throws SchedulerException {
quartzSchedulerService.pause(jobName,jobGroup);
LOGGER.info("暂停任务{}成功",jobName);
}
/**
* 立即执行
* @param jobName
* @param jobGroup
* @throws SchedulerException
*/
@GetMapping(path = "{jobName}/{jobGroup}/triggerNow")
public void triggerNow(@PathVariable(value = "jobName") String jobName,
@PathVariable(value = "jobGroup") String jobGroup) throws SchedulerException {
quartzSchedulerService.triggerNow(jobName,jobGroup);
LOGGER.info("任务{}启动成功",jobName);
}
}