Quartz中使用到的cron

论坛 期权论坛 脚本     
匿名技术用户   2021-1-9 12:53   1038   0

最近做的云平台项目中定时任务的模块使用到了quartz,定时表达式需从数据库中读取并执行。

特意学习并记录一下。

表达式说明:

corn从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份

秒(Seconds)

0~59的整数

, - * /

四个字符

分(Minutes)

0~59的整数

, - * /

四个字符

小时(Hours)

0~23的整数

, - * /

四个字符

日期(DayofMonth)

1~31的整数(但是需要考虑你月的天数)

,- * ? / L W C

八个字符

月份(Month)

1~12的整数或者 JAN-DEC

, - * /

四个字符

星期(DayofWeek)

1~7的整数或者 SUN-SAT (1=SUN)

, - * ? / L C #

八个字符

年(可选,留空)(Year)

1970~2099

, - * /

四个字符

1)*:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。

2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。

3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次

4)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.

5),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。

6)L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。

7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。

举例:

* * * * * ? * -> 任务开始后,每秒都执行

1-5 * * * * ? * -> 任务开始后,每分钟的1-5秒执行

4/4 * * * * ? * -> 任务开始后过4秒开始执行,再每隔4秒执行

3,5,7,9 * * * * ? * -> 任务开始后下一分钟,指定秒数执行

10 * * * * ? * -> 任务开始的每个整数分钟第10秒执行

0 1/7 * * * ? -> 任务开始后过一分钟,每隔7分钟(即7的倍数的分钟数)的第0秒执行

5 1-3 * * * ? -> 任务开始的下一个指定分钟数内每分钟的第5秒执行

10 3,4,6 * * * ? * -> 任务开始指定分钟数的第10秒执行

3 0,3 * * * ? * -> 任务开始,每小时的第指定分钟指定秒钟执行

* 0,3 * * * ? * -> 任务开始,每小时的第指定分钟每一秒钟执行

0 7,9 3-4 * * ? * -> 任务开始后,指定小时数内指定分钟的第指定秒数执行

* 7,9 3-4 * * ? * -> 任务开始后,指定小时数内指定分钟的每一秒数执行

0 * 3-4 * * ? * -> 任务开始后,指定小时数内每一分钟的第指定秒数执行

0 0 2 * * ? * -> 任务开始后,每次指定小时数的第指定分钟数第指定秒钟数执行

* * 2 * * ? * -> 任务开始后,每次指定小时数的每一分钟数每一秒钟数执行

0 0 0 * * ? * -> 任务开始,每一日的指定小时指定分钟指定秒钟数执行

0 0 0 2-3 * ? * -> 任务开始后,每次指定日期数的指定小时指定分钟指定秒钟数执行

0 0 0 2/4 * ? * -> 任务开始,过指定天数(此处是2)时执行,往后每隔指定天数(此处是4)执行

0 0 0 L * ? * -> 任务开始后,每月最后一条执行

0 0 0 3,4,5,6 * ? * -> 任务开始后,每月中的指定日期数执行

0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务

0 15 10 ? * MON-FRI 2019 表示2019年每月的周一到周五每天上午10:15执行作业

0 15 10 ? * MON 2019 表示2019年每月的周一每天上午10:15执行作业

0 0 12 ? * WED * 表示每个星期三中午12点

0 15 10 ? * MON-FRI * 表示每年每月周一至周五的上午10:15触发

0 15 10 L 3 ? * 表示每年3月最后一天上午10:15触发

0 15 10 ? * 6L * 每月的最后一个星期五上午10:15触发

0 15 10 ? * 6#3 * 每月的第三个星期五上午10:15触发

时间点:

每年的这个时间点都会执行

指定年份(年分段/点)的时间点执行

注意:Spring Task是Quartz的弱版,quartz支持年份,而Spring Task不支持

代码如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>


CREATE TABLE `schedule_task` (
  `id` int(50) NOT NULL AUTO_INCREMENT COMMENT '数据自增Id',
  `cron` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


import com.schedule.my.schedule.schedule.utils.TransformationUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

@Configuration
@EnableScheduling
@Component
public class QuartzScheduleTask implements SchedulingConfigurer {

    @Mapper
    public interface CronMapper {
        @Select("select cron from schedule_task limit 1")
        String getCron();
    }

    @Autowired
    @SuppressWarnings("all")
    CronMapper cronMapper;

    /**
     * 执行定时任务。读取数据库中存储的cron表达式执行定时任务
     * @param scheduledTaskRegistrar
     * 添加的是TriggerTask,目的循环读取数据库中设置好的执行周期
     *
     * 这个解析cron的地方只支持六位!“Quartz”根本就不是“Quartz” (项目名字就是  Company_Quartz),实际是Spring Task。
     * Spring Task是Quartz的弱版,quartz支持年份,而Spring Task不支持。
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        Date date = new Date();
        Date time = new Date("2019/1/23 11:26:05");
        System.out.println("进入Quartz定时任务" + date);
        //1.添加任务内容(Runnable)
        scheduledTaskRegistrar.addTriggerTask(new Runnable() {
            @Override
            public void run() {
                System.out.println("Quartz执行定时任务: " + date);
            }
            //设置执行周期(Trigger)
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                /**
                 * 注:此处实为Spring Task,不支持年份,所以cron只有6个域
                 */
                //从数据库获取执行周期
                //String cron = cronMapper.getCron();
                String cron = "06 50 09 06 07 ?";
                //String cron = TransformationUtils.formatDateByPattern(time);
                System.out.println("====Cron:" + cron);
                //合法性校验.
                if (StringUtils.isEmpty(cron)) {
                    System.out.println("===Cron不可为空!");
                }
                int oCronLength = cron.length();
                cron.replaceAll(" ", "");
                if ((oCronLength - cron.length()) > 5) {
                    System.out.println("===Cron不支持(超过6位)!");
                }

                //返回执行周期(Date)
                return new CronTrigger(cron).nextExecutionTime(triggerContext);
            }
        });
    }
}


import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 转换工具
 */
public class TransformationUtils {

    /**
     * cron表达式支持7域,即支持年份
     */
    static final String Quartz_date_fromat = "ss mm HH dd MM ? yyyy";

    /**
     * cron表达式支持6域,即不支持年份
     */
    static final String TASK_DATE_FORMAT = "ss mm HH dd MM ?";

    /**
     * 日期转换成cron表达式
     * @param date
     * @return
     */
    public static String formatDateByPattern(Date date) {
        SimpleDateFormat format = new SimpleDateFormat(TASK_DATE_FORMAT);
        String formatTimeStr = null;
        if (date != null) {
            formatTimeStr = format.format(date);
        }
        return formatTimeStr;
    }

    /*public static void main(String[] args) {
//        System.out.println(formatDateByPattern(new Date(), DATE_FORMAT));
//        System.out.println(new Date("2018/7/6/ 9:47:06"));
    }*/
}

碰到一个cron的错误:

Support for specifying both a day-of-week AND a day-of-month parameter is not implemented
Cron表达式,原因是:天(月的多少号)和天(周几)不能同时都为*,当有一个为*时,另一个要是?,才行。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP