在电商项目中我们比较常见的问题就是那些未付款的订单,我们需要在一定的时间以后自动关闭交易,如果这个任务是通过人工来完成,工作量是相当可观的,所以我们采用一个定时任务,自动扫面那些订单,然后自动关闭!
首先引入依赖
<!--核心包-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
创建工具类
package com.kaying.luck.utils.quartz;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;
/**
* quartz工具类
*
* @author yt
*/
@Component
public class QuartzUtils {
private static final Logger logger = LoggerFactory.getLogger(QuartzUtils.class);
@Autowired
private Scheduler scheduler;
private static final String JOB_GROUP_NAME = "DEFAULT_JOB_GROUP_NAME";
private static final String TRIGGER_GROUP_NAME = "DEFAULT_TRIGGER_GROUP_NAME";
/**
* addSimpleJob简略版无额外参数
*
* @param jobName 任务名称
* @param startTime 执行时间
* @param jobClass 任务类
* @return
*/
public boolean addSimpleJob(String jobName, Date startTime, Class<? extends Job> jobClass) {
return addSimpleJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME, startTime, null, jobClass);
}
/**
* addSimpleJob简略版有额外参数
*
* @param jobName 任务名称
* @param startTime 执行时间
* @param extraParam 额外参数
* @param jobClass 任务类
* @return
*/
public boolean addSimpleJob(String jobName, Date startTime, Map<String, Object> extraParam, Class<? extends Job> jobClass) {
return addSimpleJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME, startTime, extraParam, jobClass);
}
/**
* addCronJob简略版无额外参数
*
* @param jobName
* @param cronExpression
* @param jobClass
* @return
*/
public boolean addCronJob(String jobName, String cronExpression, Class<? extends Job> jobClass) {
return addCronJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME, cronExpression, null, jobClass);
}
/**
* addCronJob简略版有额外参数
*
* @param jobName
* @param cronExpression
* @param extraParam
* @param jobClass
* @return
*/
public boolean addCronJob(String jobName, String cronExpression, Map<String, Object> extraParam, Class<? extends Job> jobClass) {
return addCronJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME, cronExpression, extraParam, jobClass);
}
/**
* modifyCronJobTime简略版
*
* @param triggerName
* @param cronExpression
* @return
*/
public boolean modifyCronJobTime(String triggerName, String cronExpression) {
return modifyCronJobTime(triggerName, TRIGGER_GROUP_NAME, cronExpression);
}
/**
* removeJob简略版
*
* @param jobName
* @return
*/
public boolean removeJob(String jobName) {
return removeJob(jobName, JOB_GROUP_NAME, jobName, TRIGGER_GROUP_NAME);
}
/**
* 添加简单定时任务
*
* @param jobName
* @param jobGroup
* @param triggerName
* @param triggerGroup
* @param startTime
* @param extraParam
* @param jobClass
* @return
*/
public boolean addSimpleJob(String jobName, String jobGroup, String triggerName, String triggerGroup, Date startTime, Map<String, Object> extraParam, Class<? extends Job> jobClass) {
try {
JobDetail jobDetail = JobBuilder
.newJob(jobClass)
.withIdentity(jobName, jobGroup)
.build();
if (extraParam != null) {
jobDetail.getJobDataMap().putAll(extraParam);
}
SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder
.newTrigger()
.withIdentity(triggerName, triggerGroup)
.startAt(startTime)
.build();
scheduler.scheduleJob(jobDetail, simpleTrigger);
} catch (SchedulerException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 添加cron定时任务
*
* @param jobName
* @param jobGroup
* @param triggerName
* @param triggerGroup
* @param cronExpression
* @param extraParam
* @param jobClass
* @return
*/
public boolean addCronJob(String jobName, String jobGroup, String triggerName, String triggerGroup, String cronExpression, Map<String, Object> extraParam, Class<? extends Job> jobClass) {
try {
JobDetail jobDetail = JobBuilder
.newJob(jobClass)
.withIdentity(jobName, jobGroup)
.build();
if (extraParam != null) {
jobDetail.getJobDataMap().putAll(extraParam);
}
CronTrigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity(triggerName, triggerGroup)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
scheduler.scheduleJob(jobDetail, cronTrigger);
} catch (SchedulerException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 修改cron任务的时间的触发时间
*
* @param triggerName
* @param triggerGroup
* @param cronExpression
* @return
*/
public boolean modifyCronJobTime(String triggerName, String triggerGroup, String cronExpression) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (oldTrigger == null) {
logger.error("未找到相关任务");
return false;
}
String oldCronExpression = oldTrigger.getCronExpression();
if (!oldCronExpression.equalsIgnoreCase(cronExpression)) {
CronTrigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity(triggerName, triggerGroup)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
scheduler.rescheduleJob(triggerKey, cronTrigger);
}
} catch (SchedulerException e) {
logger.error("修改cron定时任务时间失败", e);
}
return true;
}
/**
* 删除指定定时任务
*
* @param jobName
* @param jobGroup
* @param triggerName
* @param triggerGroup
* @return
*/
public boolean removeJob(String jobName, String jobGroup, String triggerName, String triggerGroup) {
try {
scheduler.unscheduleJob(TriggerKey.triggerKey(triggerName, triggerGroup));
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup));
} catch (SchedulerException e) {
logger.error("删除定时任务失败", e);
return false;
}
return true;
}
}
枚举
package com.kaying.luck.utils.quartz.enums;
/**
* 任务名称前缀枚举
*
* @author yt
*/
public enum QuartzJobNamePrefixEnum {
/**
* 订单过期 by 订单编号
*/
ORDER_DEADLINE_BY_ORDER_NO;
public String getPrefix() {
return "{" + this.name() + "}_";
}
}
时间工具类
package com.kaying.luck.utils.date;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/**
* 日期工具类
*
* @author yt
*/
public class DateUtils {
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
public static String YYYYMMDD = "yyyyMMdd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
/**
* 获取当前unix时间戳
*
* @return 当前unix时间戳
*/
public static long getCurrentUnixTimestamp() {
return System.currentTimeMillis() / 1000L;
}
public static String formatDateToStr(Date date) {
return DateFormatUtils.format(date, YYYY_MM_DD_HH_MM_SS);
}
public static String formatDateToStr(Date date, String format) {
return DateFormatUtils.format(date, format);
}
/**
* 获取 年
*/
public static Integer getYear(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.YEAR);
}
/**
* 获取 月
*/
public static Integer getMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.MONTH) + 1;
}
/**
* 获取 日
*/
public static Integer getDay(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.DAY_OF_MONTH);
}
/**
* 获取 小时
*/
public static Integer getHour(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.get(Calendar.HOUR_OF_DAY);
}
/**
* 获取开始时间 天
*/
public static Date getDayStart(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
/**
* 获取结束时间 天
*/
public static Date getDayEnd(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
return cal.getTime();
}
// 获取昨天的开始时间
public static Date getBeginDayOfYesterday(Date date) {
Calendar cal = new GregorianCalendar();
cal.setTime(getDayStart(date));
cal.add(Calendar.DAY_OF_MONTH, -1);
return cal.getTime();
}
// 获取昨天的结束时间
public static Date getEndDayOfYesterDay(Date date) {
Calendar cal = new GregorianCalendar();
cal.setTime(getDayEnd(date));
cal.add(Calendar.DAY_OF_MONTH, -1);
return cal.getTime();
}
/**
* 获取开始时间 周
*/
public static Date getWeekStart(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
if (dayOfWeek == 1) {
dayOfWeek += 7;
}
cal.add(Calendar.DATE, 2 - dayOfWeek);
return getDayStart(cal.getTime());
}
/**
* 获取结束时间 周
*/
public static Date getWeekEnd(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(getWeekStart(date));
cal.add(Calendar.DAY_OF_WEEK, 6);
return getDayEnd(cal.getTime());
}
/**
* 根据输入的字符串来获取当月的开始时间
* @param date (“2022-11-10”)
* @return
*/
public static Date getBeginDayOfMonth(String date) {
LocalDate date2;
if (null==date){
date2=LocalDate.now();
}else {
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
date2=LocalDate.parse(date, fmt);
}
Calendar calendar = Calendar.getInstance();
calendar.set(date2.getYear(), date2.getMonthValue()-1, 1);
return getDayStartTime(calendar.getTime());
}
/**
* 根据输入的字符串来获取当月的结束时间
* @param date (“2022-11-10”)
* @return
*/
public static Date getEndDayOfMonth(String date) {
LocalDate date2;
if (null==date){
date2=LocalDate.now();
}else {
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
date2=LocalDate.parse(date, fmt);
}
Calendar calendar = Calendar.getInstance();
calendar.set(date2.getYear(), date2.getMonthValue()-1, 1);
int day = calendar.getActualMaximum(5);
calendar.set(date2.getYear(), date2.getMonthValue()-1, day);
return getDayEndTime(calendar.getTime());
}
//获取某个日期的开始时间
public static Timestamp getDayStartTime(Date d) {
Calendar calendar = Calendar.getInstance();
if(null != d) calendar.setTime(d);
calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
return new Timestamp(calendar.getTimeInMillis());
}
//获取某个日期的结束时间
public static Timestamp getDayEndTime(Date d) {
Calendar calendar = Calendar.getInstance();
if(null != d) calendar.setTime(d);
calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
calendar.set(Calendar.MILLISECOND, 999);
return new Timestamp(calendar.getTimeInMillis());
}
/**
* 日期路径 即年/月/日 如2018/08/08
*/
public static String datePath() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
/**
* date1 大于 date2
*
* @param date1
* @param date2
* @return
*/
public static boolean greaterThan(Date date1, Date date2) {
if (date1.compareTo(date2) > 0) {
return true;
}
return false;
}
/**
* date1 小于 date2
*
* @param date1
* @param date2
* @return
*/
public static boolean lessThan(Date date1, Date date2) {
if (date1.compareTo(date2) < 0) {
return true;
}
return false;
}
/**
* date1 等于 date2
*
* @param date1
* @param date2
* @return
*/
public static boolean equal(Date date1, Date date2) {
if (date1.compareTo(date2) == 0) {
return true;
}
return false;
}
/**
* date1 大于等于 date2
*
* @param date1
* @param date2
* @return
*/
public static boolean greaterThanOrEqual(Date date1, Date date2) {
if (date1.compareTo(date2) < 0) {
return false;
}
return true;
}
/**
* date1 小于等于 date2
*
* @param date1
* @param date2
* @return
*/
public static boolean lessThanOrEqual(Date date1, Date date2) {
if (date1.compareTo(date2) > 0) {
return false;
}
return true;
}
/**
* 计算 差 秒
*
* @param date1
* @param date2
* @return
*/
public static int calcSecond(Date date1, Date date2) {
long a = date1.getTime();
long b = date2.getTime();
int second = (int) ((a - b) / 1000);
return second;
}
/**
* 计算 差 月
*
* @param date1
* @param date2
* @return
*/
public static int calcMonth(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
int year1 = cal1.get(Calendar.YEAR);
int year2 = cal2.get(Calendar.YEAR);
int month1 = cal1.get(Calendar.MONTH);
int month2 = cal2.get(Calendar.MONTH);
int month = (year1 - year2) * 12 + (month1 - month2);
return month;
}
/**
* 计算 差 周
*
* @param date1
* @param date2
* @return
*/
public static int calcWeek(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
int dayOfWeek = cal1.get(Calendar.DAY_OF_WEEK);
dayOfWeek = dayOfWeek - 1;
if (dayOfWeek == 0) {
dayOfWeek = 7;
}
int day = calcDay(date1, date2);
int week = day / 7;
int i;
if (day > 0) {
i = (day % 7 + dayOfWeek > 7) ? 1 : 0;
} else {
i = (dayOfWeek + week % 7 < 1) ? -1 : 0;
}
week = week + i;
return week;
}
/**
* 计算 差 天
*
* @param date1
* @param date2
* @return
*/
public static int calcDay(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
int day1 = cal1.get(Calendar.DAY_OF_YEAR);
int day2 = cal2.get(Calendar.DAY_OF_YEAR);
int year1 = cal1.get(Calendar.YEAR);
int year2 = cal2.get(Calendar.YEAR);
if (year1 != year2) {
//同一年
int timeDistance = 0;
for (int i = year2; i < year1; i++) {
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) {
//闰年
timeDistance += 366;
} else {
//不是闰年
timeDistance += 365;
}
}
return timeDistance + (day1 - day2);
} else {
//不同年
return day1 - day2;
}
}
/**
* 加减 秒
*
* @param date
* @param second
* @return
*/
public static Date addSecond(Date date, int second) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) + second);
return cal.getTime();
}
/**
* 加减 天
*
* @param date
* @param day
* @return
*/
public static Date addDay(Date date, int day) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.DAY_OF_MONTH, day);
return cal.getTime();
}
/**
* 加减 周
*
* @param date
* @param week
* @return
*/
public static Date addWeek(Date date, int week) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.WEEK_OF_MONTH, week);
return cal.getTime();
}
/**
* 加减 月
*
* @param date
* @param month
* @return
*/
public static Date addMonth(Date date, int month) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.MONTH, month);
return cal.getTime();
}
public static String yearMonthDayString(Date date) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date);
//取天
int day = cal1.get(Calendar.DAY_OF_MONTH);
//取月,加一是因为这个是0-11,从零开始的
int month = cal1.get(Calendar.MONTH) + 1;
//取年
int year = cal1.get(Calendar.YEAR);
return year + "-" + month + "-" + day;
}
}
然后在项目中使用工具类创建任务,我这里是将订单号传到任务里
// 过期时间
Date deadline = null;
Integer orderExpire = activity.getOrderExpire();
if (orderExpire != -1 && orderExpire > 0) {
deadline = DateUtils.addSecond(createdAt, orderExpire);
}
// 过期
if (deadline != null) {
Map<String, Object> extraParam = new HashMap<>();
extraParam.put("orderNo", orderNo);
quartzUtils.addSimpleJob(QuartzJobNamePrefixEnum.ORDER_DEADLINE_BY_ORDER_NO + orderNo, DateUtils.addSecond(deadline, -3), extraParam, OrderDeadlineJob.class);
}
创建任务类通过自己设置的时间自动执行逻辑,我这里是将订单设置为未支付过期
package com.kaying.luck.timejob;
import com.kaying.luck.dao.mall.sbpay.SbPayOrderDao;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 订单过期任务类
*
* @author yt
*/
@Component
public class OrderDeadlineJob implements Job {
@Autowired
private SbPayOrderDao sbPayOrderDao;
@Override
public void execute(JobExecutionContext jobExecutionContext) {
JobDetail jobDetail = jobExecutionContext.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
String orderNo = (String) jobDataMap.get("orderNo");
if (StringUtils.isNotBlank(orderNo)) {
try {
sbPayOrderDao.orderDeadline(orderNo);
} catch (Exception ignored) {
}
}
}
}
创建订单,5分钟之后自动将订单过期并返回商品数量