1.想法
quartz框架采用的cron表达式必须是每天或者每几小时按照的是整体时间走的而非已当前时间做开始时间往后执行的,
例如40分钟未支付取消订单或30分钟无回应判断其离线等等这种场景下如果想用quartz定时调度框架成了一个难题.
虽然cron本身并不支持指定开始时间往后的某个规律执行但是我们可以换个角度去思考这个问题.
我们首先设置一下它下次执行的时间等他再执行试我们则更改一下他下次执行的时间.话不多说上代码
2.POM导入
由于我们的工具类使用的hutool工具类,我这里是导入的hutool的全部工具类,大家可以根据需求自行导入
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.3</version>
</dependency>
3.corn工具类
用我们编写的工具类生成你要执行的cron表达式 还可以再进行抽取公共地方再进行化简,我这里就不做了有有需要的自己化简抽取公共方法出来即可
public class CronUtilZ {
/**
*构建Cron表达式 举例: 当前时间开始每3天执行一次需传参 new Date(),3,1
* 当前时间开始每5个月执行一次需传参 new Date(),5,2
* @param date 开始时间
* @param count 数量
* @param type 类型:0->小时 type 1->天 type 2->周 type 3->月 type 4->季度 type 5->年 6->分钟
* @return String
*/
public static String createCronExpression(Date date,Integer count,Integer type){
if (count==0){
throw new RuntimeException("错误数量填写");
}
StringBuffer cronExp = new StringBuffer("");
//如果为小时
if (type ==0){
//小时
int hour = DateUtil.hour(date,true);
//分钟
int minute = DateUtil.minute(date);
//秒
int second = DateUtil.second(date);
//让小时部分去加一下几个小时以后执行
hour=hour+count;
if (hour>24){
//大于24考虑大于多少个24
int b=hour/24;
//偏移大于几个24就偏移几天
DateTime dateTime = DateUtil.offsetDay(date, b);
//然后小时去剪去大于的24
hour=hour-b*24;
//获取日
int day = DateUtil.dayOfMonth(dateTime);
//获取月
int month = DateUtil.month(dateTime);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份
int year = DateUtil.year(dateTime);
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
}else {
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append("* ");
cronExp.append("* ");
cronExp.append("? ");
cronExp.append("*");
return cronExp.toString();
}
}
//如果为天
if (type ==1){
//小时
int hour = DateUtil.hour(date,true);
//分钟
int minute = DateUtil.minute(date);
//秒
int second = DateUtil.second(date);
//偏移count天
DateTime dateTime = DateUtil.offsetDay(new Date(), count);
//获取日
int day = DateUtil.dayOfMonth(dateTime);
//获取月
int month = DateUtil.month(dateTime);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份
int year = DateUtil.year(dateTime);
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
return cronExp.toString();
}
//如果为周
if (type ==2){
//小时
int hour = DateUtil.hour(date,true);
//分钟
int minute = DateUtil.minute(date);
//秒
int second = DateUtil.second(date);
//偏移个count*7天
DateTime dateTime = DateUtil.offsetDay(new Date(), count*7);
//获取日
int day = DateUtil.dayOfMonth(dateTime);
//获取月
int month = DateUtil.month(dateTime);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份
int year = DateUtil.year(dateTime);
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
return cronExp.toString();
}
//如果为月
if (type ==3){
//小时
int hour = DateUtil.hour(date,true);
//分钟
int minute = DateUtil.minute(date);
//秒
int second = DateUtil.second(date);
//偏移个count*30天
DateTime dateTime = DateUtil.offsetDay(new Date(), count*30);
//获取日
int day = DateUtil.dayOfMonth(dateTime);
//获取月
int month = DateUtil.month(dateTime);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份
int year = DateUtil.year(dateTime);
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
return cronExp.toString();
}
//如果为季度
if (type ==4){
//小时
int hour = DateUtil.hour(date,true);
//分钟
int minute = DateUtil.minute(date);
//秒
int second = DateUtil.second(date);
//偏移个count*90天
DateTime dateTime = DateUtil.offsetDay(new Date(), count*90);
//获取日
int day = DateUtil.dayOfMonth(dateTime);
//获取月
int month = DateUtil.month(dateTime);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份
int year = DateUtil.year(dateTime);
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
return cronExp.toString();
}
//如果为年
if (type ==5){
//小时
int hour = DateUtil.hour(date,true);
//分钟
int minute = DateUtil.minute(date);
//秒
int second = DateUtil.second(date);
//获取日
int day = DateUtil.dayOfMonth(date);
//获取月
int month = DateUtil.month(date);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份直接+count就行
int year = DateUtil.year(date)+count;
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
return cronExp.toString();
}
//如果为分钟
if (type ==6){
//小时
int hour = DateUtil.hour(date,true);
//分钟
int minute = DateUtil.minute(date);
//秒
int second = DateUtil.second(date);
//让小时部分去加一下几个小时以后执行
minute=minute+count;
if (minute>60){
//大于24考虑大于多少个24
int b=minute/60;
minute=minute-b*60;
if (hour+b>24){
int c=hour/24;
//然后小时去剪去大于的24
hour=hour-c*24;
//偏移大于几个24就偏移几天
date = DateUtil.offsetDay(date, c);
//获取日
int day = DateUtil.dayOfMonth(date);
//获取月
int month = DateUtil.month(date);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份
int year = DateUtil.year(date);
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
}else {
//获取日
int day = DateUtil.dayOfMonth(date);
//获取月
int month = DateUtil.month(date);
//月份需加1因为 糊涂工具类是从0开始算的
month=month+1;
//获取年份
int year = DateUtil.year(date);
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append(day).append(" ");
cronExp.append(month).append(" ");
cronExp.append("? ");
cronExp.append(year).append("-").append(year);
}
}else {
cronExp.append(second).append(" ");
cronExp.append(minute).append(" ");
cronExp.append(hour).append(" ");
cronExp.append("* ");
cronExp.append("* ");
cronExp.append("? ");
cronExp.append("*");
return cronExp.toString();
}
}
return null;
}
}
4.使用方法
1.首先在你开始quartz调度之前用工具类生成下一次开始的cron表达式例如
/**
* 假装这是你的controller层的开始方法
* @param date
* @param count
* @param type
*/
public void start(Date date,Integer count, Integer type) {
//生成对应的cron表达式然后传递给你的Quartz的开始调度的方法
//生成的cron表达式对应的意思是 当前时间开始3个小时后执行一次
String cronExpression = CronUtilZ.createCronExpression(new Date(), 3, 0);
}
2.到生成的表达式后生成下一次的表达式更新一次例如
@Component
public class ReplenishOrderJob implements Job {
@Override
public void execute(JobExecutionContext context) {
// 获取定时任务名(定时任务时间id)
String timingDateId = context.getJobDetail().getKey().getName();
// 获取定时任务组名(定时任务id)
String timingId = context.getJobDetail().getKey().getGroup();
}
//开始执行定时任务了
/**
这里都是你的任务执行的逻辑
*/
//获取当前时间下次的3小时后的执行时间
String corn = CronUtilZ.createCronExpression(new Date(), 3, 0)
//更新你的cron表达式即可
xxx.upd(timingDateId,corn)
}
5.总结
总结下来其实就是开始的时候生成表达式,然后等执行的时候再生成新的下次表达式更新即可