10.RabbitMQ集群
十、集群与高可用
RabbitMQ 的集群分两种模式,一种是默认集群模式,一种是镜像集群模式;
在RabbitMQ集群中所有的节点(一个节点就是一个RabbitMQ的broker服务器) 被归为两类:一类是磁盘节点,一类是内存节点;
磁盘节点会把集群的所有信息(比如交换机、绑定、队列等信息)持久化到磁盘中,而内存节点只会将这些信息保存到内存中,如果该节点宕机或重启,内存节点的数据会全部丢失,而磁盘节点的数据不会丢失;
1、默认集群模式
默认集群模式也叫 普通集群模式、或者 内置集群模式;
10.1.1、默认集群简介
(1)、元数据
队列元数据:队列名称和属性(是否可持久化,是否自动删除)
交换器元数据:交换器名称、类型和属性
绑定元数据:交换器和队列的绑定列表
vhost元数据:vhost内的相关属性,如安全属性等;
当用户访问其中任何一个RabbitMQ节点时,查询到的queue/user/exchange/vhost等信息都是相同的;
(2)、数据同步特点
RabbitMQ默认集群模式只会把交换机、队列、虚拟主机等元数据信息在各个节点同步,而具体队列中的消息内容不会在各个节点中同步,队列的具体信息数据只在队列的拥有者节点保存,其他节点只知道队列的元数据和指向该节点的指针,所以其他节点接收到不属于该节点队列的消息时会将该消息传递给该队列的拥有者节点上;
集群不复制队列内容和状态到所有节点原因
1)节省存储空间;
2)提升性能;
如果消息需要复制到集群中每个节点,网络开销不可避免,持久化消息还需要写磁盘,占用磁盘空间。

(3)、数据访问过程
如果有一个消息生产者或者消息消费者通过amqp-client的客户端连接到节点1进行消息的发送或接收,那么此时集群中的消息收发只与节点1相关,这个没有任何问题;
如果消息生产者所连接的是节点2或者节点3,此时队列1的完整数据不在该两个节点上,那么在发送消息过程中这两个节点主要起了一个路由转发作用,根据这两个节点上的元数据(也就是指向queue的owner node的指针)转发至节点1上,最终发送的消息还是会存储至节点1的队列1上;
同样,如果消息消费者所连接的节点2或者节点3,那这两个节点也会作为路由节点起到转发作用,将会从节点1的队列1中获取消息进行消费;
10.1.2、安装
1、安装三台RabbitMQ机器
安装过程参考前面
注意:这里先安装一台MQ,然后克隆两台就可以了
2、设置IP地址
启动并设置三台机器的IP
修改配置文件方式
略
图形界面方式



3、修改主机名
sudo hostnamectl set-hostname rabbit11
4、修改/etc/hosts 文件
首先需要配置一下hosts文件,因为RabbitMQ集群节点名称是读取hosts文件得到的;
注意三台机机器都需要配置
vim /etc/hosts
192.168.1.11 rabbit11
192.168.1.12 rabbit12
192.168.1.13 rabbit13

5、重启网络
三台机器均重启网络,使节点名生效
sudo systemctl restart NetworkManager
低版本CentOS使用如下命令
systemctl restart network
6、重新连接xshell
重启后三台机器的xshell均退出,然后再重新连接,这样才能刷新主机的名字
7、关闭防火墙
三台机器均需关闭
systemctl stop firewalld ##关闭防火墙
systemctl disable firewalld ##开机不启动防火墙
systemctl status firewalld ##查看防火墙状态

8、修改.erlang.cookie文件
三台机器 .erlang.cookie文件保持一致
由于是clone出的三台机器,所以肯定是一样的
-
如果使用解压缩方式安装的RabbitMQ,那么该文件会在 用户名目录下 , 也就是 {用户名}目录下,也就是 用户名目录下,也就是{用户名}/.erlang.cookie;

-
如果使用rpm安装包方式进行安装,那么这个文件会在/var/lib/rabbitmq目录下;
注意 .erlang.cookie的权限为400,目前已经是400
9、启动MQ
分别启动三台机器上的rabbitmq
rabbitmq-server -detached
10、查看集群状态
-
查看rabbitmq状态
rabbitmqctl status
-
查看集群状态
rabbitmqctl cluster_status
11、构建集群
-
加入节点1
在rabbitmq12机器上执行命令,让12的rabbitmq加入集群
注意:一定要先停止节点,将节点重置之后才能加入集群,否则数据同步会出现混乱
## 先停止rabbitmq rabbitmqctl stop_app ## 重置rabbitmq rabbitmqctl reset ## 节点加入集群:rabbit@rabbit11是主节点的节点名,在集群状态中可以查看到节点名称 rabbitmqctl join_cluster rabbit@rabbit11 --ram ## 启动节点 rabbitmqctl start_app–ram 参数表示让rabbitmq12成为一个内存节点,如果不带参数默认为disk磁盘节点;

