当前位置: 首页 > news >正文

2.RabbitMQ - 入门

RabbitMQ 入门

文章目录

  • RabbitMQ 入门
  • 一、快速入门
    • 1.1 介绍
    • 1.2 创建项目
    • 1.3 简单入门
  • 二、Work模型
  • 三、交换机
    • 3.1 Fanout
    • 3.2 Direct
    • 3.3 Topic
  • 四、声明队列和交换机
    • 4.1 配置文件
    • 4.2 注解
  • 五、消息转换器

一、快速入门

1.1 介绍

官方的API较为麻烦,我们使用官方推荐的Spring AMQP客户端

RabbitMQ tutorial - “Hello World!” | RabbitMQ 是使用Java完成HelloWord的示例

Spring AMQP客户端实在Java客户端的基础上做了一层封装,让我们使用RabbitMQ变得更加的简单

image-20240511092119183

其中客户端Spring AMQP客户端:

image-20240511092320815

AMQP和Spring AMQP的介绍如下所示

我们使用Spring AMQP的时候,自动使用了AMQP协议

image-20240511092655082

Spring AMQP的官网地址:Spring AMQP

1.2 创建项目

创建一个聚合工程

image-20240511094937051

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.itcast.demo</groupId><artifactId>mq-demo</artifactId><version>1.0-SNAPSHOT</version><modules><module>publisher</module><module>consumer</module></modules><packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.12</version><relativePath/></parent><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--AMQP依赖,包含RabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><!--单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--Jackson--><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId></dependency></dependencies>
</project>

1.3 简单入门

我们先实现一个简单的:publisher向queue发送消息,consumer从queue中获取消息,先省去一个交换机

需求如下

  • 利用控制台创建队列simple.queue

    image-20240511100732002

  • 在publisher服务中,利用SpringAMQP直接向simple.queue发送消息

1、父工程中引入spring-amqp依赖,这样publisher和consumer服务都可以使用

<!--AMQP依赖,包含RabbitMQ-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2、在每个微服务里面引入MQ服务端信息,连接到微服务

virtual-host虚拟主机,username用户名, password密码

logging:pattern:dateformat: MM-dd HH:mm:ss:SSS
spring:rabbitmq:host: 127.0.0.1port: 5672virtual-host: /testhostusername: testallpassword: guest

3、发送消息

SpringAMQP提供了RabbitTemplate工具类,方便我们发送消息。

@Autowired
private RabbitTemplate rabbitTemplate;@Test
public void testSimpleQueue(){// 队列名称String queueName = "simple.queue";//消息String message = "hello,simple.queue";//发送消息rabbitTemplate.convertAndSend(queueName,message);
}

4、控制台结果

image-20240511101655789

消息内容如下图所示

image-20240511101726913

  • 在consumer服务中,利用SpringAMQP编写消费者,监听simple.queue队列

1、监听队列,获取消息

@Slf4j
@Component
public class MqListener {//这个注解是监听哪个队列,queues是监听队列的名字@RabbitListener(queues = "simple.queue")public void listenSimpleQueue(String msg){System.out.println("消费者收到了simple.queue的消息:【" + msg +"】");}
}

2、启动本微服务查看结果

image-20240511140308141

image-20240511095500723

二、Work模型

Work Queues,任务模型,简单来说就是让多个消费者绑定到一个队列,共同消费队列中的消息。

其实就是一种用法而已,没有太高大上

基本思路如下

  1. 在RabbitMQ控制台创建一个队列,名为work.queue

image-20240511142328747

  1. 在publiser服务中定义测试方法,在1s内产生50条消息,发送到work.queue队列
@Autowired
private RabbitTemplate rabbitTemplate;@Test
void testWorkQueue() throws InterruptedException {String queueName = "work.queue";for (int i = 1; i <= 50; i++) {String msg = "hello, worker, message_" + i;rabbitTemplate.convertAndSend(queueName, msg);Thread.sleep(20);}
}
  1. 在consumer服务中定义两个消息监听者,都监听work.queue队列

  2. 消费者1每秒处理50条消息,消费者2每秒处理5条消息

@RabbitListener(queues = "work.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {System.out.println("消费者1 收到了 work.queue的消息:【" + msg +"】");// Thread.sleep(20);
}@RabbitListener(queues = "work.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {System.err.println("消费者2 收到了 work.queue的消息...... :【" + msg +"】");// Thread.sleep(200);
}
  1. 效果图

下面的效果图没截取全,下面接受消息的总数是50

