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

RabbitMQ队列及交换机的使用

目录

一、简单模型

1、首先控制台创建一个队列

2、父工程导入依赖 

3、生产者配置文件

 4、写测试类

5、消费者配置文件

6、消费者接收消息

二、WorkQueues模型

1、在控制台创建一个新的队列

2、生产者生产消息

3、创建两个消费者接收消息

4、能者多劳充分利用每一个消费者的能力

三、交换机

四、Fanout交换机

1、 声明队列

2、 创建交换机

​编辑 3、 绑定交换机

4、示例 

五、Diect交换机

1、 声明队列

2、创建交换机

 3、绑定交换机

 4、示例

六、Topic交换机

1、创建队列

2、创建交换机 

3、绑定队列

4、示例

7、、声明队列交换机

1、SpringAMQP提供的类声明

2、基于注解声明

七、消息转换器

配置JSON转换器


一、简单模型

创建一个父工程和两个子工程consumer和publisher

1、首先控制台创建一个队列

命名为simple.queue

 

2、父工程导入依赖 

 <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></dependencies>

3、生产者配置文件

spring:rabbitmq:host: 192.168.200.129 # 你的虚拟机IPport: 5672 # 端口virtual-host: / # 虚拟主机username: admin # 用户名password: 123456 # 密码

 4、写测试类

@SpringBootTest
public class SpringAmqpTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void testSimpleQueue() {// 队列名称String queueName = "simple.queue";// 消息String message = "hello, rabbitmq!";// 发送消息rabbitTemplate.convertAndSend(queueName, message);}
}

 查看消息

 

5、消费者配置文件

spring:rabbitmq:host: 192.168.200.129 # 你的虚拟机IPport: 5672 # 端口virtual-host: / # 虚拟主机username: admin # 用户名password: 123456 # 密码

6、消费者接收消息

@Component
public class SpringRabbitListener {// 利用RabbitListener来声明要监听的队列信息// 将来一旦监听的队列中有了消息,就会推送给当前服务,调用当前方法,处理消息。// 可以看到方法体中接收的就是消息体的内容@RabbitListener(queues = "simple.queue")public void listenSimpleQueueMessage(String msg) throws InterruptedException {System.out.println("spring 消费者接收到消息:【" + msg + "】");}
}

 结果

二、WorkQueues模型

当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。 此时就可以使用work 模型,多个消费者共同处理消息处理,消息处理的速度就能大大提高了 

1、在控制台创建一个新的队列

命名为work.queue

2、生产者生产消息

/*** workQueue* 向队列中不停发送消息,模拟消息堆积。*/@Testpublic void testWorkQueue() throws InterruptedException {// 队列名称String queueName = "work.queue";// 消息String message = "hello, message_";for (int i = 0; i < 50; i++) {// 发送消息,每20毫秒发送一次,相当于每秒发送50条消息rabbitTemplate.convertAndSend(queueName, message + i);Thread.sleep(20);}}

3、创建两个消费者接收消息

  @RabbitListener(queues = "work.queue")public void listenWorkQueue1(String msg) throws InterruptedException {System.out.println("消费者1接收到消息:【" + msg + "】");}@RabbitListener(queues = "work.queue")public void listenWorkQueue2(String msg) throws InterruptedException {System.err.println("消费者2........接收到消息:【" + msg + "】");}

结果 

 

 如果消费者睡眠时间不同

 @RabbitListener(queues = "work.queue")public void listenWorkQueue1(String msg) throws InterruptedException {System.out.println("消费者1接收到消息:【" + msg + "】");Thread.sleep(20);}@RabbitListener(queues = "work.queue")public void listenWorkQueue2(String msg) throws InterruptedException {System.err.println("消费者2........接收到消息:【" + msg + "】");Thread.sleep(200);}
  • 消费者1 sleep了20毫秒,相当于每秒钟处理50个消息
  • 消费者2 sleep了200毫秒,相当于每秒处理5个消息

 

消息是平均分配给每个消费者,并没有考虑到消费者的处理能力。导致1个消费者空闲,另一个消费者忙的不可开交。没有充分利用每一个消费者的能力,最终消息处理的耗时远远超过了1秒。这样显然是有问题的。 

4、能者多劳充分利用每一个消费者的能力

在spring中有一个简单的配置,可以解决这个问题。我们修改consumer服务的application.yml文件,添加配置:

spring:rabbitmq:listener:simple:prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息

可以发现,由于消费者1处理速度较快,所以处理了更多的消息;消费者2处理速度较慢。而最终总的执行耗时也大大提升。 正所谓能者多劳,这样充分利用了每一个消费者的处理能力,可以有效避免消息积压问题。

三、交换机

在订阅模型中,多了一个exchange角色,而且过程略有变化:

  • Publisher:生产者,不再发送消息到队列中,而是发给交换机
  • Exchange:交换机,一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。
  • Queue:消息队列也与以前一样,接收消息、缓存消息。不过队列一定要与交换机绑定。
  • Consumer:消费者,与以前一样,订阅队列,没有变化

Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!

交换机的类型有四种:

  • Fanout:广播,将消息交给所有绑定到交换机的队列。我们最早在控制台使用的正是Fanout交换机
  • Direct:订阅,基于RoutingKey(路由key)发送给订阅了消息的队列
  • Topic:通配符订阅,与Direct类似,只不过RoutingKey可以使用通配符
  • Headers:头匹配,基于MQ的消息头匹配,用的较少。

四、Fanout交换机

Fanout,英文翻译是扇出,我觉得在MQ中叫广播更合适。 在广播模式下,消息发送流程是这样的:

 

  • 1)  可以有多个队列
  • 2)  每个队列都要绑定到Exchange(交换机)
  • 3)  生产者发送的消息,只能发送到交换机
  • 4)  交换机把消息发送给绑定过的所有队列
  • 5)  订阅队列的消费者都能拿到消息

