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

RabbitMQ安装配置,封装工具类,发送消息及监听

1. Get-Started

docker安装rabbitmq

  1. 拉取镜像
[root@heima ~]# docker pull rabbitmq:3.8-management
3.8-management: Pulling from library/rabbitmq
7b1a6ab2e44d: Pull complete 
37f453d83d8f: Pull complete 
e64e769bc4fd: Pull complete 
c288a913222f: Pull complete 
13adc5da62c6: Pull complete 
bd67e639afcb: Pull complete 
9a48b5ad2519: Pull complete 
1cdfc59624be: Pull complete 
8f5ad79f0ad6: Pull complete 
Digest: sha256:543f7268600a27a39e2fdd532f8df479636fc0cf528aadde88d5fe718bed71e4
Status: Downloaded newer image for rabbitmq:3.8-management
docker.io/library/rabbitmq:3.8-management
  1. 创建目录
mkdir -p /home/apps/rabbitmq/data
  1. 运行容器
docker run \
-d \
--name rabbitmq \
--restart=always \
--privileged=true \
-p 5672:5672 \
-p 15672:15672 \
-v /home/apps/rabbitmq/data:/var/lib/rabbitmq \
-e RABBITMQ_DEFAULT_VHOST=vhost0 \
-e RABBITMQ_DEFAULT_USER=admin \
-e RABBITMQ_DEFAULT_PASS=admin123 \
rabbitmq:3.8-management
  1. 启用web界面管理插件
docker exec -it rabbitmq rabbitmq-plugins enable rabbitmq_management
或
-- 进入容器
docker exec -it rabbitmq /bin/bash
-- 安装插件
rabbitmq-plugins enable rabbitmq_management
  1. 浏览器访问 http://虚拟机ip:15672/出现以下界面说明安装成功。

在这里插入图片描述
输入上面在初始化Rabbitmq容器时我们自己指定了默认账号和密码:admin/admin123,如果没有指定的话那么rabbitmq的默认账号密码是:guest/guest

扩展安装延迟队列

  • 去官网下载插件(v3.8.17)
  • 地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases
# 将下载好的插件复制到mq容器内部
docker cp rabbitmq_delayed_message_exchange-3.8.17.8f537ac.ez rabbitmq:/plugins# 进入mq容器
docker exec -it rabbitmq /bin/bash# 开启插件支持 
rabbitmq-plugins enable rabbitmq_delayed_message_exchange# 查看插件列表
rabbitmq-plugins list

2. 生产者模块

2.1 项目引入依赖:

rabbitmq依赖包,使用RabbitMq这2个依赖就够了。

<dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-amqp</artifactId><scope>provided</scope>
</dependency>
<dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit</artifactId><scope>provided</scope>
</dependency>

封装工具类用到的包

<!--hutool工具包-->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.17</version>
</dependency>

2.2 工具类

  • RabbitMqHelper
