# stage06-01 **Repository Path**: null_631_9084/stage06-01 ## Basic Information - **Project Name**: stage06-01 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-11-10 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 作业 基于RabbitMQ的TTL以及死信队列,使用SpringBoot实现延迟付款,手动补偿操作。 1、用户下单后展示等待付款页面 2、在页面上点击付款的按钮,如果不超时,则跳转到付款成功页面 3、如果超时,则跳转到用户历史账单中查看因付款超时而取消的订单。 ### 访问 http://localhost:8080/ 下单,10秒钟不支付就过期,消息会到死信队列 10秒内支付,就会消费这条消息,不会进入死信队列 ### config ```properties spring.rabbitmq.host=192.168.181.140 spring.rabbitmq.virtual-host=/ spring.rabbitmq.username=root spring.rabbitmq.password=123456 spring.rabbitmq.port=5672 ``` ## rabbitconfig ```java @EnableRabbit @Configuration public class RabbitConfig { public static String queueName = "queue.order"; public static String exchangeName = "ex.order"; public static String orderRK = "rk.order"; /** * 声明普通队列 * @return */ @Bean public Queue queue(){ Map props = new HashMap<>(); //消息10秒后过期,进入死信队列 props.put("x-message-ttl",10000); //死信交换器 props.put("x-dead-letter-exchange","ex.dlx.order"); //死信交换器中的路由key props.put("x-dead-letter-routing-key","rk.dlx.order"); return new Queue(queueName,false,false,false,props); } @Bean public Exchange exchange() { //声明direct类型的交换器 return new DirectExchange(exchangeName, true, false, null); } @Bean public Binding binding() { //绑定上面的普通队列与普通交换吕 return BindingBuilder.bind(queue()).to(exchange()).with(orderRK).noargs(); } @Bean public Queue queueDlx() { //声明死信队列 Queue queue = new Queue("queue.dlx.order", true, false, false); return queue; } @Bean public Exchange exchangeDlx() { //声明死信交换器 return new DirectExchange("ex.dlx.order", false, false, null); } @Bean @Autowired public RabbitAdmin rabbitAdmin(ConnectionFactory factory) { return new RabbitAdmin(factory); } @Bean public Binding dlxBinding() { //绑定死信队列与死信交换器,路由key return BindingBuilder.bind(queueDlx()).to(exchangeDlx()).with("rk.dlx.order").noargs(); } } ``` ### 监听器 ```java @Slf4j @Component public class OrderPayTimeOutListener { @RabbitListener(queues = "queue.dlx.order") public void onMessage(Message message, Channel channel) throws IOException { String orderId =new String(message.getBody(), message.getMessageProperties().getContentEncoding()); log.warn("===========支付订单已过期========== orderId: "+orderId); final OrderController.Order order = OrderController.orders.get(orderId); order.setStatus("已过期"); } } ``` ### controller ```java @Slf4j @RestController public class OrderController { @Autowired private AmqpTemplate rabbitTemplate; public static final ConcurrentHashMap orders = new ConcurrentHashMap<>(); @PostMapping(value = "/order") public ResponseEntity order() throws UnsupportedEncodingException { Order order = new Order(); order.setOrderId(String.valueOf(System.currentTimeMillis())); order.setStatus("待支付"); orders.put(order.getOrderId(),order); final MessageProperties messageProperties = MessagePropertiesBuilder.newInstance() .setContentEncoding("utf-8") .build(); final Message message = MessageBuilder .withBody(order.getOrderId().getBytes("UTF-8")) .andProperties(messageProperties) .build(); rabbitTemplate.convertAndSend(RabbitConfig.exchangeName, RabbitConfig.orderRK, message); return ResponseEntity.ok(order); } @PostMapping(value = "/pay") public ResponseEntity pay(String id){ final Order order = orders.get(id); if (order.getStatus().equals("已过期")) { log.info("===========支付订单失败,订单已过期========== orderId="+id); return ResponseEntity.ok().body("支付失败,订单已过期"); } log.info("===========支付订单成功========== orderId="+id); order.setStatus("已支付"); //这里消费消息 rabbitTemplate.receive(RabbitConfig.queueName); return ResponseEntity.ok().body("支付成功,消费消息"); } @GetMapping(value = "/list") public ResponseEntity list(){ final Collection values = orders.values(); return ResponseEntity.ok(values); } @Data public class Order{ private String orderId; private String status; } ```