quartz 动态添加job_spring boot Quartz基于持久化存储的动态管理
精彩回顾
我们在spring boot quartz定时任务基本使用及介绍和spring boot quartz持久化存储分别对quartz基本信息及持久化存储进行了介绍。
这篇文章我们继续介绍给予持久化存储实现任务的动态管理。
创建表结构
为了存储我们自己动态创建的任务,除了spring boot quartz持久化存储
介绍的添加quartz表结构之外,我们还需要添加一个自己的表。以下是MySQL的表结构,其他类型的数据库请按需修改。
/* Navicat Premium Data Transfer Source Server : localhost Source Server Type : MySQL Source Server Version : 80021 Source Host : localhost:3306 Source Schema : quartz Target Server Type : MySQL Target Server Version : 80021 File Encoding : 65001 Date: 30/09/2020 13:34:24*/SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for task_quartz-- ----------------------------DROP TABLE IF EXISTS `task_quartz`;CREATE TABLE `task_quartz` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `job_group` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务分组', `job_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务名', `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务描述', `cron_expression` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'cron表达式', `job_class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务执行时调用哪个类的方法 包名+类名', `job_status` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1' COMMENT '任务状态', `create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '创建者', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `modify_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '更新者', `modify_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `NameWithGroup`(`job_group`, `job_name`) USING BTREE COMMENT '任务及分组唯一') ENGINE = MyISAM AUTO_INCREMENT = 68 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
创建工程,添加依赖
如果要实现任务的动态管理,这里单独借助一张表,存储任务的信息。
先介绍一个依赖的情况:
- MySQL数据库
- mybatis执行sql
- quartz依赖
- lombok
具体项目依赖如下:
org.springframework.boot spring-boot-starter-quartz org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.3mysql mysql-connector-java runtime
修改配置文件
application.yaml
server: port: 8080spring: profiles: active: dev
application-dev.yaml
spring: datasource: url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&&serverTimezone=UTC username: root password: root type: com.zaxxer.hikari.HikariDataSource quartz: job-store-type: jdbcmybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: net.xiangcaowuyu.quartztask.entity configuration: map-underscore-to-camel-case: true
主要配置信息:
- MySQL数据库连接
- mybatis配置
- job-store-type存储到数据库
增加mybatis相关操作
TaskQuartzMapper.xml
<?xml version="1.0" encoding="UTF-8"?> id, job_group, job_name, description, cron_expression, job_class_name, job_status, create_by, create_time, modify_by, modify_time select from task_quartz where id = #{id,jdbcType=BIGINT} select from task_quartz where job_name = #{jonName,jdbcType=VARCHAR} and job_group = #{jobGroup,jdbcType=VARCHAR} delete from task_quartz where id = #{id,jdbcType=BIGINT} delete from task_quartz where job_name = #{jonName,jdbcType=VARCHAR} and job_group = #{jobGroup,jdbcType=VARCHAR} insert into task_quartz (job_group, job_name, description, cron_expression, job_class_name, job_status, create_by, create_time, modify_by, modify_time) values (#{jobGroup,jdbcType=VARCHAR}, #{jobName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{cronExpression,jdbcType=VARCHAR}, #{jobClassName,jdbcType=VARCHAR}, #{jobStatus,jdbcType=VARCHAR}, #{createBy,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyBy,jdbcType=VARCHAR}, #{modifyTime,jdbcType=TIMESTAMP}) insert into task_quartz job_group, job_name, description, cron_expression, job_class_name, job_status, create_by, create_time, modify_by, modify_time, #{jobGroup,jdbcType=VARCHAR}, #{jobName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{cronExpression,jdbcType=VARCHAR}, #{jobClassName,jdbcType=VARCHAR}, #{jobStatus,jdbcType=VARCHAR}, #{createBy,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyBy,jdbcType=VARCHAR}, #{modifyTime,jdbcType=TIMESTAMP}, update task_quartz job_group = #{jobGroup,jdbcType=VARCHAR}, job_name = #{jobName,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR}, cron_expression = #{cronExpression,jdbcType=VARCHAR}, job_class_name = #{jobClassName,jdbcType=VARCHAR}, job_status = #{jobStatus,jdbcType=VARCHAR}, create_by = #{createBy,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=TIMESTAMP}, modify_by = #{modifyBy,jdbcType=VARCHAR}, modify_time = #{modifyTime,jdbcType=TIMESTAMP}, where id = #{id,jdbcType=BIGINT} update task_quartz set job_group = #{jobGroup,jdbcType=VARCHAR}, job_name = #{jobName,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR}, cron_expression = #{cronExpression,jdbcType=VARCHAR}, job_class_name = #{jobClassName,jdbcType=VARCHAR}, job_status = #{jobStatus,jdbcType=VARCHAR}, create_by = #{createBy,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=TIMESTAMP}, modify_by = #{modifyBy,jdbcType=VARCHAR}, modify_time = #{modifyTime,jdbcType=TIMESTAMP} where id = #{id,jdbcType=BIGINT}
TaskQuartz.java
/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.org */@Datapublic class TaskQuartz implements Serializable { private Long id; /** * 任务分组 */ private String jobGroup; /** * 任务名 */ private String jobName; /** * 任务描述 */ private String description; /** * cron表达式 */ private String cronExpression; /** * 任务执行时调用哪个类的方法 包名+类名 */ private String jobClassName; /** * 任务状态 */ private String jobStatus; /** * 创建者 */ private String createBy; /** * 创建时间 */ private Date createTime; /** * 更新者 */ private String modifyBy; /** * 更新时间 */ private Date modifyTime; private static final long serialVersionUID = 1L;}
TaskQuartzService.java
/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.org */public interface TaskQuartzService { /** * 根据主键删除 * @param id 主键 * @return 删除行数 */ int deleteByPrimaryKey(Long id); /** * 插入 * @param record 实体 * @return 成功返回1 */ int insert(TaskQuartz record); /** * 插入修改的值 * @param record 实体 * @return 成功返回1 */ int insertSelective(TaskQuartz record); /** * 根据主键获取 * @param id 主键 * @return 实体 */ TaskQuartz selectByPrimaryKey(Long id); /** * 更新 * @param record 实体 * @return 更新成功返回1 */ int updateByPrimaryKeySelective(TaskQuartz record); /** * 更新所有值 * @param record 实体 * @return 成功返回1 */ int updateByPrimaryKey(TaskQuartz record); /** * 根据名称及分组查找 * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ TaskQuartz selectByJobNameAndJobGroup(@Param("jonName") String jobName, @Param("jobGroup") String jobGroup); /** * 根据名称及分组查找 * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ int deleteByJobNameAndJobGroup(@Param("jonName") String jobName,@Param("jobGroup") String jobGroup);}
TaskQuartzServiceImpl.java
/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.org */@Servicepublic class TaskQuartzServiceImpl implements TaskQuartzService { @Resource TaskQuartzMapper taskQuartzMapper; /** * 根据主键删除 * * @param id 主键 * @return 删除行数 */ @Override public int deleteByPrimaryKey(Long id) { return taskQuartzMapper.deleteByPrimaryKey(id); } /** * 插入 * * @param record 实体 * @return 成功返回1 */ @Override public int insert(TaskQuartz record) { return taskQuartzMapper.insert(record); } /** * 插入修改的值 * * @param record 实体 * @return 成功返回1 */ @Override public int insertSelective(TaskQuartz record) { return taskQuartzMapper.insertSelective(record); } /** * 根据主键获取 * * @param id 主键 * @return 实体 */ @Override public TaskQuartz selectByPrimaryKey(Long id) { return taskQuartzMapper.selectByPrimaryKey(id); } /** * 更新 * * @param record 实体 * @return 更新成功返回1 */ @Override public int updateByPrimaryKeySelective(TaskQuartz record) { return taskQuartzMapper.updateByPrimaryKeySelective(record); } /** * 更新所有值 * * @param record 实体 * @return 成功返回1 */ @Override public int updateByPrimaryKey(TaskQuartz record) { return taskQuartzMapper.updateByPrimaryKey(record); } /** * 根据名称及分组查找 * * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ @Override public TaskQuartz selectByJobNameAndJobGroup(String jobName, String jobGroup) { return taskQuartzMapper.selectByJobNameAndJobGroup(jobName,jobGroup); } /** * 根据名称及分组查找 * * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ @Override public int deleteByJobNameAndJobGroup(String jobName, String jobGroup) { return taskQuartzMapper.deleteByJobNameAndJobGroup(jobName,jobGroup); }}
增加测试任务
PrintJob.java
/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.org */public class PrintJob implements Job { private final Logger logger = LoggerFactory.getLogger(PrintJob.class); /** * 执行任务 * * @param jobExecutionContext * @throws JobExecutionException */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { try { logger.info("Hello Job执行时间: " + new Date() + " Blog:" + jobExecutionContext.getJobDetail().getJobDataMap().get("blog")); Thread.sleep(1000 * 5); System.out.println("================执行完成========================"); } catch (Exception e) { e.printStackTrace(); } }}
测试新增任务
新增任务时,我们并没有创建quartz相关表,只是存储到task_quartz表中,任务启动时,插入quartz表
/** * 新增或者保存任务 * 任务只是存储到task_quartz表中,任务启动时,插入quartz表 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("saveQuartz") public Result save(@RequestBody TaskQuartz taskQuartz) { TaskQuartz task = taskQuartzService.selectByJobNameAndJobGroup(taskQuartz.getJobName(), taskQuartz.getJobGroup()); if (task == null) { task = new TaskQuartz(); BeanUtils.copyProperties(taskQuartz, task); taskQuartzService.insertSelective(task); } else { taskQuartzService.updateByPrimaryKeySelective(taskQuartz); } return Result.ok(); }
测试启动任务
任务启动时,启动任务时,将任务信息持久化到quartz表中
/** * 启用任务 * 启动任务时,将任务信息持久化到quartz表中 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("startJob") public Result startJob(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz);// 存在先删除 if (scheduler.checkExists(jobKey)) { scheduler.deleteJob(jobKey); } Class classz = Class.forName(taskQuartz.getJobClassName()); JobDetail jobDetail = JobBuilder.newJob() .withDescription(taskQuartz.getDescription()) .withIdentity(jobKey) .usingJobData("blog", "https://www.xiangcaowuyu.net") .ofType(classz).build(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("Trigger_" + taskQuartz.getJobName(), "TriggerGroup_" + taskQuartz.getJobGroup()) .withSchedule(CronScheduleBuilder.cronSchedule(taskQuartz.getCronExpression())) .startNow() .build(); scheduler.scheduleJob(jobDetail, trigger); } catch (Exception exception) { return Result.error(exception.getMessage()); } return Result.ok(); }
通过postman测试,我们可以观察控制台,任务时10s执行一次
暂停任务
/** * 暂停任务 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("shutdown") public Result shutdown(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz); scheduler.pauseJob(jobKey); return Result.ok(); } catch (Exception ex) { return Result.error(ex.getMessage()); } }
恢复任务
/** * 恢复任务 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("resumeJob") public Result resumeJob(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz); scheduler.resumeJob(jobKey); return Result.ok(); } catch (Exception ex) { return Result.error(ex.getMessage()); } }
删除任务
/** * 删除任务 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("removeJob") public Result removeJob(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz); scheduler.deleteJob(jobKey); taskQuartzService.deleteByJobNameAndJobGroup(taskQuartz.getJobName(),taskQuartz.getJobGroup()); return Result.ok(); } catch (Exception ex) { return Result.error(ex.getMessage()); } }
代码已上传到码云
下载代码
git clone https://gitee.com/lisen0629/lisen_org.git
使用
进入克隆的位置,执行命令进入对应工程
cd quartztask