springboot整合RabbitMQ实现延时自动取消订单

1.pom依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2.配置这里我使用了死讯队列,原理其实很简单,先发送到死讯队列并且设置时间,然后死讯队列到时会自动转发到对应真正的消费队列,3个列队,自动收货,2个自动取消订单

**
 * rabbitMQ采用路由模式
 * 一个交换机对应多个队列
 * bei
 */
@AllArgsConstructor
public class OrderDirectExchangeConfig {

    /**
     * 订单实际消费队列
     */
    @Bean
    public Queue orderQueue(){
        return new Queue(QueueEnum.QUEUE_ORDER_CANCEL.getName());
    }

   /**
    * 支付延时实际消费队列
    */
   @Bean
   public Queue payQueue(){
      return new Queue(QueueEnum.QUEUE_PAY_CANCEL.getName());
   }

   /**
    * 收货延时实际消费队列
    */
   @Bean
   public Queue receiveQueue(){
      return new Queue(QueueEnum.QUEUE_AUTO_RECEIVE.getName());
   }

    /**
     * 订单延迟队列(死信队列)
     */
    @Bean
    public Queue orderTtlQueue(){
        return QueueBuilder
                .durable(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getName())
                .withArgument("x-dead-letter-exchange", QueueEnum.QUEUE_ORDER_CANCEL.getExchange()) //到期后转发的交换机
                .withArgument("x-dead-letter-routing-key", QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey()) // 到期后转发的路由键
                .build();
    }

   /**
    * 支付延迟队列(死信队列)
    */
   @Bean
   public Queue payTtlQueue(){
      return QueueBuilder
            .durable(QueueEnum.QUEUE_TTL_PAY_CANCEL.getName())
            .withArgument("x-dead-letter-exchange", QueueEnum.QUEUE_ORDER_CANCEL.getExchange()) //到期后转发的交换机
            .withArgument("x-dead-letter-routing-key", QueueEnum.QUEUE_PAY_CANCEL.getRouteKey()) // 到期后转发的路由键
            .build();
   }

   /**
    * 收货延迟队列(死信队列)
    */
   @Bean
   public Queue receiveTtlQueue(){
      return QueueBuilder
            .durable(QueueEnum.QUEUE_TTL_AUTO_RECEIVE.getName())
            .withArgument("x-dead-letter-exchange", QueueEnum.QUEUE_ORDER_CANCEL.getExchange()) //到期后转发的交换机
            .withArgument("x-dead-letter-routing-key", QueueEnum.QUEUE_AUTO_RECEIVE.getRouteKey()) // 到期后转发的路由键
            .build();
   }

    /**
     * 订单消息实际消费绑定的交换机
     */
    @Bean
    DirectExchange orderExchange(){
        return (DirectExchange) ExchangeBuilder.directExchange(QueueEnum.QUEUE_ORDER_CANCEL.getExchange())
                // 开启持久化,如果服务器宕机消息依旧存在
                .durable(true)
                .build();
    }

    /**
     * 订单队列绑定到交换机上
     */
    @Bean
    Binding orderBinding(DirectExchange orderExchange, Queue orderQueue){
        return BindingBuilder
                .bind(orderQueue)
                .to(orderExchange)
                .with(QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey());
    }

   /**
    * 支付队列绑定到交换机上
    */
   @Bean
   Binding payBinding(DirectExchange orderExchange, Queue payQueue){
      return BindingBuilder
            .bind(payQueue)
            .to(orderExchange)
            .with(QueueEnum.QUEUE_PAY_CANCEL.getRouteKey());
   }


   /**
    * 支付队列绑定到交换机上
    */
   @Bean
   Binding receiveBinding(DirectExchange orderExchange, Queue receiveQueue){
      return BindingBuilder
            .bind(receiveQueue)
            .to(orderExchange)
            .with(QueueEnum.QUEUE_AUTO_RECEIVE.getRouteKey());
   }


    /**
     * 订单延迟队列 绑定到交换机
     */
    @Bean
    Binding orderTtlBinding(DirectExchange orderExchange, Queue orderTtlQueue){
        return BindingBuilder
                .bind(orderTtlQueue)
                .to(orderExchange)
                .with(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey());
    }

   /**
    * 支付延迟队列 绑定到交换机
    */
   @Bean
   Binding payTtlBinding(DirectExchange orderExchange, Queue payTtlQueue){
      return BindingBuilder
            .bind(payTtlQueue)
            .to(orderExchange)
            .with(QueueEnum.QUEUE_TTL_PAY_CANCEL.getRouteKey());
   }

