更好的阅读体验:点这里 ( www.doubibiji.com
)
9 动态调度
源码:获取源码(0分下载,给个好评)
什么是动态调度?
动态调度就是不停止服务器,动态的控制定时任务的添加、修改、删除、启动、暂停等操作。
为什么需要动态调度?
如果现在有定时任务想停止运行或者修改执行时间,如果没有动态调度,那么就需要停止服务器,修改代码重新运行项目,具有很大的局限性。所以如果能在 web 页面动态控制定时任务的运行就很方便了。
例如有下面这样一个页面来管理定时任务就好了:
这里就不编写上面这个页面了,只实现后端的接口的实现。
下面来一步一步实现。
注意一下,如果你按照前面的内容进行了 Quartz 的持久化,那么 Quart 的表中可能有数据,但是下面操作重新整理了项目,删除了之前的一些任务类,这样启动项目的时候,Quartz会重新加载数据,找不到对应的任务类,会报错,所以需要先清空一下 Quartz 各个表的数据。
清空表的语句:
DELETE FROM QRTZ_LOCKS;
DELETE FROM QRTZ_CALENDARS;
DELETE FROM QRTZ_FIRED_TRIGGERS;
DELETE FROM QRTZ_PAUSED_TRIGGER_GRPS;
DELETE FROM QRTZ_SCHEDULER_STATE;
DELETE FROM QRTZ_BLOB_TRIGGERS;
DELETE FROM QRTZ_CRON_TRIGGERS;
DELETE FROM QRTZ_SIMPLE_TRIGGERS;
DELETE FROM QRTZ_SIMPROP_TRIGGERS;
DELETE FROM QRTZ_TRIGGERS;
DELETE FROM QRTZ_JOB_DETAILS;
1 新建SpringBoot项目
新建 SpringBoot 项目这里就不介绍了。可能你的项目已经是 SpringBoot 的项目了。
2 添加依赖
在项目的 pom.xml 中添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
直接使用 starter 的方式集成。
3 建表
因为我们需要对任务进行创建、删除、更新任务,所以要将任务保存下来,所以需要建表来保存我们的任务。
正常情况下,我们是有一个任务列表页面,显示所有的任务,可以对这些任务进行操作,也就是一个 CRUD 的功能。
CREATE TABLE tz_schedule_job (
`id` varchar(32) NOT NULL COMMENT 'ID',
`job_name` varchar(128) NOT NULL COMMENT '任务名称',
`bean_name` varchar(128) NOT NULL COMMENT 'spring容器中bean的名称',
`method_name` varchar(128) NOT NULL COMMENT 'bean中的方法名',
`cron_expression` varchar(32) NOT NULL COMMENT 'cron表达式',
`params` varchar(512) DEFAULT NULL COMMENT '调用任务传递的参数',
`status` tinyint(1) NOT NULL COMMENT '状态:1启用 0停用',
`remark` varchar(512) DEFAULT NULL COMMENT '任务备注',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4 创建pojo和mapper
这里使用 mybatis-plus
来操作 tz_schedule_job
表数据,所以需要创建表对应的实体类。
ScheduleJob.java
package com.doubibiji.springbootquartz.pojo;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("tz_schedule_job")
public class ScheduleJob implements Serializable {
// 任务id
@TableId
private String id;
private String jobName;
private String beanName;
private String methodName;
private String cronExpression;
private String params;
private Integer status;
private String remark;
private Date createTime;
private Date updateTime;
}
ScheduleJobMapper.java
package com.doubibiji.springbootquartz.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.doubibiji.springbootquartz.pojo.ScheduleJob;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface ScheduleJobMapper extends BaseMapper<ScheduleJob> {
/**
* 批量修改任务状态
*/
int updateBatch(@Param("jobIds") String[] jobIds, @Param("status") int status);
}
在 resources/mapper 下新建 ScheduleJobMapper.xml
ScheduleJobMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.doubibiji.springbootquartz.mapper.ScheduleJobMapper">
<!-- 批量更新状态 -->
<update id="updateBatch">
update tz_schedule_job set status = #{status} where id in
<foreach item="jobId" collection="jobIds" open="(" separator="," close=")">
#{jobId}
</foreach>
</update>
</mapper>
5 业务类
业务类就是要处理定时任务实际要执行的业务逻辑的类。
后面定时任务会定时调用这个类中的方法,重复执行。
OrderServiceImpl.java
package com.doubibiji.springbootquartz.service.impl;
import com.doubibiji.springbootquartz.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service("orderService")
public class OrderServiceImpl implements OrderService {
@Override
public void checkOrderPayResult() {
log.info("检查订单是否支付成功");
}
@Override
public void checkOrderExpire() {
log.info("检查订单是否超时");
}
}
注意:一定要添加 @Service("orderService")
注解,后面会通过 orderService
名称到 Spring 容器中获取这个对象。
6 任务类
任务类只有一个,任务类接收实体类对象 ScheduleJob
。获取实体类中的 beanName
和 methodName
属性,通过 beanName
到 Spring 容器中获取业务类对象
,然后通过反射执行 methodName
指定的方法。
package com.doubibiji.springbootquartz.job;
import com.doubibiji.springbootquartz.pojo.ScheduleJob;
import com.doubibiji.springbootquartz.util.JobInvokeUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
@Slf4j
public class QuartzJob extends QuartzJobBean {
public static final String SCHEDULE_JOB = "SCHEDULE_JOB_KEY";
@Override
protected void executeInternal(JobExecutionContext context) {
// 获取到ScheduleJob对象
ScheduleJob scheduleJob = (ScheduleJob) context.getMergedJobDataMap().get(SCHEDULE_JOB);
// 在这个方法中,通过ScheduleJob对象中的类创建对象,并触发指定的方法
JobInvokeUtil.invokeMethod(scheduleJob);
}
}
这里和前面实现定时任务有一些不同,在前面,我们有一个定时任务就创建一个任务类。这里我们只创建一个任务类,所有的任务都是通过这一个任务类来调用。也就是我们有多个任务的话,通过不同的触发器来调用这一个任务。然后在这个任务中,通过不同的参数,来确定调用哪个业务方法。
7 工具类
工具类主要处理通过 beanName
和 methodName
的值找到 Spring 容器中的 业务类对象
,然后通过反射执行 methodName
指定的方法。
JobInvokeUtil.java
package com.doubibiji.springbootquartz.util;
import cn.hutool.core.util.StrUtil;
import com.doubibiji.springbootquartz.pojo.ScheduleJob;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
/**
* 任务执行工具
*/
public class JobInvokeUtil {
/**
* 执行方法
*/
public static void invokeMethod(ScheduleJob scheduleJob) {
// 获取到bean
Object target = SpringContextUtils.getBean(scheduleJob.getBeanName());
try {
if (StrUtil.isNotEmpty(scheduleJob.getParams())) {
Method method = target.getClass().getDeclaredMethod(scheduleJob.getMethodName(), String.class);
ReflectionUtils.makeAccessible(method);
// 调用bean中的方法
method.invoke(target, scheduleJob.getParams());
} else {
Method method = target.getClass().getDeclaredMethod(scheduleJob.getMethodName());
ReflectionUtils.makeAccessible(method);
// 调用bean中的方法
method.invoke(target);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("执行定时任务失败", e);
}
}
}
SpringContextUtils
是获取 Spring 容器中对象的工具类:
package com.doubibiji.springbootquartz.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring Context 工具类
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<? extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
还有一个工具类,就是操作 Quartz 任务的工具类。
ScheduleManager.java
package com.doubibiji.springbootquartz.config;
import com.doubibiji.springbootquartz.constant.ScheduleStatus;
import com.doubibiji.springbootquartz.job.QuartzJob;
import com.doubibiji.springbootquartz.pojo.ScheduleJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 定时任务工具类
*/
@Component
public class ScheduleManager {
private final static String JOB_NAME = "TASK_";
@Autowired
private Scheduler scheduler;
/**
* 获取触发器key
*/
private TriggerKey getTriggerKey(ScheduleJob scheduleJob) {
return TriggerKey.triggerKey(JOB_NAME + scheduleJob.getId());
}
/**
* 获取jobKey
*/
private JobKey getJobKey(ScheduleJob scheduleJob) {
return JobKey.jobKey(JOB_NAME + scheduleJob.getId());
}
/**
* 获取表达式触发器
*/
public CronTrigger getCronTrigger(ScheduleJob scheduleJob) {
try {
return (CronTrigger) scheduler.getTrigger(getTriggerKey(scheduleJob));
} catch (SchedulerException e) {
throw new RuntimeException("获取定时任务CronTrigger出现异常", e);
}
}
/**
* 创建定时任务
*/
public void createScheduleJob(ScheduleJob scheduleJob) {
try {
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity(getJobKey(scheduleJob)).build();
//表达式调度构建器,可以根据scheduleJob修改withMisfireHandling方法
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
.withMisfireHandlingInstructionFireAndProceed();
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob)).withSchedule(scheduleBuilder).build();
// 放入参数,也就是要执行的任务信息,运行时的方法可以获取
jobDetail.getJobDataMap().put(QuartzJob.SCHEDULE_JOB, scheduleJob);
scheduler.scheduleJob(jobDetail, trigger);
//暂停任务
if (scheduleJob.getStatus().equals(ScheduleStatus.PAUSE.getType())) {
pauseJob(scheduleJob);
}
} catch (SchedulerException e) {
throw new RuntimeException("创建定时任务失败", e);
}
}
/**
* 更新定时任务
*/
public void updateScheduleJob(ScheduleJob scheduleJob) {
try {
TriggerKey triggerKey = getTriggerKey(scheduleJob);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()).withMisfireHandlingInstructionFireAndProceed();
CronTrigger trigger = getCronTrigger(scheduleJob);
// 如果定时任务不存在,则创建定时任务
if (trigger == null) {
createScheduleJob(scheduleJob);
return;
}
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 传递参数
trigger.getJobDataMap().put(QuartzJob.SCHEDULE_JOB, scheduleJob);
scheduler.rescheduleJob(triggerKey, trigger);
//暂停任务
if (scheduleJob.getStatus().equals(ScheduleStatus.PAUSE.getType())) {
pauseJob(scheduleJob);
}
} catch (SchedulerException e) {
throw new RuntimeException("更新定时任务失败", e);
}
}
/**
* 立即执行任务
*/
public void run(ScheduleJob scheduleJob) {
try {
//参数
JobDataMap dataMap = new JobDataMap();
dataMap.put(QuartzJob.SCHEDULE_JOB, scheduleJob);
scheduler.triggerJob(getJobKey(scheduleJob), dataMap);
} catch (SchedulerException e) {
throw new RuntimeException("立即执行定时任务失败", e);
}
}
/**
* 暂停任务
*/
public void pauseJob(ScheduleJob scheduleJob) {
try {
scheduler.pauseJob(getJobKey(scheduleJob));
} catch (SchedulerException e) {
throw new RuntimeException("暂停定时任务失败", e);
}
}
/**
* 恢复任务
*/
public void resumeJob(ScheduleJob scheduleJob) {
try {
scheduler.resumeJob(getJobKey(scheduleJob));
} catch (SchedulerException e) {
throw new RuntimeException("恢复定时任务失败", e);
}
}
/**
* 删除定时任务
*/
public void deleteScheduleJob(ScheduleJob scheduleJob) {
try {
// 停止触发器
scheduler.pauseTrigger(getTriggerKey(scheduleJob));
// 移除触发器
scheduler.unscheduleJob(getTriggerKey(scheduleJob));
// 删除任务
scheduler.deleteJob(getJobKey(scheduleJob));
} catch (SchedulerException e) {
throw new RuntimeException("删除定时任务失败", e);
}
}
}
解释一下 createScheduleJob(ScheduleJob scheduleJob)
方法。
该方法接收到 ScheduleJob 对象,通过该对象来创建定时任务,创建定时任务使用的就是前面的任务类,将 ScheduleJob 对象传递到任务类中,每次触发任务,在任务类中都通过传递的 ScheduleJob 对象,使用 JobInvokeUtil.invokeMethod(scheduleJob);
的方式调用业务类。
触发器使用 ScheduleJob 对象中的 cronExpression
属性来创建。
上面只是一个工具类,我们需要在维护任务的时候,调用上面的工具类。
8 任务维护
正常情况下,我们会有一个任务的维护页面,显示一个任务列表,然后在页面上通过按钮调用后端的接口。
这里只实现后端的接口,就不实现页面了。
接口实现:
ScheduleJobController.java
package com.doubibiji.springbootquartz.controller;
import com.doubibiji.springbootquartz.pojo.ScheduleJob;
import com.doubibiji.springbootquartz.service.ScheduleJobService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 定时任务
*/
@Slf4j
@RestController
@RequestMapping("/schedule")
public class ScheduleJobController {
@Autowired
private ScheduleJobService scheduleJobService;
/**
* 定时任务列表
*/
@GetMapping("/list")
public ResponseEntity<List<ScheduleJob>> list(){
List<ScheduleJob> scheduleJobList = scheduleJobService.list();
return ResponseEntity.ok(scheduleJobList);
}
/**
* 保存定时任务
*/
@PostMapping
public ResponseEntity<Void> save(@RequestBody ScheduleJob scheduleJob){
scheduleJobService.saveAndStart(scheduleJob);
return ResponseEntity.ok().build();
}
/**
* 修改定时任务
*/
@PutMapping
public ResponseEntity<Void> update(@RequestBody ScheduleJob scheduleJob){
scheduleJobService.updateScheduleJob(scheduleJob);
return ResponseEntity.ok().build();
}
/**
* 删除定时任务
*/
@DeleteMapping
public ResponseEntity<Void> delete(@RequestBody String[] jobIds){
scheduleJobService.deleteBatch(jobIds);
return ResponseEntity.ok().build();
}
/**
* 立即执行一次任务
*/
@PostMapping("/run")
public ResponseEntity<Void> run(@RequestBody String[] jobIds){
scheduleJobService.run(jobIds);
return ResponseEntity.ok().build();
}
/**
* 暂停定时任务
*/
@PostMapping("/pause")
public ResponseEntity<Void> pause(@RequestBody String[] jobIds){
scheduleJobService.pause(jobIds);
return ResponseEntity.ok().build();
}
/**
* 恢复定时任务
*/
@PostMapping("/resume")
public ResponseEntity<Void> resume(@RequestBody String[] jobIds){
scheduleJobService.resume(jobIds);
return ResponseEntity.ok().build();
}
}
Service 实现
在 Service 中实现任务数据的维护,更新数据库的数据,同时调用 Quartz 工具类,修改任务的调度。
ScheduleJobServiceImpl.java
package com.doubibiji.springbootquartz.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.doubibiji.springbootquartz.config.ScheduleManager;
import com.doubibiji.springbootquartz.constant.ScheduleStatus;
import com.doubibiji.springbootquartz.mapper.ScheduleJobMapper;
import com.doubibiji.springbootquartz.pojo.ScheduleJob;
import com.doubibiji.springbootquartz.service.ScheduleJobService;
import org.quartz.CronTrigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@Service
public class ScheduleJobServiceImpl implements ScheduleJobService {
@Autowired
private ScheduleJobMapper scheduleJobMapper;
@Autowired
private ScheduleManager scheduleManager;
/**
* 项目启动时,初始化定时器
*/
@PostConstruct
public void init(){
// 初始化的时候,查询到所有的定时任务,查看哪些定时任务需要启动
List<ScheduleJob> scheduleJobList = scheduleJobMapper.selectList(null);
for (ScheduleJob scheduleJob : scheduleJobList) {
// 从调度器中获取触发器,查看是否需要创建、恢复、暂停
CronTrigger trigger = scheduleManager.getCronTrigger(scheduleJob);
// 如果定时任务不存在,则创建定时任务
if (trigger == null) {
scheduleManager.createScheduleJob(scheduleJob);
}
else if (ScheduleStatus.NORMAL.getType().equals(scheduleJob.getStatus())) {
scheduleManager.resumeJob(scheduleJob);
}
else if (ScheduleStatus.PAUSE.getType().equals(scheduleJob.getStatus())) {
scheduleManager.pauseJob(scheduleJob);
}
}
}
/**
* 查询所有的定时任务
*/
public List<ScheduleJob> list() {
// 初始化的时候,查询到所有的定时任务,查看哪些定时任务需要启动
List<ScheduleJob> scheduleJobList = scheduleJobMapper.selectList(null);
return scheduleJobList;
}
/**
* 保存并开始定时任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void saveAndStart(ScheduleJob scheduleJob) {
// 先查看是否已经有相同的定时任务了
LambdaQueryWrapper<ScheduleJob> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ScheduleJob::getBeanName, scheduleJob.getBeanName());
queryWrapper.eq(ScheduleJob::getMethodName, scheduleJob.getMethodName());
long sameCount = scheduleJobMapper.selectCount(queryWrapper);
if (sameCount > 0) {
throw new RuntimeException("与存在相同的定时任务");
}
scheduleJob.setCreateTime(new Date());
scheduleJob.setStatus(ScheduleStatus.NORMAL.getType());
scheduleJobMapper.insert(scheduleJob);
// 创建定时任务
scheduleManager.createScheduleJob(scheduleJob);
}
/**
* 更新任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateScheduleJob(ScheduleJob scheduleJob) {
// 先查看是否已经有相同的定时任务了
LambdaQueryWrapper<ScheduleJob> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ScheduleJob::getBeanName, scheduleJob.getBeanName());
queryWrapper.eq(ScheduleJob::getMethodName, scheduleJob.getMethodName());
queryWrapper.ne(ScheduleJob::getId, scheduleJob.getId());
long sameCount = scheduleJobMapper.selectCount(queryWrapper);
if (sameCount > 0) {
throw new RuntimeException("与存在相同的定时任务");
}
scheduleJob.setUpdateTime(new Date());
scheduleManager.updateScheduleJob(scheduleJob);
scheduleJobMapper.updateById(scheduleJob);
}
/**
* 删除任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteBatch(String[] jobIds) {
List<String> ids = Arrays.asList(jobIds);
List<ScheduleJob> scheduleJobList = scheduleJobMapper.selectBatchIds(ids);
for (ScheduleJob scheduleJob : scheduleJobList) {
// 删除定时任务
scheduleManager.deleteScheduleJob(scheduleJob);
}
scheduleJobMapper.deleteBatchIds(ids);
}
/**
* 立即执行一次任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void run(String[] jobIds) {
for(String jobId : jobIds){
scheduleManager.run(scheduleJobMapper.selectById(jobId));
}
}
/**
* 暂停任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void pause(String[] jobIds) {
List<String> ids = Arrays.asList(jobIds);
List<ScheduleJob> scheduleJobList = scheduleJobMapper.selectBatchIds(ids);
for (ScheduleJob scheduleJob : scheduleJobList) {
scheduleManager.pauseJob(scheduleJob);
}
// 更新任务状态
updateBatch(jobIds, ScheduleStatus.PAUSE.getType());
}
/**
* 恢复任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void resume(String[] jobIds) {
List<String> ids = Arrays.asList(jobIds);
List<ScheduleJob> scheduleJobList = scheduleJobMapper.selectBatchIds(ids);
for (ScheduleJob scheduleJob : scheduleJobList) {
scheduleManager.resumeJob(scheduleJob);
}
// 更新任务状态
updateBatch(jobIds, ScheduleStatus.NORMAL.getType());
}
/**
* 批量更新任务状态
*/
public int updateBatch(String[] jobIds, int status) {
return scheduleJobMapper.updateBatch(jobIds, status);
}
}
9 项目配置
application.yaml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/doubibiji-db?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 3
maximum-pool-size: 10
idle-timeout: 10000
connection-test-query: select 1
initialization-fail-timeout: 15000
connection-timeout: 15000
# quartz 配置
quartz:
job-store-type: jdbc # 使用jdbc的方式持久化
jdbc:
initialize-schema: never # 启动后,不创建数据库表
# 属性配置
properties:
org:
quartz:
# 集群配置
scheduler:
instanceName: MyScheduler # 名称自定义,一起集群的各个服务器,名称要一致
instanceId: AUTO # 实例ID,各个集群的服务器,不能重复,这里使用自动生成就好了
jobStore:
isClustered: true # 是否进行集群配置
misfireThreshold: 10000 # 设置任务调度器的 Misfire 阈值为 10000 毫秒
# mybaits-plus配置
mybatis-plus:
# MyBatis Mapper所对应的XML文件位置
mapper-locations: classpath*:/mapper/*Mapper.xml
global-config:
# 关闭MP3.0自带的banner
banner: false
db-config:
# 主键类型 0:数据库ID自增 1.未定义 2.用户输入 3 id_worker 4.uuid 5.id_worker字符串表示
id-type: assign_uuid
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: NOT_NULL
# 默认数据库表下划线命名
table-underline: true
项目结构如下:
10 调用
使用 Postman 调用接口进行测试。
创建任务:
后台执行结果:
暂停任务:
11 可能出现的错误
在执行任务的时候,可能出现以下错误,ScheduleJob 传递到任务类中,再次获取报转换错误的问题。
java.lang.ClassCastException: class com.doubibiji.springbootquartz.pojo.ScheduleJob cannot be cast to class com.doubibiji.springbootquartz.pojo.ScheduleJob (com.doubibiji.springbootquartz.pojo.ScheduleJob is in unnamed module of loader 'app'; com.doubibiji.springbootquartz.pojo.ScheduleJob is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @50d4c396)
at com.doubibiji.springbootquartz.job.QuartzJob.executeInternal(QuartzJob.java:17) ~[classes/:na]
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) ~[spring-context-support-5.3.31.jar:5.3.31]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.2.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) ~[quartz-2.3.2.jar:na]
2024-01-05 21:12:03.223 ERROR 98290 --- [eduler_Worker-1] org.quartz.core.ErrorLogger : Job (DEFAULT.TASK_92599230a8db58564fdda00b5813db12 threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213) ~[quartz-2.3.2.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) ~[quartz-2.3.2.jar:na]
Caused by: java.lang.ClassCastException: class com.doubibiji.springbootquartz.pojo.ScheduleJob cannot be cast to class com.doubibiji.springbootquartz.pojo.ScheduleJob (com.doubibiji.springbootquartz.pojo.ScheduleJob is in unnamed module of loader 'app'; com.doubibiji.springbootquartz.pojo.ScheduleJob is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @50d4c396)
at com.doubibiji.springbootquartz.job.QuartzJob.executeInternal(QuartzJob.java:17) ~[classes/:na]
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) ~[spring-context-support-5.3.31.jar:5.3.31]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.2.jar:na]
... 1 common frames omitted
将项目中的 spring-boot-devtools
去掉就可以了。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
源码:获取源码 (0分下载,给个好评)