基于RabbitMQ的TTL以及死信队列,使用SpringBoot实现延迟付款,手动补偿操作。
1、用户下单后展示等待付款页面
2、在页面上点击付款的按钮,如果不超时,则跳转到付款成功页面
3、如果超时,则跳转到用户历史账单中查看因付款超时而取消的订单。
生产者:
配置类
package com.lagou.config;import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;/*** @Date 2020/8/24 17:34* @Created weijie* @Description*/@Configuration
public class RabbitConfig {@Beanpublic Queue queue() {Map<String, Object> props = new HashMap<>();// 消息的生存时间 30sprops.put("x-message-ttl", 30000);// 设置该队列所关联的死信交换器(当队列消息TTL到期后依然没有消费,则加入死信队列)props.put("x-dead-letter-exchange", "ex.go.dlx");// 设置该队列所关联的死信交换器的routingKey,如果没有特殊指定,使用原队列的routingKeyprops.put("x-dead-letter-routing-key", "go.dlx");Queue queue = new Queue("q.go", true, false, false, props);return queue;}@Beanpublic Queue queueDlx() {Queue queue = new Queue("q.go.dlx", true, false, false);return queue;}@Beanpublic Exchange exchange() {DirectExchange exchange = new DirectExchange("ex.go", true,false, null);return exchange;}/*** 死信交换器* @return*/@Beanpublic Exchange exchangeDlx() {DirectExchange exchange = new DirectExchange("ex.go.dlx", true,false, null);return exchange;}@Beanpublic Binding binding() {returnBindingBuilder.bind(queue()).to(exchange()).with("go").noargs();}/*** 死信交换器绑定死信队列* @return*/@Beanpublic Binding bindingDlx() {returnBindingBuilder.bind(queueDlx()).to(exchangeDlx()).with("go.dlx").noargs();}}
支付接口:
package com.lagou.controller;import com.lagou.entity.Order;
import com.lagou.service.OrderService;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.Date;
import java.util.List;
import java.util.UUID;/*** @Date 2020/8/23 22:27* @Created by weijie* @Description*/@Controller
public class OrderController {@AutowiredAmqpTemplate amqpTemplate;@AutowiredOrderService orderService;int count = 0;/*** 下订单接口、支付接口、查看订单接口*/@RequestMapping("/order/create/orderId")public void createOrder(@PathVariable String orderId){Order order = new Order();order.setOrderCode(UUID.randomUUID().toString());order.setCreateTime(new Date());order.setIsPay(0);order.setOrderName("订单:" + count++);amqpTemplate.convertAndSend("ex.go", "go", order);orderService.update(order);}@RequestMapping("/pay/orderCode")@ResponseBodypublic String pay(@PathVariable String orderCode){Order order = orderService.findByOrderCode(orderCode);if (order == null){return "订单不存在";}if (order.getIsPay() == 1){return "订单已支付";}if (order.getStatus() == 1){return "订单已超时";}//订单支付成功order.setIsPay(1);//未超时order.setStatus(0);orderService.update(order);return "订单支付成功";}@RequestMapping("/order/list")@ResponseBodypublic List<Order> list(){List<Order> all = orderService.findAll();return all;}}
消费者
配置类:
package com.lagou.config;import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Date 2020/8/24 15:19* @Created weijie* @Description*/@Configuration
public class RabbitConfig {@Beanpublic Queue queue(){return QueueBuilder.nonDurable("q.go.dlx").build();}
}
监听订单队列:
package com.lagou.consumer;import com.lagou.entity.Order;
import com.lagou.service.OrderService;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.io.IOException;/*** @Date 2020/8/24 15:35* @Created weijie* @Description*/@Component
public class Listener {@AutowiredOrderService orderService;private Integer index = 0;/*** 监听私信队里中的值* @param msg* @param channel*/@RabbitListener(queues = "q.go.dlx")public void getMessage(Message msg, Channel channel) throws IOException {String orderCode = new String(msg.getBody());System.out.println("超时订单 : " + orderCode);//需要确认收到的消息,否则死信队列消息会一直存在//???long deliveryTag = msg.getMessageProperties().getDeliveryTag();if (index % 2 == 0){//确认消息channel.basicAck(deliveryTag, false);}else{//拒收消息channel.basicAck(deliveryTag, false);}index ++;Order order = orderService.findByOrderCode(orderCode);if (order == null){System.out.println("未查询到相应订单:" + orderCode);return;}//订单已支付if (order.getIsPay() > 0){System.out.println("订单已支付:" + orderCode);return;}//订单未支付order.setIsPay(0);//订单已超时order.setIsTimeOut(1);orderService.update(order);}}