SpringBoot Quartz 总结(动态任务,Corn表达式)
程序员文章站
2022-07-14 10:19:17
...
我就直接粘贴代码了,后台包括了jar包的引入,任务管理类(可以动态的创建任务,删除任务,暂停任务等等),解决Quartz不能引入bean的问题,SpringBoot初始化启动Quartz等等. 关于创建Job类是写一个类实现Job接口并且实现Job中的execute方法.这个可以网上去搜我就不粘贴了.
前台涉及到了填写Corn表达式,由于Corn表达式即使相对于后台人员来说也是相当复杂的,更别说是运维人员,所以需求是Corn表达式的生成是用程序生成.我描述我实现的方法
1.Quartz后台总结
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
/**
* 任务管理类
*
* @author ZhuPengWei
* @date 2018/5/17 10:57
*/
@Component
@Slf4j
public class QuartzManager {
@Autowired
private Scheduler sched;
/**
* 任务组名
*/
private static String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME";
/**
* 触发器组名
*/
private static String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME";
/**
* 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
*
* @param jobName 任务名
* @param cls 任务
* @param time 任务触发时间( corn 表达式)
*/
public void addJob(String jobName, Class cls, String time, Object params) {
try {
JobDetail jobDetail = new JobDetailImpl(jobName, JOB_GROUP_NAME, cls);// 任务名,任务组,任务执行类
jobDetail.getJobDataMap().put("params", params);
// 触发器
CronTriggerImpl trigger = new CronTriggerImpl(jobName, TRIGGER_GROUP_NAME);// 触发器名,触发器组
//trigger.wait();
trigger.setCronExpression(time);// 触发器时间设定
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改一个任务的触发时间(使用默认的任务组名 , 触发器名 , 触发器组名)
*
* @param jobName 任务名称
* @param time 任务触发时间( corn 表达式)
*/
public void modifyJobTime(String jobName, String time) {
try {
CronTriggerImpl trigger = (CronTriggerImpl) sched.getTrigger(new TriggerKey(jobName, TRIGGER_GROUP_NAME));
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
JobDetail jobDetail = sched.getJobDetail(new JobKey(jobName, JOB_GROUP_NAME));
Class objJobClass = jobDetail.getJobClass();
removeJob(jobName);
addJob(jobName, objJobClass, time, jobDetail.getJobDataMap().get("params"));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改一个任务的触发以及触发内容(使用默认的任务组名 , 触发器名 , 触发器组名)
*
* @param jobName 任务名称
* @param jobValue 内容
* @param time 任务触发时间( corn 表达式)
*/
public void modifyJobTime(String jobName, String jobValue, String time) {
try {
CronTriggerImpl trigger = (CronTriggerImpl) sched.getTrigger(new TriggerKey(jobName, TRIGGER_GROUP_NAME));
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
JobDetail jobDetail = sched.getJobDetail(new JobKey(jobName, JOB_GROUP_NAME));
Class objJobClass = jobDetail.getJobClass();
removeJob(jobName);
addJob(jobName, objJobClass, time, jobValue);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 移除一个任务(使用默认的任务组名 , 触发器名 , 触发器组名)
*
* @param jobName 任务名称
*/
public void removeJob(String jobName) {
try {
sched.pauseTrigger(new TriggerKey(jobName, TRIGGER_GROUP_NAME));// 停止触发器
sched.unscheduleJob(new TriggerKey(jobName, TRIGGER_GROUP_NAME));// 移除触发器
sched.deleteJob(new JobKey(jobName, JOB_GROUP_NAME));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 移除多个任务(使用默认的任务组名 , 触发器名 , 触发器组名)
*
* @param jobNames 任务名称集合
*/
public void removeJobs(List<String> jobNames) {
for (String jobName : jobNames) {
removeJob(jobName);
log.info("移除工作任务:{}", jobName);
}
}
/**
* 启动所有定时任务
*/
public void startJobs() {
try {
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* 解决quartz的job中使用autowired注解注入的对象为空,
*
* @author ZhuPengWei
* @date 2018/5/22 15:52
*/
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
/**
* 解决quartz的job中使用autowired注解注入的对象为空,
*
* @author ZhuPengWei
* @date 2018/5/22 15:52
*/
@Configuration
public class JobFactoryConfig {
@Bean
public JobFactory jobFactory() {
return new JobFactory();
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setJobFactory(jobFactory());
schedulerFactoryBean.setOverwriteExistingJobs(true);
return schedulerFactoryBean;
}
}
/**
* CommandLineRunner 接口的 Component 会在所有 SpringBeans都初始化之后
* SpringApplication.run()之前执行
* 初始化定时任务
*
* @author ZhuPengWei
* @date 2018/5/19 17:05
*/
@Component
@Slf4j
public class TimedTaskWhenApplicationStartUp implements CommandLineRunner {
@Autowired
private MessageActionMasterJpaRepository messageActionMasterJpaRepository;
@Autowired
private TimedTaskSendService timedTaskSendService;
@Override
public void run(String... args) {
try {
// 查询quartz表达式不是null并且发送消息的数据
List<MessageActionMaster> byQuartzExpressionIsNotNullAndIsSendMessageTrue = messageActionMasterJpaRepository.findByQuartzExpressionIsNotNullAndIsSendMessageTrue();
// 批量新增任务
timedTaskSendService.batchAddTask(byQuartzExpressionIsNotNullAndIsSendMessageTrue);
log.info("-------------------定时任务初始化完毕-------------------");
} catch (Exception e) {
log.error("启动时候定时任务出现异常,{},{}", e, e.fillInStackTrace());
}
}
}
2.前端总结
对于一个后台人员来说 手动用Jquery实现页面生成Corn表达式是十分困难的,我在百度和谷歌上搜索了大量的前端Corn插件 ,要不界面是在太丑,无法集成到后台的项目中,要不生成的Corn表达式居然是错误的.是在是相当的为难.
所幸运的是我在github上找到了一个开源项目 并且集成到了我的后台项目之中.
我首先粘贴下这个项目的地址:
https://embed.plnkr.co/LCNjHr1s1rlr1FSXesMg/
我实现的效果图如下:
说明和描述的功能是我自己加入的 我粘贴一下描述的具体代码 ,当然由于时间的问题只是初步实现了
/**
* 解析Cron 翻译成中文
*
* @author ZhuPengWei
* @date 2018/5/18 15:26
*/
public class CronExpParserUtils {
/**
* Cron 表达式->中文描述
*
* @param corn core表达式
* @return 中文描述
*/
public static String cronConvertToChinese(String corn) {
StringBuilder result = new StringBuilder();
String[] cornArray = corn.split(" ");
// 解析cornArray
if (cornArray[1].equals(cornArray[2]) && cornArray[2].equals(cornArray[3]) && cornArray[3].equals(cornArray[4]) && cornArray[1].equals("*")) {
result = everyMinutes(result);
} else if (!cornArray[1].equals(cornArray[2]) && cornArray[2].equals(cornArray[3]) && cornArray[3].equals(cornArray[4]) && cornArray[2].equals("*")) {
result = everyHour(result, cornArray);
} else if (!cornArray[2].equals(cornArray[3]) && cornArray[3].equals(cornArray[4]) && cornArray[3].equals("*")) {
result = everDay(result, cornArray);
} else if (!cornArray[3].equals(cornArray[4]) && cornArray[4].equals("*") && cornArray[5].equals("?")) {
result = everyMonthDay(result, cornArray);
} else if (!cornArray[5].equals("?") && cornArray[3].equals("?")) {
result = everyMonthWeek(result, cornArray);
} else if (!cornArray[1].equals("*") && !cornArray[2].equals("*") && !cornArray[3].equals("*") && !cornArray[4].equals("*") && cornArray[5].equals("?")) {
result = everyYear(result, cornArray);
} else {
result.append("暂时不能解析");
}
return result.toString();
}
/**
* 每分钟 执行
*
* @return 结果
*/
private static StringBuilder everyMinutes(StringBuilder stringBuilder) {
return stringBuilder.append("每分钟发送消息");
}
/**
* 每小时每分钟
*
* @param stringBuilder 字符串拼接对象
* @param cornArray core字符串数组
* @return 结果
*/
private static StringBuilder everyHour(StringBuilder stringBuilder, String[] cornArray) {
if (cornArray[1].equals("0")) {
return stringBuilder.append("每小时发送消息");
}
return stringBuilder.append("每小时的第").append(cornArray[1]).append("分钟发送消息");
}
/**
* 每天每小时
*
* @param stringBuilder 字符串拼接对象
* @param cornArray core字符串数组
* @return 结果
*/
private static StringBuilder everDay(StringBuilder stringBuilder, String[] cornArray) {
if (cornArray[1].equals("*")) {
return stringBuilder.append("每天的第").append(cornArray[2]).append("小时么每过一分钟发送消息");
}
return stringBuilder.append("每天的").append(cornArray[2]).append("时").append(cornArray[1]).append("分发送消息");
}
/**
* 每月第几天
*
* @param stringBuilder 字符串拼接对象
* @param cornArray core字符串数组
* @return 结果
*/
private static StringBuilder everyMonthDay(StringBuilder stringBuilder, String[] cornArray) {
if (cornArray[1].equals("*") && cornArray[2].equals("*")) {
return everyMinutes(stringBuilder);
}
if (cornArray[2].equals("*")) {
return everyHour(stringBuilder, cornArray);
}
if (cornArray[1].equals("*")) {
return everDay(stringBuilder, cornArray);
}
return stringBuilder.append("每月的第").append(cornArray[3]).append("天的").append(cornArray[2]).append("时").append(cornArray[1]).append("分发送消息");
}
/**
* 星期
*
* @param stringBuilder 字符串拼接对象
* @param cornArray core字符串数组
* @return 结果
*/
private static StringBuilder everyMonthWeek(StringBuilder stringBuilder, String[] cornArray) {
if (cornArray[1].equals("*") && cornArray[2].equals("*")) {
return stringBuilder.append("每").append(cornArray[5]).append("每分钟发送消息");
}
if (cornArray[2].equals("*")) {
return stringBuilder.append("每").append(cornArray[5]).append("的每小时的第").append(cornArray[1]).append("分发送消息");
}
if (cornArray[1].equals("*")) {
return stringBuilder.append("每").append(cornArray[5]).append("的第").append(cornArray[2]).append("小时的每一分钟发送消息");
}
return stringBuilder.append("每").append(cornArray[5]).append("的第").append(cornArray[2]).append("时").append(cornArray[1]).append("分发送消息");
}
/**
* 每年
*
* @param stringBuilder 字符串拼接对象
* @param cornArray core字符串数组
* @return 结果
*/
private static StringBuilder everyYear(StringBuilder stringBuilder, String[] cornArray) {
return stringBuilder.append("每年").append(cornArray[4]).append("月").append(cornArray[3]).append("号").append(cornArray[2]).append("点").append(cornArray[1]).append("发送消息");
}
}
因为每一个人的前端代码都不一样所以我就不粘贴前端代码了
下一篇: Quartz使用教程