package com.ltkj.web.config.redis;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.ltkj.common.core.domain.AjaxResult;
|
import com.ltkj.hosp.domain.TjReservation;
|
import com.ltkj.hosp.service.ITbTransitionService;
|
import com.ltkj.hosp.service.ITjReservationService;
|
import com.ltkj.mall.domain.MallOrder;
|
import com.ltkj.mall.domain.MallTimeConfig;
|
import com.ltkj.mall.mallOrderUtils.OrderHandleOption;
|
import com.ltkj.mall.mallOrderUtils.OrderUtil;
|
import com.ltkj.mall.service.IMallOrderService;
|
import com.ltkj.mall.service.IMallTimeConfigService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.ZSetOperations;
|
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.stereotype.Component;
|
|
import javax.annotation.Resource;
|
import java.util.Date;
|
import java.util.Set;
|
|
@Component
|
@Slf4j
|
public class OrderDelayService implements InitializingBean {
|
//redis zset key
|
public static final String ORDER_DELAY_TASK_KEY = "delaytask:order";
|
public static final String RESERVATION_DELAY_TASK_KEY = "delaytask:reservationId";
|
|
@Resource
|
private StringRedisTemplate stringRedisTemplate;
|
@Resource
|
private ITjReservationService reservationService;
|
@Resource
|
private ITbTransitionService transitionService;
|
@Autowired
|
private IMallTimeConfigService mallTimeConfigService;
|
|
@Autowired
|
private IMallOrderService orderService;
|
|
//生成订单-order为订单信息,可以是订单流水号,用于延时任务达到时效后关闭订单
|
public void produce(String orderId){
|
stringRedisTemplate.opsForZSet().add(
|
ORDER_DELAY_TASK_KEY, // redis key
|
orderId, // zset member
|
//30分钟延时
|
System.currentTimeMillis() + (30 * 60 * 1000) //zset score
|
// System.currentTimeMillis() + (10 * 1000) //zset score
|
);
|
}
|
|
|
//预约超时
|
public void reservation(String reservationId){
|
|
TjReservation tjReservation = reservationService.getById(reservationId);
|
if(null !=tjReservation){
|
stringRedisTemplate.opsForZSet().add(
|
RESERVATION_DELAY_TASK_KEY, // redis key
|
reservationId, // zset member
|
//预约时间的 晚上7点过时
|
tjReservation.getReservationTime().getTime() + (60 * 60 * 1000 * 19) //zset score
|
);
|
}
|
}
|
|
//延时任务,也是异步任务,延时任务达到时效之后关闭订单,并将延时任务从redis zset删除
|
@Async("async")
|
public void consuming(){
|
|
//订单
|
Set<ZSetOperations.TypedTuple<String>> orderSerialNos = stringRedisTemplate.opsForZSet().rangeByScoreWithScores(
|
ORDER_DELAY_TASK_KEY,
|
0, //延时任务score最小值
|
System.currentTimeMillis() //延时任务score最大值(当前时间)
|
);
|
if (!CollectionUtils.isEmpty(orderSerialNos)) {
|
for (ZSetOperations.TypedTuple<String> orderId : orderSerialNos) {
|
//这里根据orderSerialNo去检查用户是否完成了订单支付
|
//如果用户没有支付订单,去执行订单关闭的操作
|
|
MallOrder order = orderService.getById(orderId.getValue());
|
if (order == null) {
|
log.info("订单" + orderId.getValue() + "不存在 被自动关闭");
|
stringRedisTemplate.opsForZSet().remove(ORDER_DELAY_TASK_KEY, orderId.getValue());
|
}else {
|
// 检测是否能够取消
|
OrderHandleOption handleOption = OrderUtil.build(order);
|
if (!handleOption.isCancel()) {
|
log.info("订单" + orderId.getValue() + "不能取消 被自动关闭");
|
stringRedisTemplate.opsForZSet().remove(ORDER_DELAY_TASK_KEY, orderId.getValue());
|
}else {
|
// 设置订单已取消状态
|
order.setOrderStatus(OrderUtil.STATUS_CANCEL.longValue());
|
order.setCloseTime(new Date());
|
order.setUpdateTime(new Date());
|
orderService.updateById(order);
|
//对应预约时间数量+1
|
final TjReservation byId = reservationService.getById(order.getReservationId());
|
final Date reservationTime = byId.getReservationTime();
|
LambdaQueryWrapper<MallTimeConfig> wq=new LambdaQueryWrapper<>();
|
wq.eq(MallTimeConfig::getTime,reservationTime);
|
final MallTimeConfig one = mallTimeConfigService.getOne(wq);
|
one.setNowNum(one.getNowNum()+1);
|
mallTimeConfigService.updateById(one);
|
byId.setIsExpire(1);
|
reservationService.updateById(byId);
|
transitionService.deletedTbTransitionListByCusIdAndTjNum(byId.getIdCard(),byId.getCardId());
|
}
|
}
|
//订单关闭之后,将订单延时任务从队列中删除
|
stringRedisTemplate.opsForZSet().remove(ORDER_DELAY_TASK_KEY, orderId.getValue());
|
}
|
}
|
|
|
//预约超时
|
Set<ZSetOperations.TypedTuple<String>> reservation = stringRedisTemplate.opsForZSet().rangeByScoreWithScores(
|
RESERVATION_DELAY_TASK_KEY,
|
0, //延时任务score最小值
|
System.currentTimeMillis() //延时任务score最大值(当前时间)
|
);
|
if (!CollectionUtils.isEmpty(reservation)) {
|
for (ZSetOperations.TypedTuple<String> reservationId : reservation) {
|
TjReservation tjReservation = reservationService.getById(reservationId.getValue());
|
if(null==tjReservation) continue;
|
if(tjReservation.getIsExpire()==2){
|
//对应预约时间数量+1
|
LambdaQueryWrapper<MallTimeConfig> wq=new LambdaQueryWrapper<>();
|
wq.eq(MallTimeConfig::getTime,tjReservation.getReservationTime());
|
final MallTimeConfig one = mallTimeConfigService.getOne(wq);
|
one.setNowNum(one.getNowNum()+1);
|
mallTimeConfigService.updateById(one);
|
tjReservation.setIsExpire(1);
|
reservationService.updateById(tjReservation);
|
transitionService.deletedTbTransitionByCusId(tjReservation.getIdCard());
|
}
|
//关闭之后,将任务从队列中删除
|
stringRedisTemplate.opsForZSet().remove(RESERVATION_DELAY_TASK_KEY, reservationId.getValue());
|
}
|
}
|
}
|
|
//该类对象Bean实例化之后,就开启while扫描任务
|
@Override
|
public void afterPropertiesSet() throws Exception {
|
new Thread(() -> { //开启新的线程,否则SpringBoot应用初始化无法启动
|
while(true){
|
try {
|
Thread.sleep(3 * 1000); //每5秒扫描一次redis库获取延时数据,不用太频繁没必要
|
// log.info("我执行了一次~~~~~~");
|
} catch (InterruptedException e) {
|
e.printStackTrace(); //本文只是示例,生产环境请做好相关的异常处理
|
}
|
consuming();
|
}
|
}).start();
|
}
|
}
|