使用RabbitMQ实现订单超时未支付自动取消

1.在properties或yml配置rabbitmq信息(这里使用properties)

# RabbitMQ服务器的主机地址
spring.rabbitmq.host=192.168.0.1

# RabbitMQ服务器的用户名
spring.rabbitmq.username=root

# RabbitMQ服务器的密码(有就填没有就不填)
spring.rabbitmq.password=""

# RabbitMQ服务器的端口号,默认是5672
spring.rabbitmq.port=5672

# Spring AMQP SimpleMessageListenerContainer配置:初始重试间隔时间(单位为毫秒)
# 当消费者监听到消息处理失败并需要重试时,第一次重试前等待的时间
spring.rabbitmq.listener.simple.retry.initial-interval=5000

# 启用消费者的简单声明式重试机制
spring.rabbitmq.listener.simple.retry.enabled=true

# 设置最大重试次数。如果超过这个次数,消息仍然无法正确处理,则不再重试
spring.rabbitmq.listener.simple.retry.max-attempts=3

# 设置是否将被拒绝的消息重新放回队列。false表示不重新入队列,即默认情况下错误消息不会再次消费
spring.rabbitmq.listener.simple.default-requeue-rejected=false

# 设置消费者确认模式为自动确认(auto acknowledge)。这意味着一旦消息被消费处理器方法成功处理后,就会自动发送acknowledgement给RabbitMQ
spring.rabbitmq.listener.simple.acknowledge-mode=auto

2.创建消息队列配置类

@Configuration
public class OrderQueueConfig {
    // 普通交换机名称
    private static final String ORDER_EXCHANGE = "normal_order_exchange";

    // 死信交换机名称
    private static final String DEAD_EXCHANGE = "normal_dead_exchange";

    // 普通队列名称
    private static final String ORDER_QUEUE = "normal_order_queue";

    // 延迟队列名称
    private static final String DELAY_QUEUE = "normal_delay_queue";


    // 声名普通交换机
    @Bean("orderNormalExchange")
    public DirectExchange orderExchange() {
        return new DirectExchange(ORDER_EXCHANGE);
    }

    // 声名死信交换机
    @Bean("deadDelayExchange")
    public DirectExchange deadExchange() {
        return new DirectExchange(DEAD_EXCHANGE);
    }

    // 声名延迟队列
    @Bean("delayDelayQueue")
    public Queue delayQueue() {
        return QueueBuilder.durable(DELAY_QUEUE).build();
    }

    // 声名普通队列并与死信队列进行绑定
    @Bean("orderNormalDelayQueue")
    public Queue orderQueue() {
        HashMap<String, Object> param = new HashMap<>();
        // 设置死信交换机
        param.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        // 设置死信routingKey
        param.put("x-dead-letter-routing-key", "expire");
        return QueueBuilder.durable(ORDER_QUEUE).withArguments(param).build();
    }

    // 普通队列与交换机绑定
    @Bean
    public Binding orderQueueBindingToOrderExchange(@Qualifier("orderNormalDelayQueue") Queue queue,
                                                    @Qualifier("orderNormalExchange") DirectExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("normal_order");
    }

    // 死信队列与与死信交换机进行绑定
    @Bean
    public Binding DelayQueueBingingToDeadExchange(@Qualifier("delayDelayQueue") Queue queue,
                                                   @Qualifier("deadDelayExchange") DirectExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("expire");
    }

}

3.在controller层调用

@RestController
@RequestMapping(value = "/api/farm/order")
@Slf4j
@Api(tags = "创建订单")
public class OrderController {
	@PostMapping(value = "/createOrder")
	@ApiOperation("创建订单")
	public RespResult createOrder(@RequestBody OrderRequest body) throws JsonProcessingException {

		OrderResponse order = null;
		try {
			order = newPlantOrderService.createOrder(body, result.getResult().toString());
		} catch (Exception e) {
			return RespResult.builder().code(500).msg("创建订单失败,请重试" + e.getMessage()).build();
		}
		if (null != order) {
			//生产者生产消息
			log.info("当前时间:{}订单入库成功,订单Id:{},正在发送到RabbitMQ,超时时间:{}s", LocalDateTime.now(), order.getOrder_no(), 60 * 60 * 1000);
			String orderJson = objectMapper.writeValueAsString(order.getOrder_no());
			this.amqpTemplate.convertAndSend("normal_order_exchange", "normal_order", orderJson, message -> {
				message.getMessageProperties().setExpiration(String.valueOf(60 * 60 * 1000L));
				return message;
			});
		}
		return RespResult.builder().result(order).build();
	}

}

4.创建监听器(消费者端),用于接收超时未支付的订单,并对该订单进行处理

@Component
@Slf4j
public class OrderListener {
    private final ObjectMapper objectMapper = new ObjectMapper();
    @Resource
    private OrderMapper orderMapper;

    @RabbitListener(queues = {"normal_delay_queue"})
    public void orderExpire(Message message, Channel channel) throws IOException {
        // 使用JackSon反序列化
        String orderNo = objectMapper.readValue(message.getBody(), String.class);
        orderNo = orderNo.replace("\"", "");
        log.info("----------------------------------------------------");
        log.info("当前时间:{},订单超时检查订单支付状态,订单信息:{}", LocalDateTime.now(), orderNo);
        // 通过订单Id查询该订单超时后的支付状态
        PlantingOrderDto orderDto = orderMapper.selectOrderByOrderNo(orderNo);
        // 如果订单状态为未支付则将此订单状态关闭
        try {
            if (orderDto.getPayStatus() == 0) {
                log.info("当前时间:{},订单超时关闭订单,订单信息:{}", LocalDateTime.now(), orderNo);
                orderDto.setOrderStatus(-1);
                orderDto.setCompleteTime(LocalDateTime.now());
                orderMapper.updateByPrimaryKeySelective(orderDto);
            }
            log.info("----------------------------------------------------");
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艳哥不秃头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值