最近做一个小小小小商城,有一个需求就是需要在订单24小时内未付款将订单取消的需求,本来想着弄个定时任务随便搞一搞就完事了,但是本着以用户体验至上的原则,还是好好做吧。
在Java的并发包里有一个java.util.concurrent.DelayQueue,要用这个队列必须要有一个类实现java.util.concurrent.Delayed接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | @Data public class OrderCancelDelayedImpl implements Delayed {
      public OrderCancelDelayedImpl(Long id, LocalDate executeTime) {         this.id = id;         this.executeTime = executeTime;     }
      private Long id;     private LocalDateTime executeTime;
      @Override     public long getDelay(TimeUnit unit) {         return executeTime.isBefore(LocalDateTime.now()) ? -1 : 1;     }
      @Override     public int compareTo(Delayed o) {         if (this == o) {             return 0;         }         if (o instanceof OrderCancelDelayedImpl) {             return this.executeTime.compareTo(((OrderCancelDelayedImpl) o).getExecuteTime());         } else {             throw new RuntimeException("this is a error message");         }     } }
   | 
 
主要实现两个方法:
getDelay:官方给的解释Returns the remaining delay associated with this object, in the given time unit.,简单来说就是用来判断什么时候出列。返回值大于0不出列,反之出列。 
compareTo:这个没啥说的就是做个比较看看是不是放重了。 
在这个类中有两个属性:
id:主要记录要取消那个订单。 
executeTime:执行取消订单的时间,前期主要作用是判断执不执行。 
其中的属性可以根据自己的需求来添加。
然后是创建一个一个队列
1 2 3 4 5 6 7 8 9 10 11 12 13
   | 
 
 
 
  @Configuration public class OrderConfig {
      @Bean     public DelayQueue<OrderCancelDelayedImpl> delayQueue() {         return new DelayQueue<>();     } }
 
  | 
 
然后是在什么时候将DelayedImpl放入队列,我的需求是确认订单后24小时未付款取消订单,需要在订单创建完成之后将订单信息放入队列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | @Slf4j @Service("orderService") public class OrderServiceImpl{                    public void create(Order order) {                  LocalDateTime now = LocalDateTime.now();         order.setCreateTime(now);         orderDao.insert(order);         delayQueue.put(new OrderCancelDelayedImpl(order.getId(), now));     } }
   | 
 
然后我们需要启动一个线程来取消超过24小时未付款的订单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | 
 
 
 
  @Slf4j public class CancelOrderThread extends Thread {
      @Resource(name = "orderService")     private OrderService orderService;
      @Resource(name = "delayQueue")     private DelayQueue<OrderCancelDelayedImpl> delayQueue;
      @Override     public void run() {         OrderCancelDelayedImpl delayed;         while (true) {             try {
                  delayed = delayQueue.take();                 orderService.cancel(new Order(delayed.getOrderId()));                 log.info("------ id为" + delayed.getOrderId() + "订单已被取消 ------");
              } catch (InterruptedException e) {                 if (delayed != null) {                     log.error("------ id为" + delayed.getOrderId() + "订单取消失败 ------", e);                 }             }         }     } }
 
  | 
 
然后再OrderConfig注册CancelOrderThread
1 2 3 4
   | @Bean public CancelOrderThread cancelOrderThread() {     return new CancelOrderThread(); }
   | 
 
最后则是在启动服务器的时候启动该线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | 
 
 
 
  @Slf4j @Component public class ServerStartedListenerCancelOrderThread implements ApplicationListener<ContextRefreshedEvent> {
      @Resource(name = "cancelOrderThread")     private CancelOrderThread cancelOrderThread;
      @Override     public void onApplicationEvent(ContextRefreshedEvent event) {         if (event.getApplicationContext().getParent() == null) {             cancelOrderThread.start();             log.info("------ 取消订单线程开始工作 ------");         }     } }
 
  |