1、业务流程
2、程序架构
3、代码实战
启动项目可以在 http://127.0.0.1:15672/中看到延迟队列配置类中定义的交换机与队列
延迟队列配置
/**
* 订单超时未支付,延迟队列配置
*/
@Configuration
public class OrderQueueConfig {
// 普通交换机名称
private static final String ORDER_EXCHANGE = "order_exchange";
// 死信交换机名称
private static final String DEAD_EXCHANGE = "dead_exchange";
// 普通队列名称
private static final String ORDER_QUEUE = "order_queue";
// 延迟队列名称
private static final String DELAY_QUEUE = "delay_queue";
// 声名普通交换机
@Bean("orderExchange")
public DirectExchange orderExchange(){
return new DirectExchange(ORDER_EXCHANGE);
}
// 声名死信交换机
@Bean("deadExchange")
public DirectExchange deadExchange(){
return new DirectExchange(DEAD_EXCHANGE);
}
// 声名延迟队列
@Bean("delayQueue")
public Queue delayQueue(){
return QueueBuilder.durable(DELAY_QUEUE).build();
}
// 声名普通队列并与死信队列进行绑定
@Bean("orderQueue")
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("orderQueue") Queue queue,
@Qualifier("orderExchange") DirectExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("order");
}
// 死信队列与与死信交换机进行绑定
@Bean
public Binding DelayQueueBingingToDeadExchange(@Qualifier("delayQueue") Queue queue,
@Qualifier("deadExchange") DirectExchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("expire");
}
}
生产者配置
@RestController()
@RequestMapping("/order")
@Slf4j
public class OrdersController {
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private OrdersService ordersService;
/**
* 通过配置文件注入,提高灵活性
*/
@Value("${order.expire.time}")
private String ORDER_TTL;
/**
* 选择支付方式生产订单,订单状态为未支付,并将消息发送到rabbitMQ的延迟队中
*/
@PostMapping("/create")
public void createOrder(@RequestBody OrdersDTO dto) throws JsonProcessingException {
Orders orders = new Orders();
BeanUtils.copyProperties(dto, orders);
// 订单入库
boolean b = ordersService.save(orders);
// 若此订单入库成功则发送到RabbitMQ并设置过期时间为60s
if (b){
log.info("当前时间:{}订单入库成功,订单Id:{},正在发送到RabbitMQ,超时时间:{}s",new Date(),orders.getOrderId(),ORDER_TTL);
String orderJson = objectMapper.writeValueAsString(orders);
rabbitTemplate.convertAndSend("order_exchange", "order", orderJson,
message ->{
message.getMessageProperties().setExpiration(ORDER_TTL);
return message;});
}
}
}
消费者配置
/**
* 订单延迟队列监听
*/
@Component
@Slf4j
public class OrderListener {
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private OrdersService ordersService;
/**
* 订单超时未支付处理
*/
@RabbitListener(queues = {"delay_queue"})
public void orderExpire(Message message, Channel channel) throws IOException {
// 使用JackSon反序列化
Orders orders = objectMapper.readValue(message.getBody(), Orders.class);
log.info("当前时间:{},订单超时检查订单支付状态,订单信息:{}",new Date(),orders);
// 通过订单Id查询该订单超时后的支付状态
Orders order = ordersService.getById(orders.getOrderId());
// 如果订单状态为未支付则将此订单状态关闭
if (orders.getStatus().equals("未支付")){
ordersService.updateStatusById(order.getOrderId());
}
}
}
结果