import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
public class RabbitMqHelper {public static final String REQUEST_ID_HEADER = "requestId";private final RabbitTemplate rabbitTemplate;private final MessagePostProcessor processor = new BasicIdMessageProcessor();private final ThreadPoolTaskExecutor executor;public RabbitMqHelper(RabbitTemplate rabbitTemplate) {this.rabbitTemplate = rabbitTemplate;executor = new ThreadPoolTaskExecutor();//配置核心线程数executor.setCorePoolSize(10);//配置最大线程数executor.setMaxPoolSize(15);//配置队列大小executor.setQueueCapacity(99999);//配置线程池中的线程的名称前缀executor.setThreadNamePrefix("mq-async-send-handler");// 设置拒绝策略:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//执行初始化executor.initialize();}/*** 根据exchange和routingKey发送消息*/public <T> void send(String exchange, String routingKey, T t) {log.debug("准备发送消息,exchange:{}, RoutingKey:{}, message:{}", exchange, routingKey, t);// 1.设置消息标示,用于消息确认,消息发送失败直接抛出异常,交给调用者处理String id = UUID.randomUUID().toString(true);CorrelationData correlationData = new CorrelationData(id);// 2.设置发送超时时间为500毫秒rabbitTemplate.setReplyTimeout(500);// 3.发送消息,同时设置消息idrabbitTemplate.convertAndSend(exchange, routingKey, t, processor, correlationData);}/*** 根据exchange和routingKey发送消息,并且可以设置延迟时间*/public <T> void sendDelayMessage(String exchange, String routingKey, T t, Duration delay) {// 1.设置消息标示,用于消息确认,消息发送失败直接抛出异常,交给调用者处理String id = UUID.randomUUID().toString(true);CorrelationData correlationData = new CorrelationData(id);// 2.设置发送超时时间为500毫秒rabbitTemplate.setReplyTimeout(500);// 3.发送消息,同时设置消息idrabbitTemplate.convertAndSend(exchange, routingKey, t, new DelayedMessageProcessor(delay), correlationData);}/*** 根据exchange和routingKey 异步发送消息,并指定一个延迟时间** @param exchange   交换机* @param routingKey 路由KEY* @param t          数据* @param <T>        数据类型*/public <T> void sendAsync(String exchange, String routingKey, T t, Long time) {String requestId = MDC.get(REQUEST_ID_HEADER);CompletableFuture.runAsync(() -> {try {MDC.put(REQUEST_ID_HEADER, requestId);// 发送延迟消息if (time != null && time > 0) {sendDelayMessage(exchange, routingKey, t, Duration.ofMillis(time));} else {send(exchange, routingKey, t);}} catch (Exception e) {log.error("推送消息异常,t:{},", t, e);}}, executor);}/*** 根据exchange和routingKey 异步发送消息** @param exchange   交换机* @param routingKey 路由KEY* @param t          数据* @param <T>        数据类型*/public <T> void sendAsync(String exchange, String routingKey, T t) {sendAsync(exchange, routingKey, t, null);}
}
  • MqConfig
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.MDC;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.ContainerCustomizer;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;@Configuration
@ConditionalOnClass(value = {MessageConverter.class, AmqpTemplate.class})
public class MqConfig implements EnvironmentAware{public static final String REQUEST_ID_HEADER = "requestId";public static final String ERROR_EXCHANGE = "error.topic";public static final String ERROR_KEY_PREFIX = "error.";public static final String ERROR_QUEUE_TEMPLATE = "error.{}.queue";private String defaultErrorRoutingKey;private String defaultErrorQueue;@Bean(name = "rabbitListenerContainerFactory")@ConditionalOnProperty(prefix = "spring.rabbitmq.listener", name = "type", havingValue = "simple",matchIfMissing = true)SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory,ObjectProvider<ContainerCustomizer<SimpleMessageListenerContainer>> simpleContainerCustomizer) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();configurer.configure(factory, connectionFactory);simpleContainerCustomizer.ifUnique(factory::setContainerCustomizer);factory.setAfterReceivePostProcessors(message -> {Object header = message.getMessageProperties().getHeader(REQUEST_ID_HEADER);if(header != null) {MDC.put(REQUEST_ID_HEADER, header.toString());}return message;});return factory;}@Beanpublic MessageConverter messageConverter(ObjectMapper mapper){// 1.定义消息转换器Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(mapper);// 2.配置自动创建消息id,用于识别不同消息jackson2JsonMessageConverter.setCreateMessageIds(true);return jackson2JsonMessageConverter;}/*** <h1>消息处理失败的重试策略</h1>* 本地重试失败后,消息投递到专门的失败交换机和失败消息队列:error.queue*/@Bean@ConditionalOnClass(MessageRecoverer.class)@ConditionalOnMissingBeanpublic MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){// 消息处理失败后,发送到错误交换机:error.direct,RoutingKey默认是error.微服务名称return new RepublishMessageRecoverer(rabbitTemplate, ERROR_EXCHANGE, defaultErrorRoutingKey);}/*** rabbitmq发送工具**/@Bean@ConditionalOnMissingBean@ConditionalOnClass(RabbitTemplate.class)public RabbitMqHelper rabbitMqHelper(RabbitTemplate rabbitTemplate){return new RabbitMqHelper(rabbitTemplate);}/*** 专门接收处理失败的消息*/@Beanpublic DirectExchange errorMessageExchange(){return new DirectExchange(ERROR_EXCHANGE);}@Beanpublic Queue errorQueue(){return new Queue(defaultErrorQueue, true);}@Beanpublic Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange){return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with(defaultErrorRoutingKey);}@Overridepublic void setEnvironment(Environment environment) {String appName = environment.getProperty("spring.application.name");this.defaultErrorRoutingKey = ERROR_KEY_PREFIX + appName;this.defaultErrorQueue = StrUtil.format(ERROR_QUEUE_TEMPLATE, appName);}
}
  • Processor