image-20240511173052060

之后我们将注释打开,一个消费者睡眠20ms,一个消费者睡眠200ms,效果图,依然是一人一个,一人一半,所以说投递消息的时候并没有考虑到消费者的消费能力

image-20240511173149702

  1. 结论
  • 向一个队列发送消息,这个队列有两个消费者,那这同一条消息只会被消费一次

  • 默认情况下,如果队列中有多个消费者,那么在队列投递消息时,会采用一种轮训的机制,一个消费者一条

  • 可以在consumer工程中添加listener.simple.prefetch=1参数,每次只能回去一条消息,处理完成才能获取下一个消息

假如消费者处理消息处理不过来,消息就会在队列中进行积累,出现消息堆积问题,此时我们应该加快消息的消费速度,比如同一个队列绑定多个消费者,但是为了充分利用消费者的性能,或选择添加下列的prefetch参数

logging:pattern:dateformat: MM-dd HH:mm:ss:SSS
spring:rabbitmq:host: 127.0.0.1port: 5672virtual-host: /testhostusername: testallpassword: guestlistener:simple:prefetch: 1

效果图

image-20240511173409534

三、交换机

真正的生产环境都会经过exchange发送消息,而不是直接发送到队列

  • Fanout:广播
  • Direct:定向
  • Topic:话题

交换机本身具备一些路由功能,而我们实际业务需求往往是需要去做路由的

image-20240511174513683

3.1 Fanout

Fanout Exchange将接收到的消息广播到每一个跟其绑定的queue,所示叫广播模式

  • 接收publisher发送的消息
  • 将消息按照规则路由到与之绑定的队列
  • FanoutExchange的会将消息路由到每个绑定的队列

image-20240511174639379

实现思路如下所示

  1. 在RabbitMQ控制台,声明队列fanout.queue1和fanout.queue2

image-20240514085409051

  1. 在RabbitMQ控制台中,声明交换机hmall.fanout,将两个队列与其绑定

注意,声明队列的时候记得要选择队列的类型

image-20240514085623118

下图所示进行绑定

image-20240514090041526

  1. 在consumer服务中,编写两个消费者方法,分别监听fanout.queue1和fanout.queue2
@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg) throws InterruptedException {System.out.println("消费者1 收到了 fanout.queue1的消息:【" + msg +"】");
}@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg) throws InterruptedException {System.out.println("消费者2 收到了 fanout.queue2的消息:【" + msg +"】");
}
  1. 在publish中编写测试方法,向hmall.fanout发送消息
@Test
void testSendFanout() {String exchangeName = "hmall.fanout";String msg = "hello, everyone!";rabbitTemplate.convertAndSend(exchangeName, null, msg);
}
  1. 实现效果图

image-20240514090521259

3.2 Direct

目前希望发送的消息不是所有人都接收到,目前场景下我们会用到Direct交换机

比如,支付成功后,就要改变订单状态为已支付,支付失败的话需要将支将订单状态改为支付失败或者取消

对于交易服务,不论成功与失败,都需要给交易服务发送请求,进而修改订单状态

支付成功可能需要给用户发送短信通知,但是支付失败可能就不需要给用户发送短信通知了

相当于通知服务只监听支付成功的消息,而交易服务要监听支付成功、支付失败的消息

Direct Exchange会将接收到的消息根据规则路由到指定的Queue,因此称为定向路由

  • 每一个Queue都与Exchange设置一个BindingKey
  • 发布者发送消息时,指定消息的RoutingKey
  • Exchange将消息路由到BindingKey与消息RoutingKey一致的队列

image-20240514092038512

需求如下

  1. 在RabbitMQ控制台中,声明队列direct.queue1和direct.queue2

image-20240514092430115

  1. 在RabbitMQ控制台中,声明交换机hmall.direct,将两个队列与其绑定

image-20240514092525950

如下图所示,绑定的时候一次不能绑定两个key,所以一个队列有两个key的话,我们需要多次添加

image-20240514092656663

image-20240514092817730

  1. 在consumer服务中,编写两个消费者方法,分别监听direct.queue1和direct.queue2
@RabbitListener(queues = "direct.queue1")
public void listenDirectQueue1(String msg) throws InterruptedException {System.out.println("消费者1 收到了 direct.queue1的消息:【" + msg +"】");
}@RabbitListener(queues = "direct.queue2")
public void listenDirectQueue2(String msg) throws InterruptedException {System.out.println("消费者2 收到了 direct.queue2的消息:【" + msg +"】");
}
  1. 在publisher中编写测试方法,利用不同的RoutingKey向hmall.direct发送消息
