欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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/

我实现的效果图如下:

SpringBoot Quartz 总结(动态任务,Corn表达式)

SpringBoot Quartz 总结(动态任务,Corn表达式)

SpringBoot Quartz 总结(动态任务,Corn表达式)

说明和描述的功能是我自己加入的 我粘贴一下描述的具体代码 ,当然由于时间的问题只是初步实现了


/**
 * 解析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