-
添加节点2
在rabbit13节点上也执行同样的命令,使rabbit13节点也加入到集群中
## 先停止rabbitmq rabbitmqctl stop_app ## 重置rabbitmq rabbitmqctl reset ## 节点加入集群:rabbit@rabbit11是主节点的节点名,在集群状态中可以查看到节点名称 rabbitmqctl join_cluster rabbit@rabbit11 --ram ## 启动节点 rabbitmqctl start_app当然也可以让rabbit13作为一个磁盘节点
12、添加用户和权限
操作一个节点,添加用户和权限等
#列出用户
rabbitmqctl list_users
# 添加用户
rabbitmqctl add_user admin 123456
#查看权限
rabbitmqctl list_permissions
#设置权限
rabbitmqctl set_permissions admin ".*" ".*" ".*"
#设置角色
rabbitmqctl set_user_tags admin administrator

13、启动web控制台
启动web控制台插件
注意:三台机器都要启动,因为插件不属于元数据,因此需要分别启动
#进入插件目录
cd /usr/local/rabbitmq_server-4.0.7/plugins/
#启动web端插件
rabbitmq-plugins enable rabbitmq_management

14、创建虚拟主机
使用web浏览器添加一个虚拟主机:longdidi

15、再次查看集群状态
当执行完操作以后在浏览器访问web管控台来看看效果;
随便在哪个节点打开web管控台都能看到集群环境各节点的信息;
也可以使用"rabbitmqctl cluster_status"查看集群状态;

以上就是RabbitMQ默认集群模式(普通集群模式)的搭建;
16、验证集群
- 创建队列

-
创建交换机

-
绑定交换机与队列
-
进入交换机

-
绑定交换机与队列

-
-
发布消息

-
查看消息
在任意节点查看消息

-
停止主节点rabbit@rabbit11节点

-
再在其它节点查看消息

17、删除节点

10.1.3、节点原理
RabbitMQ底层是通过Erlang架构来实现的,所以rabbitmqctl会启动Erlang节点,并基于Erlang节点来使用Erlang系统连接RabbitMQ节点,在连接过程中需要正确的Erlang Cookie和节点名称,Erlang节点通过交换Erlang Cookie以获得认证;
2、镜像集群模式
10.2.1、镜像模式简介
镜像模式是基于默认集群模式加上一定的配置得来的;
在默认模式下的RabbitMQ集群,它会把所有节点的交换机、绑定、队列的元数据进行复制确保所有节点都有一份相同的元数据信息
但是队列数据分为两种
- 一种是队列的元数据信息(比如队列的最大容量,队列的名称等配置信息)
- 一种是队列里面的消息
镜像模式则是把所有的队列数据完全同步,包括元数据信息和消息数据信息,当然这对性能肯定会有一定影响,当对数据可靠性要求较高时,可以使用镜像模式;
10.2.2、镜像模式配置
实现镜像模式也非常简单,它是在普通集群模式基础之上搭建而成的
3.X版本设置
镜像队列配置语法:
rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]
-
rabbitmqctl set_policy:固定写法
-
-p Vhost: 可选参数,设置虚拟主机的名字(针对指定vhost下的queue进行设置)
-
Name: 设置策略的名称(自己取个名字就可以)
-
Pattern: queue的匹配模式(正则表达式);^表示所有的队列都是镜像队列
-
Definition:镜像定义(json格式),包括三个部分ha-mode、ha-params、ha-sync-mode
-
ha-mode
指明镜像队列的模式,有效值为 all/exactly/nodes
all:表示在集群中所有的节点上进行镜像 exactly:表示在指定个数的节点上进行镜像,节点的个数由ha-params指定 nodes:表示在指定的节点上进行镜像,节点名称通过ha-params指定 -
ha-params
ha-mode模式需要用到的参数
-
ha-sync-mode
队列中消息的同步方式,有效值为automatic(自动向master同步数据)和manual(手动向master同步数据)
-
-
priority:可选参数,指的是policy策略的优先级;
在默认集群模式的基础上执行上面这个命令就可以把一个默认的集群模式变成镜像集群模式
比如想配置所有名字开头为policy_的队列进行镜像,镜像数量为2,那么命令如下(在任意节点执行如下命令):
rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]
rabbitmqctl set_policy -p longdidi my_policy "^policy_" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}'
(1)、同步所有数据
所有节点、所有虚拟主机、所有队列 都进行镜像
如果要在所有节点所有队列上进行镜像则在任意节点执行如下命令
语法:rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]
rabbitmqctl set_policy my-all "^" '{"ha-mode":"all"}'
(2)、同步指定数据
针对某个虚拟主机进行镜像
语法:rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]
rabbitmqctl set_policy -p longdidi my-all "^" '{"ha-mode": "exactly", "ha-params": 2, "ha-sync-mode": "automatic"}'
在默认集群模式的基础上执行上面这个命令就可以把一个默认的集群模式变成镜像集群模式
4.X版本设置