   /**
    * 收货延迟队列 绑定到交换机
    */
   @Bean
   Binding receiveTtlBinding(DirectExchange orderExchange, Queue receiveTtlQueue){
      return BindingBuilder
            .bind(receiveTtlQueue)
            .to(orderExchange)
            .with(QueueEnum.QUEUE_TTL_AUTO_RECEIVE.getRouteKey());
   }
}
/**
 * @author bei
 * @2019/11/18 22:59
 */
public interface TimeConstants {
   /**
    * 延时任务默认延时时间 15分钟
    */
   Long DEFAULT_DELAYED_TIME = 15 * 60 * 1000L;

   /**
    * 自动收货时间为7天
    */
   Long AUTO_RECEIVE_TIME = 60 * 1000 * 60 * 24 * 7L;
// Long AUTO_RECEIVE_TIME =  1 * 60 * 1000L;
}
public enum QueueEnum {
    /**
     * 订单延时队列
     */
    QUEUE_ORDER_CANCEL("mall.order.direct", "mall.order.cancel", "mall.order.cancel"),
    /**
     * 订单延时ttl队列
     */
    QUEUE_TTL_ORDER_CANCEL("mall.order.direct", "mall.order.cancel.ttl", "mall.order.cancel.ttl"),

   /**
    * 订单延时队列
    */
   QUEUE_PAY_CANCEL("mall.order.direct", "mall.pay.cancel", "mall.pay.cancel"),

   /**
    * 订单支付ttl队列
    */
   QUEUE_TTL_PAY_CANCEL("mall.order.direct", "mall.pay.cancel.ttl", "mall.pay.cancel.ttl"),


   /**
    * 自动收货队列
    */
   QUEUE_AUTO_RECEIVE("mall.order.direct", "mall.auto.receive", "mall.auto.receive"),

   /**
    * 自动收货ttl队列
    */
   QUEUE_TTL_AUTO_RECEIVE("mall.order.direct", "mall.auto.receive.ttl", "mall.auto.receive.ttl");
   /**
     * 交换名称
     */
    private String exchange;
    /**
     * 队列名称
     */
    private String name;
    /**
     * 路由键
     */
    private String routeKey;

    QueueEnum(String exchange, String name, String routeKey) {
        this.exchange = exchange;
        this.name = name;
        this.routeKey = routeKey;
    }

    public String getExchange() {
        return exchange;
    }

    public String getName() {
        return name;
    }

    public String getRouteKey() {
        return routeKey;
    }
}

3.yml

spring:
  rabbitmq:
    username: guest
    password: guest
    host: 127.0.0.1
    port: 5672

4.生产者和消费者

/**
 * 延时订单消费者
 * bei
 */
@Component
@Slf4j
public class CancelOrderReceiver {
   @Autowired
   private MallOrderService mallOrderService;
   @Autowired
   MallProdSelfInfoService mallProdSelfInfoService;

    /**
     * 订单需要先确认是否还是未付款状态
     */
   @RabbitListener(queues = "mall.order.cancel") // 设置队列路由键,和监听容器
   public void handle(String orderId, Message message, Channel channel){
      try {
         MallOrder mallOrder = mallOrderService.getById(orderId);
         if (ShopOrderConstants.WAITRECEIVE_ORDER_STATUS.equals(mallOrder.getStatus())){
            MallOrder temp = new MallOrder();
            temp.setId(mallOrder.getId());
            log.info("订单超时自动取消,订单id为{}", mallOrder.getId());
            mallOrderService.cancelOrder(orderId, "订单超时,系统自动取消");
         }
         // TODO 通知 MQ 消息已被成功消费,可以ACK了
         channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
      } catch (Exception e) {
         // TODO 如果报错了,那么我们可以进行容错处理,比如转移当前消息进入其它队列
      }
    }


}
/**
 * 订单延迟生产者
 * bei
 */
@Component
public class CancelOrderSender {
    private static Logger logger = LoggerFactory.getLogger(CancelOrderSender.class);
    @Autowired
    private RabbitTemplate rabbitTemplate;
    public void sendMessage(String orderId, long delayTimes){
            rabbitTemplate.convertAndSend(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange(),
                    QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey(), orderId,
                    message -> {
                            message.getMessageProperties().setExpiration(String.valueOf(delayTimes));
                            // 当数据还没有持久化的时候,如果服务器宕机,设置此参数也可以恢复数据
                            message.getMessageProperties().setDeliveryMode(MessageProperties.DEFAULT_DELIVERY_MODE);
                            return message;
                        }
                    );
            logger.info("订单生成者 订单编号:{}",orderId);
    }
}

5.方法调用:

// 启动延时任务
cancelOrderSender.sendMessage(mallOrder.getId(), TimeConstants.DEFAULT_DELAYED_TIME);
发布了13 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39701913/article/details/103938121