1、 声明队列

 创建两个队列fanout.queue1fanout.queue2,绑定到交换机hmall.fanout

2、 创建交换机

创建一个名为fanout的交换机,类型是Fanout

 3、 绑定交换机

4、示例 

 生产者

/*** Fanout交换机*/@Testpublic void testFanoutExchange() {// 交换机名称String exchangeName = "mq.fanout";// 消息String message = "hello, everyone!";rabbitTemplate.convertAndSend(exchangeName, "", message);}

消费者

@RabbitListener(queues = "fanout.queue1")public void listenFanoutQueue1(String msg) {System.out.println("消费者1接收到Fanout消息:【" + msg + "】");}@RabbitListener(queues = "fanout.queue2")public void listenFanoutQueue2(String msg) {System.out.println("消费者2接收到Fanout消息:【" + msg + "】");}

 

五、Diect交换机

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

在Direct模型下:

  • 队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)
  • 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 RoutingKey
  • Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息 

1、 声明队列

首先在控制台声明两个队列direct.queue1direct.queue2

 

2、创建交换机

 

 3、绑定交换机

 一个队列绑定两个RoutingKey

 4、示例

生产者:RoutingKey为red

  /*** Direct交换机*/@Testpublic void testSendDirectExchange() {// 交换机名称String exchangeName = "mq.direct";// 消息String message = "hello direct red";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "red", message);}

消费者

@RabbitListener(queues = "direct.queue1")public void listenDirectQueue1(String msg) {System.out.println("消费者1接收到direct.queue1的消息:【" + msg + "】");}@RabbitListener(queues = "direct.queue2")public void listenDirectQueue2(String msg) {System.out.println("消费者2接收到direct.queue2的消息:【" + msg + "】");}

 两个队列都收到消息

RoutingKey为blue

 /*** Direct交换机*/@Testpublic void testSendDirectExchange() {// 交换机名称String exchangeName = "mq.direct";// 消息String message = "hello direct blue";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "blue", message);}

 只有队列2收到消息

六、Topic交换机

Topic类型的ExchangeDirect相比,都是可以根据RoutingKey把消息路由到不同的队列。 只不过Topic类型Exchange可以让队列在绑定BindingKey 的时候使用通配符!

BindingKey 一般都是有一个或多个单词组成,多个单词之间以.分割,例如: item.insert

通配符规则:

  • #:匹配一个或多个词
  • *:匹配不多不少恰好1个词

举例:

  • item.#:能够匹配item.spu.insert 或者 item.spu
  • item.*:只能匹配item.spu

 

 示例

publisher发送的消息使用的RoutingKey共有四种:

  • china.news 代表有中国的新闻消息;
  • china.weather 代表中国的天气消息;
  • japan.news 则代表日本新闻
  • japan.weather 代表日本的天气消息;

解释:

  • topic.queue1:绑定的是china.# ,凡是以 china.开头的routing key 都会被匹配到,包括:
    • china.news
    • china.weather
  • topic.queue2:绑定的是#.news ,凡是以 .news结尾的 routing key 都会被匹配。包括:
    • china.news
    • japan.news

1、创建队列

2、创建交换机 

3、绑定队列

 

4、示例

生产者:RoutingKey为china.news

 /*** topicExchange*/@Testpublic void testSendTopicExchange() {// 交换机名称String exchangeName = "mq.topic";// 消息String message = "hello topis china.news";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "china.news", message);}

消费者

  @RabbitListener(queues = "topic.queue1")public void listenTopicQueue1(String msg){System.out.println("消费者1接收到topic.queue1的消息:【" + msg + "】");}@RabbitListener(queues = "topic.queue2")public void listenTopicQueue2(String msg){System.out.println("消费者2接收到topic.queue2的消息:【" + msg + "】");}

 

 RoutingKey为china.people

 /*** topicExchange*/@Testpublic void testSendTopicExchange() {// 交换机名称String exchangeName = "mq.topic";// 消息String message = "hello topis china.people";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "china.people", message);}

只有消费者1收到消息 

7、、声明队列交换机

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

1、Queue:用于声明队列,可以用工厂类QueueBuilder构建
2、Exchange:用于声明交换机,可以用工厂类ExchangeBuilder构建
3、Binding:用于声明队列和交换机的绑定关系,可以用工厂类BindingBuilder构建

1、SpringAMQP提供的类声明

示例:创建Fanout交换机队列

@Configuration
public class FanoutConfig {/*** 声明交换机* @return Fanout类型交换机*/@Beanpublic FanoutExchange fanoutExchange2(){return new FanoutExchange("mq.fanout2");}/*** 第1个队列*/@Beanpublic Queue fanoutQueue3(){return new Queue("fanout.queue3");}/*** 绑定队列和交换机1*/@Beanpublic Binding bindingQueue1(Queue fanoutQueue3, FanoutExchange fanoutExchange3){return BindingBuilder.bind(fanoutQueue3).to(fanoutExchange3);}/*** 第2个队列*/@Beanpublic Queue fanoutQueue4(){return new Queue("fanout.queue4");}/*** 绑定队列和交换机2*/@Beanpublic Binding bindingQueue2(){return BindingBuilder.bind(fanoutQueue4()).to(fanoutExchange2());}
}

 direct示例

@Configuration
public class DirectConfig {/*** 声明交换机* @return Direct类型交换机*/@Beanpublic DirectExchange directExchange(){return ExchangeBuilder.directExchange("mq.direct2").build();}/*** 第1个队列*/@Beanpublic Queue directQueue1(){return new Queue("direct.queue1");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue1WithRed(Queue directQueue1, DirectExchange directExchange){return BindingBuilder.bind(directQueue1).to(directExchange).with("red");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue1WithBlue(Queue directQueue1, DirectExchange directExchange){return BindingBuilder.bind(directQueue1).to(directExchange).with("blue");}/*** 第2个队列*/@Beanpublic Queue directQueue2(){return new Queue("direct.queue2");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue2WithRed(Queue directQueue2, DirectExchange directExchange){return BindingBuilder.bind(directQueue2).to(directExchange).with("red");}/*** 绑定队列和交换机*/@Beanpublic Binding bindingQueue2WithYellow(Queue directQueue2, DirectExchange directExchange){return BindingBuilder.bind(directQueue2).to(directExchange).with("yellow");}
}

 direct模式由于要绑定多个KEY,会非常麻烦,每一个Key都要编写一个binding

2、基于注解声明

/*** 注解声明交换机* @param msg*/@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue3"),//队列名称exchange = @Exchange(name = "mq.direct", //交换机名称type = ExchangeTypes.DIRECT),//交换机类型key = {"red", "blue"}//RoutingKey))public void listenDirectQueue3(String msg){System.out.println("消费者3接收到direct.queue3的消息:【" + msg + "】");}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue4"),exchange = @Exchange(name = "mq.direct", type = ExchangeTypes.DIRECT),key = {"red", "yellow"}))public void listenDirectQueue4(String msg){System.out.println("消费者4接收到direct.queue4的消息:【" + msg + "】");}

 队列

 交换机

七、消息转换器

 @Testpublic void testSendMap() throws InterruptedException {// 准备消息Map<String,Object> msg = new HashMap<>();msg.put("name", "张三");msg.put("age", 21);// 发送消息rabbitTemplate.convertAndSend("object.queue", msg);}

当发送的数据为Objiet类型时会出现乱码现象,而在数据传输时,它会把你发送的消息序列化为字节发送给MQ,接收消息的时候,还会把字节反序列化为Java对象。 只不过,默认情况下Spring采用的序列化方式是JDK序列化

配置JSON转换器

publisherconsumer两个服务中都引入依赖:

 <dependencies><!--mq消息转换为json--><dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.10</version></dependency></dependencies>

注意:如果项目中引入了spring-boot-starter-web依赖,则无需再次引入Jackson依赖。

配置消息转换器,在publisherconsumer两个服务的启动类中添加一个Bean即可:

@Bean
public MessageConverter messageConverter(){// 1.定义消息转换器Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();// 2.配置自动创建消息id,用于识别不同消息,也可以在业务中基于ID判断是否是重复消息jackson2JsonMessageConverter.setCreateMessageIds(true);return jackson2JsonMessageConverter;
}

结果

 消费者接收Object

我们在consumer服务中定义一个新的消费者,publisher是用Map发送,那么消费者也一定要用Map接收,格式如下:

  @RabbitListener(queues = "object.queue")public void listenSimpleQueueMessage(Map<String, Object> msg) throws InterruptedException {System.out.println("消费者接收到object.queue消息:【" + msg + "】");}

 

相关文章:

RabbitMQ队列及交换机的使用

目录 一、简单模型 1、首先控制台创建一个队列 2、父工程导入依赖 3、生产者配置文件 4、写测试类 5、消费者配置文件 6、消费者接收消息 二、WorkQueues模型 1、在控制台创建一个新的队列 2、生产者生产消息 3、创建两个消费者接收消息 4、能者多劳充分利用每一个消…...

分布式唯一Id,它比GUID好

分布式唯一Id&#xff0c;它比GUID好 一、前言 分布式唯一Id&#xff0c;顾名思义&#xff0c;是指在全世界任何一台计算机上都不会重复的唯一Id。 在单机/单服务器/单数据库的小型应用中&#xff0c;不需要用到这类东西。但在高并发、海量数据、大型分布式应用中&#xff0c…...

计算机服务器中了勒索病毒怎么解决,勒索病毒解密流程,数据恢复

计算机服务器中了勒索病毒是一件非常令人头疼的事情&#xff0c;勒索病毒不仅会加密企业服务器中的数据&#xff0c;还会对企业计算机系统带来损害&#xff0c;严重地影响了企业的正常运转。最近&#xff0c;云天数据恢复中心工程师总结了&#xff0c;今年以来网络上流行的勒索…...

【NPM】vuex 数据持久化库 vuex-persistedstate

在 GitHub 上找到&#xff1a;vuex-persistedstate。 安装 npm install --save vuex-persistedstate使用 import { createStore } from "vuex"; import createPersistedState from "vuex-persistedstate";const store createStore({// ...plugins: [cr…...

英语——分享篇——每日200词——2601-2800

2601——resistant——[rɪzɪstənt]——adj.抵抗的——resistant——resi热死(拼音)st石头(拼音)ant蚂蚁(熟词)——热死了石头上的蚂蚁还在抵抗——The body may be less resistant if it is cold. ——天冷时&#xff0c;身体的抵抗力会下降。 2602——prospect——[prɒspe…...

SpringCloud-Sentinel

一、介绍 &#xff08;1&#xff09;提供界面配置配置服务限流、服务降级、服务熔断 &#xff08;2&#xff09;SentinelResource的blockHandler只处理后台配置的异常&#xff0c;运行时异常fallBack处理&#xff0c;且资源名为value时才生效&#xff0c;走兜底方法 二、安装…...

为什么索引要用B+树来实现呢,而不是B树

首先&#xff0c;常规的数据库存储引擎&#xff0c;一般都是采用 B 树或者 B树来实现索引的存储。 B树 因为 B 树是一种多路平衡树&#xff0c;用这种存储结构来存储大量数据&#xff0c;它的整个高度会相比二叉树来说&#xff0c;会矮很多。 而对于数据库来说&#xff0c;所有…...

使用vue3前端开发的一些知识点

Vue 3 是一种流行的 JavaScript 框架&#xff0c;用于构建用户界面。它是 Vue.js 框架的第三个主要版本&#xff0c;具有许多新特性和性能改进。下面是 Vue 3 的一些常用语法和概念的详细介绍&#xff1a; 创建 Vue 实例&#xff1a; 在 Vue 3 中&#xff0c;你可以通过创建一个…...

零基础Linux_20(进程信号)内核态和用户态+处理信号+不可重入函数+volatile

目录 1. 内核态和用户态 1.1 内核态和用户态概念 1.2 内核态和用户态转化 2. 处理信号 2.2 捕捉信号 2.2 系统调用sigaction 3. 不可重入函数 4. volatile关键字 5. SIGCHLD信号&#xff08;了解&#xff09; 6. 笔试选择题 答案及解析 本篇完。 1. 内核态和用户态…...

vite+vue3+elementPlus+less+router+pinia+axios

1.创建项目2.按需引入elementplus3.引入less安装vue-router安装 axios安装 piniapinia的持久化配置(用于把数据放在localStorage中)---另外增加的配置 1.创建项目 npm init vitelatest2.按需引入elementplus npm install element-plus --save//按需引入 npm install -D unpl…...

VMwarePlayer安装Ubuntu,切换中文并安装中文输入法

1.下载和安装 虚拟机使用的免费版官网链接&#xff1a;VMwarePlayer Ubuntu镜像下载官网链接&#xff1a;Ubuntu桌面版 自己学习使用&#xff0c;不需要考虑迁移之类的。选择单个磁盘IO性能会更高 安装过程中如果出现如下报错&#xff0c;则用系统管理员身份运行 右击VMwa…...

C# JSON转为实体类和List,以及结合使用

引用 using Newtonsoft.Json;using Newtonsoft.Json.Linq;JSON转实体类 public class Person {public string Name { get; set; }public int Age { get; set; }public string Gender { get; set; } }string jsonStr "{\"name\": \"Tom\", \"a…...

使用TensorRT-LLM进行高性能推理

LLM的火爆之后&#xff0c;英伟达(NVIDIA)也发布了其相关的推理加速引擎TensorRT-LLM。TensorRT是nvidia家的一款高性能深度学习推理SDK。此SDK包含深度学习推理优化器和运行环境,可为深度学习推理应用提供低延迟和高吞吐量。而TensorRT-LLM是在TensorRT基础上针对大模型进一步…...

怎么去别人的github工程下载

1、网络 确保网络能够顺利访问github&#xff0c;有的地方的公共网络不能访问github&#xff0c;我之前开过科学上网的会员&#xff0c;发现没必要特意开去访问它。可以直接开手机热点&#xff0c;一般是可以顺利访问的。 2、下载 以我的github开源笔记qq-hh/C_review (gith…...

【java基础-实战3】list遍历时删除元素的方法

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 在实际的业务开发中&#xff0c;容器的遍历可以说是非…...

云计算与云服务

云计算与云服务 1、云计算与云服务概述2、云服务模式(IaaS、PaaS、SaaS、DaaS)3、公有云、私有云和混合云1、云计算与云服务概述 什么是云计算? “云”实质上就是一个网络,狭义上讲,云计算就是一种提供资源的网络,使用者可以随时获取“云”上的资源,按需求量使用,并且…...

Ubuntu20.4 设置代理

主要是涉及2个代理 涉及apt 可以在、/etc/apt/apt.conf 中进行修改 在系统全局可以在/etc/profile中进行修改...

RustDay06------Exercise[71-80]

71.box的使用 说实话这题没太看懂.敲了个模板跟着提示就过了 // box1.rs // // At compile time, Rust needs to know how much space a type takes up. This // becomes problematic for recursive types, where a value can have as part of // itself another value of th…...

Leetcode—2525.根据规则将箱子分类【简单】

2023每日刷题&#xff08;五&#xff09; Leetcode—2525.根据规则将箱子分类 实现代码 char * categorizeBox(int length, int width, int height, int mass){long long volume;long long len (long long)length;long long wid (long long)width;long long heig (long lo…...

RustDay05------Exercise[51-60]

51.使用?当作错误处理符 ? 是 Rust 中的错误处理操作符。通常用于尝试解析或执行可能失败的操作&#xff0c;并在出现错误时提前返回错误&#xff0c;以避免程序崩溃或出现未处理的错误。 具体来说&#xff0c;? 用于处理 Result 或 Option 类型的返回值。 // errors2.rs…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...

若依项目部署--传统架构--未完待续

若依项目介绍 项目源码获取 #Git工具下载 dnf -y install git #若依项目获取 git clone https://gitee.com/y_project/RuoYi-Vue.git项目背景 随着企业信息化需求的增加&#xff0c;传统开发模式存在效率低&#xff0c;重复劳动多等问题。若依项目通过整合主流技术框架&…...

C++ Saucer 编写Windows桌面应用

文章目录 一、背景二、Saucer 简介核心特性典型应用场景 三、生成自己的项目四、以Win32项目方式构建Win32项目禁用最大化按钮 五、总结 一、背景 使用Saucer框架&#xff0c;开发Windows桌面应用&#xff0c;把一个html页面作为GUI设计放到Saucer里&#xff0c;隐藏掉运行时弹…...

项目研究:使用 LangGraph 构建智能客服代理

概述 本教程展示了如何使用 LangGraph 构建一个智能客服代理。LangGraph 是一个强大的工具&#xff0c;可用于构建复杂的语言模型工作流。该代理可以自动分类用户问题、分析情绪&#xff0c;并根据需要生成回应或升级处理。 背景动机 在当今节奏飞快的商业环境中&#xff0c…...

【异常】极端事件的概率衰减方式(指数幂律衰减)

在日常事件中,极端事件的概率衰减方式并非单一模式,而是取决于具体情境和数据生成机制。以下是科学依据和不同衰减形式的分析: 1. 指数衰减(Exponential Decay) 典型场景:当事件服从高斯分布(正态分布)或指数分布时,极端事件的概率呈指数衰减。 数学形式:概率密度函数…...

node 进程管理工具 pm2 的详细说明 —— 一步一步配置 Ubuntu Server 的 NodeJS 服务器详细实录 7

前言 我以 Ubuntu Server 打造的 NodeJS 服务器为主题的系列文章&#xff0c;经过五篇博客&#xff0c;我们顺利的 安装了 ubuntu server 服务器&#xff0c;并且配置好了 ssh 免密登录服务器&#xff0c;安装好了 服务器常用软件安装, 配置好了 zsh 和 vim 以及 通过 NVM 安装…...

【docker】Windows安装docker

环境及工具&#xff08;点击下载&#xff09; Docker Desktop Installer.exe &#xff08;windows 环境下运行docker的一款产品&#xff09; wsl_update_x64 &#xff08;Linux 内核包&#xff09; 前期准备 系统要求2&#xff1a; Windows 11&#xff1a;64 位系统&am…...

OGG-01635 OGG-15149 centos服务器远程抽取AIX oracle11.2.0.4版本

背景描述 有一套ogg远程抽取的环境&#xff0c;源端是AIX7.1环境的oracle 11.2.0.4版本的数据库&#xff0c;中间是OGG抽取服务器&#xff0c;目标端是centos 7.9环境的oracle 19c。 采用集成模式远程抽取源端数据正常&#xff0c;但是经典模式远程抽取源数据的时候抽取进程启…...

【五子棋在线对战】三.数据管理模块实现

数据管理模块实现 1.数据库表的设计2.数据管理模块的封装和实现2.1 user_table() && ~user_table()2.2 insert() 注册时新增用户2.3 login() 登录验证&#xff0c;并返回详细的用户信息2.4 通过用户名获取用户信息 && 通过用户id获取用户信息2.5 win() &&a…...

《校园生活平台从 0 到 1 的搭建》第一篇:创建项目与构建目录结构

在本系列第一篇中&#xff0c;我们将从项目初始化开始&#xff0c;搭建基本的目录结构&#xff0c;并完成四个主页面的创建与 TabBar 设置。 &#xff08;tip&#xff1a;你可能会觉得有点 ai 化&#xff0c;因为这个文案是我自己写了一遍文案之后让 ai 去优化输出的&#xff0…...