rabbitMQ实现订单超时未支付自动取消订单

前期准备

下面展示一些 内联代码片

1.配置文件,导入jar包

server:
  port: 8983
spring:
  application:
    name: API-RABBITMQ

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/yingxue?characterEncoding=UTF-8&useSSL=false
    username: root
    password: 123

  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /

mybatis:
  #mapper配置文件的位置
  mapper-locations: classpath:com.hou.mapper/*.xml
  #别名
  type-aliases-package: com.hou.entity


# 自定义过期时间
order:
  delay:
    time: 12000 # 单位毫秒

2. 使用rabbitMQ插件绑定延时队列,插件可自动实现死信队列,无需配置

//**
 * mq 配置类
 */
@Configuration
public class RabbitMQConfig {

    //声明1个路由key 1个队列 1个交换机
    //延迟交换机
    public static final String DELAY_EXCHANGE_NAME = "delay.exchange";
    //延迟队列
    public static final String DELAY_QUEUE_NAME = "delay.queue";
    //延迟队列路由key
    public static final String DELAY_QUEUE_ROUTING_KEY = "delay.queue.routingkey";

    // 声明延迟交换机,由插件处理代码
    @Bean("delayExchange")
    public CustomExchange delayExchange() {
        HashMap<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        // 自定义的交换机
        return new CustomExchange(DELAY_EXCHANGE_NAME,
                "d-delayed-message", true, false, args);
    }

    // 声明延迟队列,
    @Bean("delayQueue")
    public Queue delayQueueA() {
        return new Queue(DELAY_QUEUE_NAME);
    }

    // 声明延迟队列B的绑定关系
    @Bean
    public Binding delayBindingB(@Qualifier("delayQueue") Queue queue,
                                 @Qualifier("delayExchange") CustomExchange exchange) {
        return BindingBuilder.bind(queue)
                .to(exchange)
                .with(DELAY_QUEUE_ROUTING_KEY)
                .noargs();
    }

}

3. 生产者代码实现,

/**
 * 生产者代码
 */
@Component
public class DelayMessageProducer {

    @Resource
    private RabbitTemplate rabbitTemplate;

    public void send(String message, Integer delayTime) {

        // 三个参数
        rabbitTemplate.convertAndSend(RabbitMQConfig.DELAY_EXCHANGE_NAME,
                RabbitMQConfig.DELAY_QUEUE_ROUTING_KEY,
                message1 -> {
                    message1.getMessageProperties().setDelay(delayTime);
                    return message1;
                });
    }

}

4. service层代码, 创建订单时,同步发送消息到mq,指定超时时间

public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired  // 注入生产者
    private DelayMessageProducer producer;
    @Value("${order.delay.time}")
    private Integer orderDelayTime;

    /**
     * 保存新增订单
     */
    @Override
    @Transactional
    public Map<String, Object> save(Order order) {

        // 订单编号
        order.setOrderSn(IdUtil.getSnowflake(1, 1).nextIdStr());
        // 订单状态
        order.setOrderStatus(OrderStatus.no_confirm.getStatus());
        // 支付状态
        order.setPayStatus(PayStatus.no_pay.getStatus());
        // 下单时间
        order.setOrderTime(new Date());
        // 使用plus插入一条记录
        int result = orderMapper.insert(order);
        HashMap<String, Object> map = new HashMap<>();

        // 插入成功
        if (result > 0) {
            map.put("code", 200);
            map.put("message", "订单已提交");
            map.put("data", order);
            // 发送消息到延迟队列, 设置消息过期时间
            producer.send(order.getOrderSn(), orderDelayTime);
            return map;
        } else {
            map.put("code", 400);
            map.put("message", "订单提交失败");
            map.put("data", null);
            return map;
        }
    }

5.消费者代码实现,修改订单的状态, 保存未支付订单表中数据

/**
 * 消息消费者
 */
@Slf4j
@Component
public class DeadLetterQueueConsumer {

    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderActionMapper orderActionMapper;

    // 监听延迟队列A
    @RabbitListener(queues = RabbitMQConfig.DELAY_QUEUE_NAME)
    public void receiveA(Message message, Channel channel) {
        String orderSn = new String(message.getBody());
        log.info("当前时间: {},  延迟队列收到订单编号: {}", LocalDateTime.now(), orderSn);

        // 根据订单编号查询订单
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.ge("orderSn", orderSn);
        Order order = orderMapper.selectOne(wrapper);

        if (order != null && order.getOrderStatus().equals(OrderStatus.no_confirm.getStatus())
                && order.getPayStatus().equals(PayStatus.no_pay.getStatus())) {
            // 设置订单的状态为已取消
            order.setOrderStatus(OrderStatus.cancel.getStatus());
            // 修改状态
            int result = orderMapper.updateById(order);
            if (result > 0) {
                // 订单取消表中插入数据
                OrderAction orderAction = new OrderAction();
                orderAction.setOrderSn(orderSn);
                orderAction.setOrderStatus(OrderStatus.cancel.getStatus());
                orderAction.setPayStatus(PayStatus.no_pay.getStatus());
                orderAction.setActionNote("支付超时,订单已取消");
                orderAction.setActionTime(new Date());
                orderAction.setStatusDesc("支付超时,订单已取消");
                //新增取消订单 表
                orderActionMapper.insert(orderAction);
            }
        }
    }

}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值