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();
}
}
}