@Test
void testSendDirect() {String exchangeName = "hmall.direct";String msg = "蓝色通知,警报解除,哥斯拉是放的气球";rabbitTemplate.convertAndSend(exchangeName, "blue", msg);
}
  1. 效果图

确实只有队列1收到

image-20240514093343102

3.3 Topic

Topic交换机和Direct交换机非常的像,都是通过RoutingKey来控制消息转发给谁,路由给谁

区别在于,Topic交换机的RoutingKey可以使多个单词的列表并且以“.”分割

china.news 代表有中国的新闻消息

china.weather 代表中国的天气消息

japan.news 则代表日本新闻

japan.weather 代表日本的天气消息

Queue与Exchange指定BindingKey时可以使用通配符

  • #:代指0个活多个单词
  • *:代指一个单词

image-20240514095244524

需求如下所示

image-20240514095405700

  1. 在RabbitMQ控制台中,声明队列topic.queue1和topic.queue2

image-20240514095741739

  1. 在RabbitMQ控制台中,声明交换机hmall.topic,将两个队列与其绑定

image-20240514095803832

image-20240514095919843

  1. 在consumer服务中,编写两个消费者方法,分别监听topic.queue1和topic.queue2
@RabbitListener(queues = "topic.queue1")
public void listenTopicQueue1(String msg) throws InterruptedException {System.out.println("消费者1 收到了 topic.queue1的消息:【" + msg +"】");
}@RabbitListener(queues = "topic.queue2")
public void listenTopicQueue2(String msg) throws InterruptedException {System.out.println("消费者2 收到了 topic.queue2的消息:【" + msg +"】");
}
  1. 在publisher中编写测试方法,利用不同的RoutingKey向hmall.topic发送消息
@Test
void testSendTopic() {String exchangeName = "hmall.topic";String msg = "今天天气挺不错,我的心情的挺好的";rabbitTemplate.convertAndSend(exchangeName, "china.weather", msg);rabbitTemplate.convertAndSend(exchangeName, "china.news", "中国的新闻");rabbitTemplate.convertAndSend(exchangeName, "japan.news", "日本新闻");
}
  1. 效果图

image-20240514100223246

四、声明队列和交换机

在控制台创建队列和交换机非常容易出错、效率极低,实际应该采用Java代码进行创建

SpringAMQP提供了几个类,用来声明队列、交换机及其绑定关系

  • Queue:用于声明队列,可以用工厂类QueueBuilder构建
  • Exchange:用于声明交换机,可以用工厂类ExchangeBuilder构建

因为交换机有许多的类型,所以ExchangeBuilder有多个实现类

image-20240514101059146

  • Binding:用于声明队列和交换机的绑定关系,可以用工厂类BindingBuilder构建

4.1 配置文件

在消费者方面声明队列和Fanout类型交换机

@Configuration
public class FanoutConfiguration {//声明FanoutExchange交换机import org.springframework.amqp.core.FanoutExchange;@Beanpublic FanoutExchange fanoutExchange() {// ExchangeBuilder.fanoutExchange("").build();return new FanoutExchange("hmall.fanout2");}//声明队列import org.springframework.amqp.core.Queue;@Beanpublic Queue fanoutQueue3() {// QueueBuilder.durable("ff").build(); durable是持久化,当前的队列是持久的队列 与下面new的形式相同return new Queue("fanout.queue3");}//将上面声明的队列和交换机绑定@Beanpublic Binding fanoutBinding3(Queue fanoutQueue3, FanoutExchange fanoutExchange) {//将哪个队列绑定到哪个交换机return BindingBuilder.bind(fanoutQueue3).to(fanoutExchange);}//声明队列@Beanpublic Queue fanoutQueue4() {return new Queue("fanout.queue4");}//绑定队列和交换机@Beanpublic Binding fanoutBinding4() {//将哪个队列绑定到哪个交换机//下面是直接调用了队列和交换机的方法进行绑定的//凡是加了Bean的方法都会被动态代理,当我们调用方法时,Spring首先会检查Spring容器中是否有对应的Bean//如果有的话,就不会执行方法中的任何内容,直接从容器中取出Bean对象即可,//如果没有,便执行方法注入Bean即可//所以说这里虽然是直接调用了fanoutQueue4()和fanoutExchange()方法,但是这两个方法也要有@Bean注解return BindingBuilder.bind(fanoutQueue4()).to(fanoutExchange());}
}

