业务场景,以下单为例,如果订单在24小时内未付款,则定时器执行,修改订单未失效
1.ProjectConfig 启动时开启定时功能
public void onStart() {
//开启
QuartzManager qm = new QuartzManager();
qm.initJob();
}
// 系统关闭之前回调
@Override
public void onStop() {
//项目暂停时 关闭
QuartzManager qm = new QuartzManager();
qm.shutdown();
}
2.QuartzManager 工具类
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.List;
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
/**
* @Author: Timelk
* @Date: 2021-08-10 9:33
*/
public class QuartzManager {
private Logger log = LogManager.getLogger(QuartzManager.class);
private Scheduler scheduler = null;
public QuartzManager() {
try {
scheduler = new StdSchedulerFactory().getScheduler();
//log.info("初始化调度器 ");
} catch (SchedulerException ex) {
log.error("初始化调度器=> [失败]:" + ex.getLocalizedMessage());
}
}
//初始化启动任务 这里订单在创建时,会在表中创建一条执行失效的记录,但项目如果关闭,定时就会暂停,每次项目启动前需要在这执行定时任务
public void initJob() {
List<BusOrderTimeout> jobs = BusOrderTimeout.dao.template("orderTimeout.find", Kv.by("is_enabled", "2")).find();
for (BusOrderTimeout job : jobs) {
if ("2".equals(job.getStr("is_enabled"))) {
String className = job.getStr("clazz");
String name = job.getStr("name");
String group = job.getStr("group");
String cronExpression = job.getStr("cron_expression");
this.addJob(name, group, className, cronExpression);
}
}
this.start();
}
//添加任务
public void addJob(String name, String group, String className, String cronExpression) {
Class<? extends Job> jobClazz = null;
try {
jobClazz = Class.forName(className).asSubclass(Job.class);
// 构造任务
JobDetail job = newJob(jobClazz).withIdentity(name, group).build();
//定时器中存入id
job.getJobDataMap().put("id", name);
// 构造任务触发器
Trigger trg = newTrigger().withIdentity(name, group).withSchedule(cronSchedule(cronExpression)).build();
// 将作业添加到调度器
scheduler.scheduleJob(job, trg);
log.info("创建作业=> [作业名称:" + name + " 作业组:" + group + "id: " + name + "] ");
} catch (SchedulerException | ClassNotFoundException e) {
e.printStackTrace();
log.error("创建作业=> [作业名称:" + name + " 作业组:" + group + "id: " + name + "]=> [失败]");
}
}
//移除任务
public void removeJob(String name, String group) {
try {
TriggerKey tk = TriggerKey.triggerKey(name, group);
scheduler.pauseTrigger(tk);// 停止触发器
scheduler.unscheduleJob(tk);// 移除触发器
JobKey jobKey = JobKey.jobKey(name, group);
scheduler.deleteJob(jobKey);// 删除作业
log.info("删除作业=> [作业名称:" + name + " 作业组:" + group + "] ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("删除作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
}
}
public void start() {
try {
scheduler.start();
//log.info("启动调度器 ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("启动调度器=> [失败]");
}
}
public void shutdown() {
try {
scheduler.shutdown();
//log.info("停止调度器 ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("停止调度器=> [失败]");
}
}
}
3.下单&取消订单
public void create() {
Db.tx(() -> {
try {
String format = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String numbers = RandomUtil.randomNumbers(5);
String liushui = format + numbers;
BusOrder target = new BusOrder();
target.setId(UuidKit.getUUIDNoMinus());
target.setCreateTime(DateUtil.now());
target.setOrderId(liushui);
target.setPayMethod(get("pay_method"));
target.setUserId(user.getId());
target.setNote(get("note"));
target.setActualPrice(get("actual_price"));
target.save();
//加入调度 动态增加一个定时器
OrderJob.saveOrderJob(target, "订单失效定时创建");
rs("下单成功")
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
});
}
/**
* 取消订单
*/
public void delete() {
String id = get("id");
Db.tx(() -> {
try {
BusOrder target = BusOrder.dao.template("order.find",
Kv.by("id", id))
.findFirst();
if (target != null) {
target.setCancelTime(DateUtil.now());
target.setState("0");//改失效
target.update();
//删除调度
OrderJob.deleteOrderJob(target);
}
rs(CodeKit.DELETE_SUCCESS_MESSAGE);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
});
}
4. 定时器 相关逻辑
package com.huayueye.t.job.task;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.huayueye.b.model.BusOrder;
import com.huayueye.b.model.BusOrderTimeout;
import com.huayueye.t.job.QuartzManager;
import com.jfinal.kit.Kv;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
/**
* @Author: 订单超时改失效
* @Date: 2021-08-10 9:35
*/
public class OrderJob implements Job {
@Override //定时执行进入此方法
public void execute(JobExecutionContext context) throws JobExecutionException {
String id = context.getMergedJobDataMap().getString("id");
BusOrder order = BusOrder.dao.template("order.find", Kv.by("id", id)).findFirst();
try {
if (order.getState().equals("1")) {
order.setState("0");
order.setCancelTime(DateUtil.now());
order.update();
deleteOrderJob(order);
}
} catch (Exception e) {
e.printStackTrace();
}
/*System.out.println("订单超时查询");
List<BusOrder> list = BusOrder.dao.template("order.find", Kv.by("state", "1")).find();
List<BusOrder> noOrders = new ArrayList<>();
if (list.size()>0){
for (BusOrder order:list){
String createTime = order.getCreateTime();
Date create_date = Convert.toDate(createTime);
Date now = Convert.toDate(DateUtil.now());
long l = DateUtil.betweenDay(create_date, now, false);
//超过一天
if (l>0){
order.setState("0");
order.setCancelTime(DateUtil.now());
noOrders.add(order);
}
}
}
Db.batchUpdate(noOrders, noOrders.size());*/
}
//新建定时 订单失效 开启
public static void saveOrderJob(BusOrder order, String group) {
BusOrderTimeout orderTimeout = new BusOrderTimeout();
orderTimeout.setCreateTime(DateUtil.now());
orderTimeout.setName(order.getId());
orderTimeout.setGroup(group);
orderTimeout.setClazz("com.huayueye.t.job.task.OrderJob");
//计算24小时的失效时间
String createTime = order.getCreateTime();
Date create_date = Convert.toDate(createTime);
DateTime stime = DateUtil.offsetDay(create_date, 1);
String formatDate = DateUtil.format(stime, "yyyy-MM-dd HH:mm:ss");
//计算cron
orderTimeout.setCronExpression(onlyOnce(formatDate));
orderTimeout.save();
QuartzManager qm = new QuartzManager();
qm.addJob(orderTimeout.getName(), orderTimeout.getGroup(), orderTimeout.getClazz(), orderTimeout.getCronExpression());
}
//订单失效关闭
public static void deleteOrderJob(BusOrder target) {
BusOrderTimeout orderTimeout = BusOrderTimeout.dao.template("orderTimeout.find", Kv.by("name", target.getId()).set("is_enabled", "2")).findFirst();
if (orderTimeout != null) {
QuartzManager qm = new QuartzManager();
qm.removeJob(orderTimeout.getName(), orderTimeout.getGroup());//定时删除
orderTimeout.setIsEnabled("1");//关闭
orderTimeout.update();
}
}
/**
* 仅一次
*
* @param dateStr 2022-03-31 09:51:05
* @return
*/
public static String onlyOnce(String dateStr) {
LocalDateTime time = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
String cronStr = time.format(DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy"));
return cronStr;
}
}
5.转cron 代码
链接: 转cron 代码
6.表结构
CREATE TABLE `bus_order_timeout` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT 'task name',
`group` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '分组',
`clazz` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT 'class name',
`cron_expression` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT 'cron tab',
`is_enabled` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '2' COMMENT 'is enable 2开1关',
`create_time` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'create time',
PRIMARY KEY (`id`) USING BTREE
)
其余按自己逻辑来吧