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> orderSerialNos = stringRedisTemplate.opsForZSet().rangeByScoreWithScores( ORDER_DELAY_TASK_KEY, 0, //延时任务score最小值 System.currentTimeMillis() //延时任务score最大值(当前时间) ); if (!CollectionUtils.isEmpty(orderSerialNos)) { for (ZSetOperations.TypedTuple 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 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> reservation = stringRedisTemplate.opsForZSet().rangeByScoreWithScores( RESERVATION_DELAY_TASK_KEY, 0, //延时任务score最小值 System.currentTimeMillis() //延时任务score最大值(当前时间) ); if (!CollectionUtils.isEmpty(reservation)) { for (ZSetOperations.TypedTuple reservationId : reservation) { TjReservation tjReservation = reservationService.getById(reservationId.getValue()); if(null==tjReservation) continue; if(tjReservation.getIsExpire()==2){ //对应预约时间数量+1 LambdaQueryWrapper 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(); } }