假如是Direct类型的交换机的话,就显得非常的麻烦

@Configuration
public class DirectConfiguration {//交换机@Beanpublic DirectExchange directExchange(){return new DirectExchange("hmall.direct");}//队列@Beanpublic Queue directQueue1(){return new Queue("direct.queue1");}//绑定hmall.direct交换机与directQueue1队列@Beanpublic Binding directQueue1BindingRed(Queue directQueue1, DirectExchange directExchange){return BindingBuilder.bind(directQueue1).to(directExchange).with("red");}//绑定hmall.direct交换机与directQueue1队列@Beanpublic Binding directQueue1BindingBlue(Queue directQueue1, DirectExchange directExchange){return BindingBuilder.bind(directQueue1).to(directExchange).with("blue");}@Beanpublic Queue directQueue2(){return new Queue("direct.queue2");}@Beanpublic Binding directQueue2BindingRed(Queue directQueue2, DirectExchange directExchange){return BindingBuilder.bind(directQueue2).to(directExchange).with("red");}@Beanpublic Binding directQueue2BindingBlue(Queue directQueue2, DirectExchange directExchange){return BindingBuilder.bind(directQueue2).to(directExchange).with("yellow");}}

4.2 注解

如下图所示,Direct交换机形式

@Slf4j
@Component
public class MqListener {@RabbitListener(bindings = @QueueBinding(//队列value = @Queue(name = "direct.queue1", durable = "true"),//交换机exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),//Routing keykey = {"red", "blue"}))public void listenDirectQueue1(String msg) throws InterruptedException {System.out.println("消费者1 收到了 direct.queue1的消息:【" + msg + "】");}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue2", durable = "true"),exchange = @Exchange(name = "hmall.direct", type = ExchangeTypes.DIRECT),key = {"red", "yellow"}))public void listenDirectQueue2(String msg) throws InterruptedException {System.out.println("消费者2 收到了 direct.queue2的消息:【" + msg + "】");}}

五、消息转换器

需求:测试利用SpringAMQP发送对象类型的消息

  1. 声明一个名为object.queue的队列

image-20240514110035568

  1. 编写测试单元,向队列中直接发送一条消息,消息类型为Map
    @Testvoid testSendObject() {Map<String, Object> msg = new HashMap<>(2);msg.put("name", "jack");msg.put("age", 21);//我们发送的是一个对象,Spring在接受这个对象的时候会将其转换成字节的形似rabbitTemplate.convertAndSend("object.queue", msg);}
  1. 在控制台查看消息

下种情况是因为Spring的对消息对象的处理是由org.springframework.amqp.support.converter.MessageConverter来处理的。而默认实现是SimpleMessageConverter,基于JDK的ObjectOutputStream完成序列化。

image-20240514110435176

  1. 建议采用JSON序列化替换默认的JDK序列化

  2. 在publisher和consumer中引入Jackson依赖

<!--Jackson-->
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId>
</dependency>
  1. 在publisher和consumer中都要配置MessageConverter

发布和接收都要有这段代码

@Bean
public MessageConverter jacksonMessageConvertor(){//import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;return new Jackson2JsonMessageConverter();
}
  1. 效果图

image-20240514111740634

相关文章:

2.RabbitMQ - 入门

RabbitMQ 入门 文章目录 RabbitMQ 入门一、快速入门1.1 介绍1.2 创建项目1.3 简单入门 二、Work模型三、交换机3.1 Fanout3.2 Direct3.3 Topic 四、声明队列和交换机4.1 配置文件4.2 注解 五、消息转换器 一、快速入门 1.1 介绍 官方的API较为麻烦&#xff0c;我们使用官方推…...

智能配送机器人控制系统设计

标题:智能配送机器人控制系统设计 内容:1.摘要 随着物流行业的快速发展&#xff0c;智能配送机器人的需求日益增长。本文的目的是设计一套高效、稳定的智能配送机器人控制系统。方法上&#xff0c;采用了先进的传感器技术、定位算法和路径规划策略&#xff0c;确保机器人能准确…...

2025.04.23华为机考第一题-100分

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 01. 星空探索者 问题描述 LYA是一位天文学爱好者,她拍摄了一张星空照片并将其数字化为二维亮度图。在这张图像中,每个像素点的值代表该位置的亮度。现在,LYA想要寻找特定亮度的星…...

MCP 基于 TypeScript 的完整示例,包含stdio、sse多种用法和调试,对于构建自己的API工具链很有用

typescript-mcp-demo 这是一个基于 Model Context Protocol (MCP) 的 TypeScript 示例项目&#xff0c;展示了如何创建一个简单的 MCP 服务器&#xff0c;包含基本的工具&#xff08;tools&#xff09;和资源&#xff08;resources&#xff09;功能。 官网&#xff1a;https:…...

【计算机视觉】CV项目实战- SORT 多目标跟踪算法

SORT 多目标跟踪算法&#xff1a;从原理到实战的完整指南 一、SORT算法核心解析1.1 算法架构1.2 关键技术组件 二、实战环境搭建2.1 基础环境配置2.2 数据准备 三、核心功能实战3.1 基础跟踪演示3.2 自定义检测器集成3.3 性能评估 四、高级应用与优化4.1 针对遮挡场景的改进4.2…...

常用第三方库精讲:cached_network_image图片加载优化

常用第三方库精讲&#xff1a;cached_network_image图片加载优化 在Flutter应用开发中&#xff0c;图片加载是一个非常重要的环节。合理的图片加载策略不仅能提升用户体验&#xff0c;还能优化应用性能。本文将深入讲解cached_network_image库的使用&#xff0c;以及如何通过它…...

xcode 16 遇到contains bitcode

问题 "id" : "xxx-xxx-xxx","status" : "409","code" : "STATE_ERROR.VALIDATION_ERROR","title" : "Validation failed","detail" : "Invalid Executable. The executable …...

MySQL数据库精研之旅第十期:打造高效联合查询的实战宝典(一)

专栏&#xff1a;MySQL数据库成长记 个人主页&#xff1a;手握风云 目录 一、简介 1.1. 为什么要使用联合查询 1.2. 多表联合查询时的计算 1.3. 示例 二、内连接 2.1. 语法 2.2. 示例 三、外连接 4.1. 语法 4.2. 示例 一、简介 1.1. 为什么要使用联合查询 一次查询需…...

Sentinel源码—9.限流算法的实现对比二

大纲 1.漏桶算法的实现对比 (1)普通思路的漏桶算法实现 (2)节省线程的漏桶算法实现 (3)Sentinel中的漏桶算法实现 (4)Sentinel中的漏桶算法与普通漏桶算法的区别 (5)Sentinel中的漏桶算法存在的问题 2.令牌桶算法的实现对比 (1)普通思路的令牌桶算法实现 (2)节省线程的…...

单片机外设模块汇总与介绍

一、基础外设 GPIO&#xff08;通用输入输出&#xff09; 功能&#xff1a;数字信号输入/输出&#xff0c;支持推挽、开漏模式。 应用&#xff1a;控制LED、按键检测、数字传感器接口。 配置要点&#xff1a; 输入模式&#xff1a;上拉/下拉电阻配置 输出模式&#xff1a;…...

git lfs下载大文件限额

起因是用 model.load_state_dict(torch.load())加载pt权重文件时&#xff0c;出现错误&#xff1a;_pickle.UnpicklingError: invalid load key, ‘v’. GPT告诉我&#xff1a;你的 pt 文件不是权重文件&#xff0c;而是模型整体保存&#xff08;或根本不是 PyTorch 文件&#…...

第4天:Linux开发环境搭建

&#x1f9f0; 第4天&#xff1a;Linux开发环境搭建 一、GCC 编译器 &#x1f4cc; 1. 什么是 GCC&#xff1f; GCC&#xff08;GNU Compiler Collection&#xff09;是 GNU 工程开发的编译器集合&#xff0c;主要支持 C、C、Fortran 等语言的编译&#xff0c;是 Linux 系统中…...

“在中国,为中国” 英飞凌汽车业务正式发布中国本土化战略

3月28日&#xff0c;以“夯实电动化&#xff0c;推进智能化&#xff0c;实现高质量发展”为主题的2025中国电动汽车百人会论坛在北京举办。众多中外机构与行业上下游嘉宾就全球及中国汽车电动化的发展现状、面临的挑战与机遇&#xff0c;以及在技术创新、市场布局、供应链协同等…...

【AI应用】免费代码仓构建定制版本的ComfyUI应用镜像

免费代码仓构建定制版本的ComfyUI应用镜像 1 创建代码仓1.1 注册登陆1.2 创建代码仓1.5 安装中文语言包1.4 拉取ComfyUI官方代码2 配置参数和预装插件2.1 保留插件和模型的版本控制2.2 克隆插件到代码仓2.2.1 下载插件2.2.2 把插件设置本仓库的子模块管理3 定制Docker镜像3.1 创…...

新市场环境下新能源汽车电流传感技术发展前瞻

新能源革命重构产业格局 在全球碳中和战略驱动下&#xff0c;新能源汽车产业正经历结构性变革。国际清洁交通委员会&#xff08;ICCT&#xff09;最新报告显示&#xff0c;2023年全球新能源汽车渗透率突破18%&#xff0c;中国市场以42%的市占率持续领跑。这种产业变革正沿着&q…...

ctfhub-RCE

关于管道操作符 windows&#xff1a; 1. “|”&#xff1a;直接执行后面的语句。 2. “||”&#xff1a;如果前面的语句执行失败&#xff0c;则执行后面的语句&#xff0c;前面的语句只能为假才行。 3. “&”&#xff1a;两条命令都执行&#xff0c;如果前面的语句为假则直…...

SSE(Server-Sent Events)技术详解:轻量级实时通信的全能方案

一、实时通信技术演进与SSE定位 1.1 主流实时通信技术对比 #mermaid-svg-1VQcZqAOmMoxosiW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-1VQcZqAOmMoxosiW .error-icon{fill:#552222;}#mermaid-svg-1VQcZqAOmMox…...

QT项目----电子相册(4)

文章目录 前言一、右侧区域PicShow1.创建PicShow2.创建PicButton3.效果图qss 4.设置动画QGraphicsOpacityEffectQPropertyAnimation 5.双击左侧图片目录 右侧显示图片解决缩放时卡顿的问题 二、删除相册实现思路代码实现 总结 前言 提示&#xff1a;这里可以添加本文要记录的大…...

Sentinel源码—9.限流算法的实现对比一

大纲 1.漏桶算法的实现对比 (1)普通思路的漏桶算法实现 (2)节省线程的漏桶算法实现 (3)Sentinel中的漏桶算法实现 (4)Sentinel中的漏桶算法与普通漏桶算法的区别 (5)Sentinel中的漏桶算法存在的问题 2.令牌桶算法的实现对比 (1)普通思路的令牌桶算法实现 (2)节省线程的…...

46. 全排列

题目 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&#xff1a; 输入&#xff1a…...

UML 顺序图:电子图书馆管理系统的交互之道

目录 一、初识 UML 顺序图 二、电子图书馆管理系统顺序图解析 &#xff08;一&#xff09;借阅流程 &#xff08;二&#xff09;归还流程 三、顺序图绘画 四、顺序图的优势与价值 五、总结 UML 顺序图是描绘系统组件交互的有力工具。顺序图直观展示消息传递顺序与对象协…...

前端渲染pdf文件解决方案-pdf.js

目录 一、前言 二、简介 1、pdf.js介绍 2、插件版本参数 三、通过viewer.html实现预览&#xff08;推荐&#xff09; 1、介绍 2、部署 【1】下载插件包 【2】客户端方式 【3】服务端方式&#xff08;待验证&#xff09; 3、使用方法 【1】预览PDF文件 【2】外部搜索…...

接口测试和功能测试详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 本文主要分为两个部分&#xff1a; 第一部分&#xff1a;主要从问题出发&#xff0c;引入接口测试的相关内容并与前端测试进行简单对比&#xff0c;总结两者…...

LeetCode热题100--283.移动零--简单

1.题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0]…...

CoT 数据集如何让大模型学会「一步一步思考」?

目前&#xff0c;大模型的回答路径基本遵循input-output的方式&#xff0c;在面对复杂任务时表现不佳。反之&#xff0c;人类会遵循一套有条理的思维流程&#xff0c;逐步推理得出正确答案。这种差异促使人们深入思考&#xff1a;如何才能让大模型“智能涌现”&#xff0c;学会…...

量子跃迁:Vue组件安全工程的基因重组与生态免疫(完全体)

总章数字免疫系统的解剖学革命 在2024年某国家级数字政务平台的安全审计中&#xff0c;传统前端架构暴露出的信任链断裂问题&#xff0c;导致公民隐私数据以每秒23TB的速度在暗网流通。当我们用PET扫描技术观察现代Web应用的微观结构&#xff0c;发现94.7%的安全威胁源自组件间…...

配置 Nginx 的 HTTPS

证书文件 文件名 作用 来源 example.com.key 服务器的私钥&#xff0c;用于加密和解密数据。 本地生成 -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAqp5c... -----END RSA PRIVATE KEY----- example.com.csr 证书签名请求文件&#xff0c;包含公钥和申请者信息&…...

FPGA开发流程初识

FPGA 的开发流程可知&#xff0c;在 FPGA 开发的过程中会产生很多不同功能的文件&#xff0c;为了方便随时查找到对应文件&#xff0c;所以在开始开发设计之前&#xff0c;我们第一个需要考虑的问题是工程内部各种文件的管理。如 果不进行文件分类&#xff0c;而是将所有文件…...

c++中的enum变量 和 constexpr说明符

author: hjjdebug date: 2025年 04月 23日 星期三 13:40:21 CST description: c中的enum变量 和 constexpr说明符 文章目录 1.Q:enum 类型变量可以有,--操作吗&#xff1f;1.1补充: c/c中enum的另一个细微差别. 2.Q: constexpr 修饰的函数,要求传入的参数必需是常量吗&#xff…...

JVM学习笔记

1、jvm概述 1.1、即时编译 为什么java没有c和c快 多了一层解释&#xff0c;而即时编译就是将热点数放入内存&#xff0c;下次执行的时候不用解释&#xff0c;提高了效率 1.2、常见的jvm jvm不止一个&#xff0c;意不意外&#xff1f;惊不惊喜&#xff1f; 1.3、hotspot的发展…...

AtCoder Beginner Contest 402题解

A - CBC 思路&#xff1a;仔细看这题其实就发现&#xff0c;我们只需要遍历一遍字符串把大写字母输出即可&#xff0c;很标准的签到题 #include<bits/stdc.h> using namespace std; #define int long longsigned main() {string s;cin>>s;for(char c:s){if(c>A…...

Rust 语言使用场景分析

1. 引言&#xff1a;Rust 语言概述 Rust 是一门专注于性能、内存安全和并发性的现代系统编程语言。自 2010 年由 Mozilla Research 的 Graydon Hoare 发起&#xff0c;并于 2015 年正式发布以来&#xff0c;Rust 凭借其独特的设计理念和强大的功能集&#xff0c;在技术领域迅速…...

HTTP 请求头的 key 不区分大小写。

详细说明 HTTP 协议规范 根据 RFC 7230&#xff0c;HTTP 头字段的名称&#xff08;即 key&#xff09;在传输时不区分大小写。例如&#xff0c;Content-Type 和 content-type 被视为相同的字段。 实际行为 客户端行为&#xff1a;大多数 HTTP 客户端&#xff08;如浏览器、cur…...

4.RabbitMQ - 延迟消息

RabbitMQ延迟消息 文章目录 RabbitMQ延迟消息一、延迟消息介绍二、实现2.1 死信交换机2.2 延迟消息插件2.3 取消超时订单 一、延迟消息介绍 延迟消息&#xff1a;生产者发送消息时指定一个时间&#xff0c;消费者不会立刻收到消息&#xff0c;而是在指定时间后才收到消息 用户…...

C++学习:六个月从基础到就业——STL算法(一) 基础与查找算法

C学习&#xff1a;六个月从基础到就业——STL算法&#xff08;一&#xff09; 基础与查找算法 本文是我C学习之旅系列的第二十五篇技术文章&#xff0c;也是第二阶段"C进阶特性"的第三篇&#xff0c;主要介绍C STL算法库的基础知识与查找类算法。查看完整系列目录了解…...

springboot+vue 支付宝支付(沙箱方式,测试环境使用)

准备工作&#xff1a; 1 支付宝沙箱环境的公钥&#xff0c;私钥配置&#xff0c;查询等使用&#xff0c;如果是用自定义的方式&#xff0c;需要下生成公钥&#xff0c;私钥的工具&#xff0c;否则不需要 登录 - 支付宝 小程序文档 - 支付宝文档中心 2 本地测试时&…...

安装win11自带linux是报错:WslRegisterDistribution failed with error: 0x800701bcErr

确保系统设置中的“打开win11的子系统”已打钩 管理员身份运行cmd&#xff0c;并输入如下 然后再重启ubantu...

面试经历(一)雪花算法

uid生成方面 1&#xff1a;为什么用雪花算法 分布式ID的唯一性需要保证&#xff0c;同时需要做到 1&#xff1a;单调递增 2&#xff1a;确保安全&#xff0c;一个是要能体现出递增的单号&#xff0c;二一个不能轻易的被恶意爬出订单数量 3&#xff1a;含有时间戳 4&#…...

docker底层原理简述

前言 平时用docker很多&#xff0c;今天深入了解下docker原理层面的实现&#xff0c;包括docker核心概念&#xff0c;文件系统&#xff0c;资源隔离&#xff0c;网络通信等 参考文章&#xff1a; Docker底层原理&#xff08;图解秒懂史上最全&#xff09; - 疯狂创客圈 - 博…...

【6D位姿估计】Foundation Pose复现

主要参考 项目仓库README站内其他博文 注意事项 容器化部署不难&#xff0c;主要是部署docker本身会存在一些环境问题&#xff0c;重点关注访问外网的端口需要手动调整至与魔法相同&#xff0c;可以参考&#xff1a; docker部署在启动容器镜像后&#xff0c;需要注意镜像当前…...

TDengine 数据订阅设计

简介 数据订阅作为 TDengine 的一个核心功能&#xff0c;为用户提供了灵活获取所需数据的能力。通过深入了解其内部原理&#xff0c;用户可以更加有效地利用这一功能&#xff0c;满足各种实时数据处理和监控需求。 基本概念 主题 与 Kafka 一样&#xff0c;使用 TDengine 数…...

VMware Fusion Pro 13 Mac版虚拟机 安装Win11系统教程

Mac分享吧 文章目录 Win11安装完成&#xff0c;软件打开效果一、VMware安装Windows11虚拟机1️⃣&#xff1a;准备镜像2️⃣&#xff1a;创建虚拟机3️⃣&#xff1a;虚拟机设置4️⃣&#xff1a;安装虚拟机5️⃣&#xff1a;解决连不上网问题 安装完成&#xff01;&#xff0…...

高并发下单库存扣减异常?飞算 JavaAI 自动化生成分布式事务解决方案

在电商、旅游等行业业务量激增&#xff0c;高并发下单场景中&#xff0c;传统库存扣减方式弊端尽显。超卖问题因缺乏有效并发控制机制频发&#xff0c;多个订单同时访问库存数据&#xff0c;导致同一商品多次售出&#xff0c;订单无法履约引发客户投诉&#xff1b;同时&#xf…...

crictl 遇到报错 /run/containerd/containerd.sock: connect: permission denied

报错内容 crictl --runtime-endpoint unix:///run/containerd/containerd.sock logs CONTAINERID FATA[0000] validate service connection: validate CRI v1 runtime API for endpoint "unix:///run/containerd/containerd.sock": rpc error: code Unavailable de…...

CSS外边距合并现象

外边距合并&#xff08;Margin Collapsing&#xff09;是指在文档流中&#xff0c;两个或多个相邻元素的外边距&#xff08;margin&#xff09;会合并为一个外边距&#xff0c;其大小会取其中最大的外边距值 当两个相邻的兄弟元素之间没有其他内容&#xff08;如边框、内边距、…...

《深度神经网络之数据增强、模型保存、模型调用、学习率调整》

文章目录 前言一、数据增强1、什么是数据增强&#xff1f;2、数据增强的实现方法&#xff08;1&#xff09;几何变换翻转:旋转&#xff1a;平移&#xff1a; &#xff08;2&#xff09;颜色变换亮度调整&#xff1a;对比度调整&#xff1a;色彩抖动&#xff1a; &#xff08;3&…...

【Java学习笔记】random的使用

random使用方法 使用说明&#xff1a;返回的是(0<n<1)这个范围中的任意带正号的double值 代码实例 public class helloworld{public static void main(String[] args){System.out.println(Math.random());} }生成0-100中的任意数代码示例 public class Main {public …...

Redis的string类型使用

第一步&#xff1a;添加缓存 以若依岗位代码为例 一&#xff1a;首先从redis中查询岗位信息&#xff0c;如果查询到了则直接返回。 二&#xff1a;如果redis中没有数据&#xff0c;则直接从数据库中查询。查询后放到redis并返回 package com.ruoyi.system.service.impl;imp…...

AIGC架构与原理

AIGC&#xff08;AI Generated Content&#xff0c;人工智能生成内容&#xff09;的架构与原理 AIGC通过整合数据采集、模型训练、推理服务等模块&#xff0c;结合深度学习与生成对抗网络&#xff08;GAN&#xff09;等技术&#xff0c;实现从数据到内容的自动化生成。 一、AIG…...

安全复健|windows常见取证工具

写在前面&#xff1a; 此博客仅用于记录个人学习内容&#xff0c;学识浅薄&#xff0c;若有错误观点欢迎评论区指出。欢迎各位前来交流。&#xff08;部分材料来源网络&#xff0c;若有侵权&#xff0c;立即删除&#xff09; 取证 01系统运行数据 使用工具&#xff1a;Live-F…...