3、SpringBoot集成集群
重点连接配置
spring:rabbitmq:# 连接单台rabbitmq 服务器的地址# host: 192.168.1.101# 连接单台rabbitmq 服务器的端口# port: 5672username: adminpassword: 123456virtual-host: longdidipublisher-confirm-type: correlated # 开启生产者的确认模式,设置关联模式publisher-returns: true #开启return模式# 开启消费者手动确认listener:simple:acknowledge-mode: manualaddresses: 192.168.1.11:5672,192.168.1.12:5672,192.1.13:5672
测试模块:rabbitmq-10-cluster-01
引入依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency></dependencies>
配置MQ
server:port: 8080spring:application:name: cluster-learn01rabbitmq:# 连接单台rabbitmq 服务器的地址# host: 192.168.1.101# 连接单台rabbitmq 服务器的端口# port: 5672username: adminpassword: 123456virtual-host: longdidipublisher-confirm-type: correlated # 开启生产者的确认模式,设置关联模式publisher-returns: true #开启return模式# 开启消费者手动确认listener:simple:acknowledge-mode: manualaddresses: 192.168.1.11:5672,192.168.1.12:5672,192.1.13:5672data:redis:host: 192.168.1.4port: 6379#password: 123456database: 0 # 0号数据库
定义MQ队列
package com.longdidi.config;import com.longdidi.constants.RabbitMQConstant;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitConfig {/*** 正常交换机* 使用durable()方法设置持久化** @return*/@Beanpublic DirectExchange normalExchange() {return ExchangeBuilder.directExchange(RabbitMQConstant.EXCHANGE_NAME).durable(true).build();}/*** 正常队列* durable()方法就是持久化** @return*/@Beanpublic Queue normalQueue() {return QueueBuilder.durable(RabbitMQConstant.QUEUE_NAME1).build();}/*** 正常交换机和正常队列绑定** @param normalExchange* @param normalQueue* @return*/@Beanpublic Binding bindingNormal(DirectExchange normalExchange, Queue normalQueue) {return BindingBuilder.bind(normalQueue).to(normalExchange).with(RabbitMQConstant.ROUTING_NAME1);}}
生产者
package com.longdidi.service;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.longdidi.constants.RabbitMQConstant;
import com.longdidi.vo.Orders;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;import java.math.BigDecimal;
import java.util.Date;@Service
@Slf4j
public class SendMessageService {@Resourceprivate RabbitTemplate rabbitTemplate;//这个对象可以进行序列化和反序列化(json格式)@Resourceprivate ObjectMapper objectMapper;/*** 构造方法执行后自动执行*/@PostConstructpublic void init() {//开启生产者的确定模式rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {if (!ack) {log.error("消息没有到达交换机,原因为:{}", cause);//TODO 重发消息或者记录错误日志}});rabbitTemplate.setReturnsCallback(returnedMessage -> {log.error("消息没有从交换机正确的投递(路由)到队列,原因为:{}", returnedMessage.getReplyText());//TODO 记录错误日志,给程序员发短信或者或者邮件});}public void sendMsg() throws JsonProcessingException {{//创建订单Orders orders1 = Orders.builder().orderId("order_12345").orderName("买的手机").orderMoney(new BigDecimal(2356)).orderTime(new Date()).build();//转成jsonString strOrders1 = objectMapper.writeValueAsString(orders1);MessageProperties messageProperties = new MessageProperties();//设置单条消息的持久化,默认就是持久化messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);Message message = MessageBuilder.withBody(strOrders1.getBytes()).andProperties(messageProperties).build();rabbitTemplate.convertAndSend(RabbitMQConstant.EXCHANGE_NAME, RabbitMQConstant.ROUTING_NAME1, message);}{Orders orders2 = Orders.builder().orderId("order_12345").orderName("买的手机").orderMoney(new BigDecimal(2356)).orderTime(new Date()).build();String strOrders2 = objectMapper.writeValueAsString(orders2);MessageProperties messageProperties = new MessageProperties();//设置单条消息的持久化,默认就是持久化messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);Message message = MessageBuilder.withBody(strOrders2.getBytes()).andProperties(messageProperties).build();rabbitTemplate.convertAndSend(RabbitMQConstant.EXCHANGE_NAME, RabbitMQConstant.ROUTING_NAME1, message);}log.info("消息发送完毕,发送时间为:{}", new Date());}
}
消费者
package com.longdidi.service;import com.fasterxml.jackson.databind.ObjectMapper;
import com.longdidi.constants.RabbitMQConstant;
import com.longdidi.vo.Orders;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.io.IOException;import com.rabbitmq.client.Channel;@Component
@Slf4j
public class ReceiveMessageService {@Resourceprivate ObjectMapper objectMapper;@Resourceprivate StringRedisTemplate stringRedisTemplate;@RabbitListener(queues = {RabbitMQConstant.QUEUE_NAME1})public void receiveMsg(Message message, Channel channel) throws IOException {//获取消息的唯一标识long deliveryTag = message.getMessageProperties().getDeliveryTag();//使用objectmapper把字节数组反序列化成对象Orders orders = objectMapper.readValue(message.getBody(), Orders.class);try {log.info("接收到的消息为:{}", orders.toString());//如果不存在就在redis中存储Boolean setResult = stringRedisTemplate.opsForValue().setIfAbsent("idempotent:" + orders.getOrderId(), orders.getOrderId());if (setResult) {// TODO 向数据库插入订单等log.info("向数据库插入订单");}//手动确认channel.basicAck(deliveryTag, false);} catch (Exception e) {log.error("消息处理出现问题");try {channel.basicNack(deliveryTag, false, true);} catch (IOException ex) {throw new RuntimeException(ex);}throw new RuntimeException(e);}}
}
定义常量
package com.longdidi.constants;public class RabbitMQConstant {// 正常交换机public static final String EXCHANGE_NAME = "exchange.idempotent.normal.1";// 队列public static final String QUEUE_NAME1 = "queue.idempotent.normal.1";// 路由keypublic static final String ROUTING_NAME1 = "key.idempotent.normal.1";
}
定义实体类
package com.longdidi.vo;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Orders implements Serializable {private String orderId;private String orderName;private BigDecimal orderMoney;private Date orderTime; //下单时间
}
发送消息
package com.longdidi;import com.longdidi.service.SendMessageService;
import jakarta.annotation.Resource;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Rabbitmq10Cluster01Application implements ApplicationRunner {public static void main(String[] args) {SpringApplication.run(Rabbitmq10Cluster01Application.class, args);}@Resourceprivate SendMessageService sendMessageService;/*** 程序一启动就会运行该方法** @param args* @throws Exception*/@Overridepublic void run(ApplicationArguments args) throws Exception {sendMessageService.sendMsg();}
}
测试

相关文章:
10.RabbitMQ集群
十、集群与高可用 RabbitMQ 的集群分两种模式,一种是默认集群模式,一种是镜像集群模式; 在RabbitMQ集群中所有的节点(一个节点就是一个RabbitMQ的broker服务器) 被归为两类:一类是磁盘节点,一类是内存节点; 磁盘节点会把集群的所有信息(比如交换机、绑…...
Web网页开发——水果忍者
1.介绍 复刻经典小游戏——水果忍者 2.预览 3.代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&…...
信息安全访问控制、抗攻击技术、安全体系和评估(高软42)
系列文章目录 信息安全访问控制、抗攻击技术、安全体系和评估 文章目录 系列文章目录前言一、信息安全技术1.访问控制2.抗攻击技术 二、欺骗技术1.ARP欺骗2.DNS欺骗3.IP欺骗 三、抗攻击技术1.端口扫描2.强化TCP/IP堆栈 四、保证体系和评估1.保证体系2.安全风险管理 五、真题在…...
【算法】009、单双链表反转
【算法】009、单双链表反转 文章目录 一、单链表反转1.1 实现思路1.2 多语言解法 二、双链表反转2.1 实现思路2.2 多语言解法 一、单链表反转 1.1 实现思路 维护 pre 变量。 从前向后遍历 head,首先记录 next head.next,其次反转指针使 head.next pr…...
物联网设备接入系统后如何查看硬件实时数据?
要在软件中实时查看硬件设备的信息,通常需要结合前后端技术来实现。以下是设计思路和实现步骤: 1. 系统架构设计 实时查看硬件设备信息的系统通常采用以下架构: 数据采集层: 硬件设备通过传感器采集数据,发送到InfluxDB。数据存…...
【Linux系统编程】初识系统编程
目录 一、什么是系统编程1. 系统编程的定义2. 系统编程的特点3. 系统编程的应用领域4. 系统编程的核心概念5. 系统编程的工具和技术 二、操作系统四大基本功能1. 进程管理(Process Management)2. 内存管理(Memory Management)3. 文…...
解决stylelint对deep报错
报错如图 在.stylelintrc.json的rules中配置 "selector-pseudo-class-no-unknown": [true,{"ignorePseudoClasses": ["deep"]} ]...
React基础之useInperativehandlle
通过ref调用子组件内部的focus方法来实现聚焦 与forwardRef类似,但是forwardRef是通过暴露整个Ref来实现,而useInperativehandle是通过对外暴露一个方法来实现的 import { forwardRef, useImperativeHandle, useRef, useState } from "react";…...
使用joblib 多线程/多进程
文章目录 1. Joblib 并行计算的两种模式多进程(Multiprocessing,适用于 CPU 密集型任务)多线程(Multithreading,适用于 I/O 密集型任务)2. Joblib 的基本用法3. Joblib 多进程示例(适用于 CPU 密集型任务)示例:计算平方4. Joblib 多线程示例(适用于 I/O 密集型任务)…...
⭐算法OJ⭐N-皇后问题 II【回溯剪枝】(C++实现)N-Queens II
⭐算法OJ⭐N-皇后问题【回溯剪枝】(C实现)N-Queens 问题描述 The n-queens puzzle is the problem of placing n n n queens on an n n n \times n nn chessboard such that no two queens attack each other. Given an integer n, return the num…...
【数据结构初阶】---堆的实现、堆排序以及文件中的TopK问题
1.树的概念及结构 1.1树的概念 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 有一个特殊的结点&…...
ubuntu20系统下conda虚拟环境下安装文件存储位置
在 Conda 虚拟环境中执行 pip install 安装软件后,安装的文件会存储在该虚拟环境专属的 site-packages 目录中。具体路径取决于你激活的 Conda 环境路径。以下是定位步骤: 1. 确认 Conda 虚拟环境的安装路径 查看所有环境: conda info --env…...
鸿蒙开发:RelativeContainer 相对布局详解【全套华为认证学习资料分享(考试大纲、培训教材、实验手册等等)】
前言 在最新版本的 DevEco Studio 中,官方在创建新项目时,默认使用 RelativeContainer 组件作为根布局。这足以证明 RelativeContainer 的重要性。相比其他容器组件,它极大地简化了复杂 UI 布局中的元素对齐问题。 例如,在没有 R…...
基于SpringBoot实现旅游酒店平台功能一
一、前言介绍: 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高,旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求,旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上࿰…...
HttpServletRequest 和 HttpServletResponse 区别和作用
一、核心作用对比 对象HttpServletRequest(请求对象)HttpServletResponse(响应对象)本质客户端发给服务器的 HTTP 请求信息(输入)服务器返回客户端的 HTTP 响应信息(输出)生命周期一…...
树莓派学习(一)——3B+环境配置与多用户管理及编程实践
树莓派学习(一)——3B环境配置与多用户管理及编程实践 一、实验目的 掌握树莓派3B无显示器安装与配置方法。学习Linux系统下多用户账号的创建与管理。熟悉在树莓派上使用C语言和Python3编写简单程序的方法。 二、实验环境 硬件设备:树莓派…...
Mysql安装方式
方式一:安装包安装 下载安装包 官网直接下载:https://dev.mysql.com/downloads/ 安装配置 2.1、双击刚刚下载好的msi文件,开始安装MySQL。 2.2、选择自定义模式Custom安装 2.3、点击选择自己电脑对应的mysql安装目录 2.5、继续点击下一步&…...
Vue3实战学习(Vue3的基础语法学习与使用(超详细))(3)
目录 (1)Vue3工程环境准备、项目基础脚手架搭建详细教程。(博客链接) (2)Vue3的基础语法学习与使用。 (1)"{{}}"绑定数据。 <1>ref()函数定义变量——绑定数据。 <2>reactive({...})…...
使用websocket,注入依赖service的bean为null
问题:依赖注入失败,service获取不到,提示null 这是参考代码 package com.shier.ws;import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.google.gson.Gson; import com.s…...
批量在 Word 的指定位置插入页,如插入封面、末尾插入页面
我们经常会碰到需要在 Word 文档中插入新的页面的需求,比如在 Word 文档末尾插入一个广告页、给 Word 文档插入一个说明封面,在 Word 文档的中间位置插入新的页面等等。相信这个操作对于大部分小伙伴来说都不难,难的是同时给多个 Word 文档插…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
