rabbitmq的基本设置
进入sbin目录
cd /usr/local/rabbitmq_server-3.8.3/sbin
新增用户
./rabbitmqctl add_user cf 123456
设置用户权限
./rabbitmqctl set_user_tags cf administrator
创建虚拟主句host
创建springBoot项目
导入相关的依赖
略过
创建数据库,创建表
CREATE TABLE `c_order` (
`id` varchar(64) NOT NULL,
`status` int(15) DEFAULT NULL,
`name` varchar(15) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
application.properties
# 配置数据库连接池及数据库驱动
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 配置mysql的链接信息
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
#rabbitmq相关的信息
spring.rabbitmq.host=47.97.206.12
spring.rabbitmq.virtual-host=host2
spring.rabbitmq.username=cf
spring.rabbitmq.password=123456
spring.rabbitmq.port=5672
logging.level.com.itheima.rabbitmq_demo.dao=debug
rabbitMq的相关配置
首先要有个host2,然后创建两个交换机和队列,对于普通的队列,设置消息的存活时间,超过超过该时间则成为死信,通过路由规则进入死信队列
@Configuration
public class RabbitmqConfig {
/**
* 死信队列 和死信交换机
*/
@Bean("dlx_queue")
public Queue dlxQueue() {
return QueueBuilder.durable("dlx_queue").build();
}
@Bean("dlx_exchange")
public Exchange dlxExchange() {
return ExchangeBuilder.directExchange("dlx_exchange").durable(true).build();
}
@Bean
public Binding dlxBinding(@Qualifier("dlx_queue") Queue queue,
@Qualifier("dlx_exchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("dlx").noargs();
}
/**
* 普通的队列 设置消息的超时时间为30s
*/
@Bean("order_queue")
public Queue OrderQueue() {
HashMap<String, Object>mp=new HashMap<>();
mp.put("x-message-ttl", 120 * 1000);//消息的超时时间为60s
mp.put("x-dead-letter-exchange", "dlx_exchange"); //消息过期后进入的交换机为dlx_exchange
mp.put("x-dead-letter-routing-key", "dlx");//信息成为死信后,会以该路由重新发送到死信队列中
return QueueBuilder.durable("order_queue").withArguments(mp).build();
}
@Bean("order_exchange")
public Exchange OrderExchange() {
return ExchangeBuilder.directExchange("order_exchange").durable(true).build();
}
@Bean
public Binding OrderBinding(@Qualifier("order_queue") Queue queue,
@Qualifier("order_exchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("order.biz").noargs();
}
}
Order 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private String id;
private Integer status;
private String name;
}
OrderDao
@Repository
public interface OrderDao {
@Select("select * from c_order")
List<Order> findAll();
@Select("select * from c_order where id= #{id}")
Order getOrderById(String id);
@Select("select * from c_order where status =#{status}")
List<Order>getOrderByStatus(Integer status);
@Insert("insert into c_order (id,status)values(#{id},#{status})")
void insertOneOrder(Order order);
@Update("update c_order set status= #{status} where id =#{id}")
void updateOrderStatusById(@Param("id") String id, @Param("status") Integer status);
}
OrdererviceImpl
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public String placeOrder() {
String id= UUID.randomUUID().toString();
Order order=new Order();
order.setId(id);
order.setStatus(OrderStatus.TO_BE_PAID);
log.info("用户下单成功,订单号为:{},订单状态为:{}",id,order.getStatus());
orderDao.insertOneOrder(order);
rabbitTemplate.convertAndSend("order_exchange","order.biz",id);
log.info("用户生成了一个待付款的订单,订单号为:{}",id);
return "等待付款";
}
@Override
public String paidOrder(String orderId) {
Order order = orderDao.getOrderById(orderId);
Integer status=order.getStatus();
if(status==OrderStatus.TO_BE_PAID){
//如果此时该订单还未付款,则消费此订单
String receivedOrderId = (String)rabbitTemplate.receiveAndConvert("order_queue");
System.out.println(orderId);
//这里的receivedOrderId 是队首元素,也就是第一个出队列的元素
System.out.println(receivedOrderId);
log.info("用户付款了一个订单,订单编号为:{}",receivedOrderId);
orderDao.updateOrderStatusById(receivedOrderId, OrderStatus.HAS_PAID);
log.info("订单号为:{}的订单状态修改为已支付", receivedOrderId);
return "跳转到付款成功页面";
}
return "付款失败";
}
}
OrderConsumer
@Component
@Slf4j
public class OrderConsumer {
@Autowired
private OrderDao orderDao;
@RabbitListener(queues="dlx_queue")
public void timeoutOrderMessage(@Payload String message){
log.info("接收到用户还未支付的订单,订单编号为:{}",message);
//将订单的状态修改为超时未支付
orderDao.updateOrderStatusById(message, OrderStatus.CANCELLED_OVER_TIME);
log.info("订单号为:{}的订单状态修改为超时未支付", message);
//查询用户所有付款超时而取消的订单
List<Order> overTimeOrder = orderDao.getOrderByStatus(OrderStatus.CANCELLED_OVER_TIME);
log.info("用户所有付款超时而取消的订单为:{}", overTimeOrder);
}
}
OrderController
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 用户下单接口(==>发送一条等待付款的消息)
*/
@RequestMapping("/placeOrder")
public String placeOrder(){
return orderService.placeOrder();
}
/**
* 用户付款
*/
@GetMapping("/paidOrder/{orderId}")
public String paidOrder(@PathVariable("orderId") String orderId){
return orderService.paidOrder(orderId);
}
}
项目存在的问题
设置了消息的过期时间,但是队列是先进先出的,如果在service层给某一条订单付款了,但是这个订单却不是队首元素,则此订单最终没有显示付款
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决