import cn.hutool.core.lang.UUID;
import org.slf4j.MDC;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;public class BasicIdMessageProcessor implements MessagePostProcessor {public static final String REQUEST_ID_HEADER = "requestId";@Overridepublic Message postProcessMessage(Message message) throws AmqpException {String requestId = MDC.get(REQUEST_ID_HEADER);if (requestId == null) {requestId = UUID.randomUUID().toString(true);}// 写入RequestID标示message.getMessageProperties().setHeader(REQUEST_ID_HEADER, requestId);return message;}
}----------------------------------------------------------------------import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import java.time.Duration;public class DelayedMessageProcessor extends BasicIdMessageProcessor {private final long delay;public DelayedMessageProcessor(Duration delay) {this.delay = delay.toMillis();}@Overridepublic Message postProcessMessage(Message message) throws AmqpException {// 1.添加消息idsuper.postProcessMessage(message);// 2.添加延迟时间message.getMessageProperties().setHeader("x-delay", delay);return message;}
}

2.3 配置

通常mq是放在common模块中,别的模块需要mq时就引入该模块,因此需要把MqConfig放在IOC容器里加载。

  • resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.tianji.common.autoconfigure.mq.MqConfig

配置rabbitmq的地址等信息

  • boostrap.yml
spring:rabbitmq:host: ${mydemo.mq.host:192.168.150.101}port: ${mydemo.mq.port:5672}virtual-host: ${mydemo.mq.vhost:/vhost0}username: ${mydemo.mq.username:admin}password: ${mydemo.mq.password:admin123}listener:simple:retry:enabled: ${mydemo.mq.listener.retry.enable:true} # 开启消费者失败重试initial-interval: ${mydemo.mq.listener.retry.interval:1000ms} # 初始的失败等待时长为1秒multiplier: ${mydemo.mq.listener.retry.multiplier:2} # 失败的等待时长倍数,下次等待时长 = multiplier * last-intervalmax-attempts: ${mydemo.mq.listener.retry.max-attempts:3} # 最大重试次数stateless: ${mydemo.mq.listener.retry.stateless:true} # true无状态;false有状态。如果业务中包含事务,这里改为false

2.4 测试文件

TestController

@RestController
public class TestController {@AutowiredRabbitMqHelper rabbitMqHelper;@GetMapping("/hello")public String hello(){return "hello";}@GetMapping("/sendMsg")public String sendMsg(){rabbitMqHelper.send("order.topic", // "order.topic""order.pay", // "order.pay"UserDto.builder().id(10001).name("gz").age(23).phone("15500000001").email("123@qq.com").build());return "success";}
}

UserDto

import lombok.Builder;
import lombok.Data;@Data
@Builder
public class UserDto {private Integer id;private String name;private String phone;private Integer age;private String email;
}

2.5 生产者测试

生产者模块目录结构
在这里插入图片描述

启动生产者服务,访问http://127.0.0.1:8080/sendMsg
在这里插入图片描述报错了,原因是没有消费者消费消息
但是发现创建了新的错误消息exchange和queue
在这里插入图片描述
因此,接下来创建消费者监听消息。

3. 消费者

3.1 引入通用模块

由于消费者也需要使用刚刚的工具类和UserDto用来接收消息。
在这里插入图片描述
而这些工具类和UserDto都在模块rabbitmq-demo中。因此,在消费者模块中引入该生产者模块(如果这些通用的配置和实体类dto都在一个通用的模块common中,哪些模块需要发送消息,哪些模块需要监听消息,就都引入common模块就行了)

    <groupId>com.gzdemo</groupId><artifactId>rabbitmq-demo</artifactId><version>1.0-SNAPSHOT</version>

因为rabbitmq-demo模块中已经引入了RabbitMq相关依赖,因此消费者模块不需要重复引入RabbitMq相关的依赖。只需要把依赖包添加到classpath下,再import就行了
在这里插入图片描述
在这里插入图片描述

3.2 配置yml

与生产者的配置相同,通常只有消费者才需要配置listener,生产者不需要。
在这里插入图片描述

3.3 编写listener

import com.gzdemo.rabbitmq.pojos.UserDto;import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class UserListener {/*** 监听消息*/@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "learning.lesson.pay.queue", durable = "true"),exchange = @Exchange(name = "order.topic", type = ExchangeTypes.TOPIC),key = "order.pay"))public void listenLessonPay(UserDto userDto){System.out.println(userDto);}
}

3.4 消费者目录结构

这里是随便找了个同工程中的子模块作为消费者测试,在UserListener类中监听消息
在这里插入图片描述

4 测试消息发送、监听

启动这两个服务,浏览器访问http://127.0.0.1:8080/sendMsg,多访问几次后发现消费者接收到了消息
在这里插入图片描述生产者console

2024-06-14 05:46:39.187  INFO 106168 --- [nio-8080-exec-1] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: [192.168.150.101:5672]
2024-06-14 05:46:39.210  INFO 106168 --- [nio-8080-exec-1] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory#399d82:0/SimpleConnection@1673b17 [delegate=amqp://admin@192.168.150.101:5672/vhost0, localPort= 61317]

相关文章:

RabbitMQ安装配置,封装工具类,发送消息及监听

1. Get-Started docker安装rabbitmq 拉取镜像 [rootheima ~]# docker pull rabbitmq:3.8-management 3.8-management: Pulling from library/rabbitmq 7b1a6ab2e44d: Pull complete 37f453d83d8f: Pull complete e64e769bc4fd: Pull complete c288a913222f: Pull complet…...

iOS接入Flutter

在现有的iOS项目上接入Flutter&#xff0c;参考链接 第一步&#xff1a;创建flutter项目&#xff0c;即 创建 Flutter module flutter create --template module my_flutter第二步&#xff1a;创建framework&#xff0c;这里选择的是B方式&#xff0c;即 选项 B - 在 Xcode 中…...

【ubuntu】用户添加root权限

添加root用户添加新用户并赋予权限 文件只读&#xff0c;无法更改 rootubuntu-server:/home/ubuntu# vi /etc/sudoers rootubuntu-server:/home/ubuntu# vi /etc/sudoers rootubuntu-server:/home/ubuntu# chmod -R 777 /etc/sudoers rootubuntu-server:/home/ubuntu# vi /et…...

设计通用灵活的LabVIEW自动测试系统

为了在不同客户案例中灵活使用不同设备&#xff08;如采集卡、Modbus模块&#xff09;且保持功能一致的LabVIEW自动测试系统&#xff0c;需要采用模块化的软件架构、配置文件管理、标准化接口和良好的升级维护策略。本文从软件架构、模块化设计、配置管理、升级维护、代码管理和…...

C# WinForm —— 35 StatusStrip 介绍

1. 简介 状态栏 StatusStrip&#xff0c;默认在软件的最下方&#xff0c;用于显示系统时间、版本、进度条、账号、角色信息、操作位置信息等 可以在状态栏中添加的控件类型有&#xff1a;StatusLabel、ProgressBar、DropDownButton、SplitButton 2. 属性 属性解释(Name)控…...

如何应对生活中的不确定性:仁者安仁,知者利仁。

有较高自尊水平的人&#xff0c;接近于孔子说的&#xff1a;仁者。 ——— 有着稳定的高自尊&#xff0c;无论外在环境如何变化&#xff0c;对其影响都不大&#xff0c;他能够愉快地生活。 相反&#xff1a;一个人处于低自尊状态&#xff0c;就会活得很痛苦&#xff0c;对自己…...

C#面:请解释C#接口的显式实现有什么意义

C#接口的显式实现是指在实现接口成员时&#xff0c;使用接口名称进行限定的方式。这种方式可以在一个类中实现多个接口&#xff0c;并且可以避免接口成员之间的命名冲突。显式实现接口的成员只能通过接口类型来访问&#xff0c;而不能通过类的实例来访问。 显式实现接口的主要…...

STM32项目分享:智能窗帘系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…...

【算法-力扣】72. 编辑距离(动态规划)

目录 一、题目描述 二、解题思路 三、参考答案 一、题目描述 编辑距离 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符 删除一个字符 替换一个字符 示例 1&#…...

Spring 系统架构图

Spring 系统架构图 Spring Framework是Spring生态圈中最基础的项目&#xff0c;是其他项目的根基。 Spring Framework的发展也经历了很多版本的变更&#xff0c;每个版本都有相应的调整 Spring Framework的5版本目前没有最新的架构图&#xff0c;而最新的是4版本&#xff0c;…...

同三维T80005EHS-4K60 4K60 HDMI/SDI编码器

1路4K60 HDMI或12G SDI输入&#xff0c;2路3.5MM音频输入&#xff0c;对应HDMI或SDI&#xff0c;1个USB口和1个SD卡槽&#xff0c;可录像到U盘/移动硬盘/SSD硬盘/TF卡 产品简介&#xff1a; 同三维T80005EHS-4K60 4K60HDMI/SDI H.265编码器采用最新高效H.265高清数字视频压缩…...

React state(及组件) 的保留与重置

当在树中相同的位置渲染相同的组件时&#xff0c;React 会一直保留着组件的 state return (<div><Counter />{showB && <Counter />} </div> ) // 当 showB 为 false, 第二个计数器停止渲染&#xff0c;它的 state 完全消失了。这是因为 React…...

flask返回的数据怎么是转义后的字符串啊

Flask在返回JSON数据时,默认情况下会对特殊字符进行转义,以确保数据能安全地在HTML页面中展示,避免XSS(跨站脚本攻击)等安全问题。如果不希望Flask对JSON响应中的字符串自动转义,通常是因为你希望在前端直接使用这些数据(例如作为JavaScript的一部分),那么需要确保数据…...

C++17并行算法与HIPSTDPAR

C17 parallel algorithms and HIPSTDPAR — ROCm Blogs (amd.com) C17标准在原有的C标准库中引入了并行算法的概念。像std::transform这样的并行版本算法保持了与常规串行版本相同的签名&#xff0c;只是增加了一个额外的参数来指定使用的执行策略。这种灵活性使得已经使用C标准…...

【什么是几度cms,主要功能有什么】

几度CMS内容管理框架是基于 PHP 语言采用最新 Thinkphp 作为开发框架生产的网站 内容管理框架&#xff0c;提供“电脑网站 手机网站 多终端 APP 接口”一体化网站技术解 决方案。她拥有强大稳定底层框架&#xff0c;以灵活扩展为主的开发理念&#xff0c;二次开发方便且…...

组合和外观模式

文章目录 组合模式1.引出组合模式1.院系展示需求2.组合模式基本介绍3.组合模式原理类图4.解决的问题 2.组合模式解决院系展示1.类图2.代码实现1.AbsOrganizationComponent.java 总体抽象类用于存储信息和定义方法2.University.java 第一层&#xff0c;University 可以管理 Coll…...

设置服务器禁止和ip通信

要禁止服务器与特定 IP 地址的通信&#xff0c;可以使用防火墙来设置规则。在 Ubuntu 上&#xff0c;iptables 是一个常用的防火墙工具。以下是使用 iptables 设置禁止与特定 IP 通信的步骤&#xff1a; 阻止所有进出的通信 如果你想阻止服务器与特定 IP 地址的所有通信&…...

中文技术文档的写作规范(搬运)

阮一峰老师的《中文技术文档的写作规范》搬运。 链接指路&#xff1a; https://github.com/ruanyf/document-style-guide/tree/master 内容&#xff1a;对中文技术文档从标题、文本、段落、数值、标点符号、文档体系、参考链接等七大方面进行了简明扼要的介绍。...

「实战应用」如何用DHTMLX将上下文菜单集成到JavaScript甘特图中(一)

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 DHTMLX Gantt是一个高度可定制的工具&#xff0c;可以与项目管理应用程序所需的其他功能相补充。在本文中您将学习如何使用自定义上…...

Python使用策略模式生成TCP数据包

使用策略模式&#xff08;Strategy Pattern&#xff09;来灵活地生成不同类型的TCP数据包。 包括三次握手、数据传输和四次挥手。 from scapy.all import * from scapy.all import Ether, IP, TCP, UDP, wrpcap from abc import ABC, abstractmethodclass TcpPacketStrategy(A…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...