springboot对接rabbitmq并且实现动态创建队列和消费
背景
1、对接多个节点上的MQ(如master-MQ,slave-MQ),若读者需要自己模拟出两个MQ,可以部署多个VM然后参考 docker 安装rabbitmq_Steven-Russell的博客-CSDN博客
2、队列名称不是固定的,需要接受外部参数,并且通过模板进行格式化,才能够得到队列名称
3、需要在master-MQ上延迟一段时间,然后将消息再转发给slave-MQ
问题
1、采用springboot的自动注入bean需要事先知道队列的名称,但是队列名称是动态的情况下,无法实现自动注入
2、mq弱依赖,在没有master-mq或者slave-mq时,不能影响到现有能力
解决方案
1、由于mq的队列创建、exchange创建以及队列和exchange的绑定关系是可重入的,所以采用connectFactory进行手动声明
2、增加自定义条件OnMqCondition,防止不必要的bean创建
总体流程

实施过程
搭建springboot项目
参考 搭建最简单的SpringBoot项目_Steven-Russell的博客-CSDN博客
引入amqp依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency>
引入后续会用到的工具类依赖
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version> </dependency> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>provided</scope> </dependency> <dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.40</version> </dependency>
创建配置文件
在application.yml中增加如下配置
mq:master:addresses: 192.168.30.128:5672username: guestpassword: guestvhost: /slave:addresses: 192.168.30.131:5672username: guestpassword: guestvhost: /
创建自定义Condition注解和注解实现
package com.wd.config.condition;import org.springframework.context.annotation.Conditional;import java.lang.annotation.*;@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnMqCondition.class)
public @interface MqConditional {String[] keys();}
package com.wd.config.condition;import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.lang.NonNull;
import org.springframework.util.ObjectUtils;import java.util.Map;public class OnMqCondition implements Condition {@Overridepublic boolean matches(@NonNull ConditionContext context, @NonNull AnnotatedTypeMetadata metadata) {Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(MqConditional.class.getName());if (annotationAttributes == null || annotationAttributes.isEmpty()) {// 为空则不进行校验了return true;}String[] keys = (String[])annotationAttributes.get("keys");for (String key : keys) {String property = context.getEnvironment().getProperty(key);if (ObjectUtils.isEmpty(property)) {return false;}}return true;}
}
创建多个链接工厂connectFactory
package com.wd.config;import com.wd.config.condition.MqConditional;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;@Configuration
public class MqConnectionFactory {@Value("${mq.master.addresses}")private String masterAddresses;@Value("${mq.master.username}")private String masterUsername;@Value("${mq.master.password}")private String masterPassword;@Value("${mq.master.vhost}")private String masterVhost;@Value("${mq.slave.addresses}")private String slaveAddresses;@Value("${mq.slave.username}")private String slaveUsername;@Value("${mq.slave.password}")private String slavePassword;@Value("${mq.slave.vhost}")private String slaveVhost;@Bean@Primary@MqConditional(keys = {"mq.master.addresses", "mq.master.vhost", "mq.master.username", "mq.master.password"})public ConnectionFactory masterConnectionFactory() {return doCreateConnectionFactory(masterAddresses, masterUsername, masterPassword, masterVhost);}@Bean@MqConditional(keys = {"mq.slave.addresses", "mq.slave.vhost", "mq.slave.username", "mq.slave.password"})public ConnectionFactory slaveConnectionFactory() {return doCreateConnectionFactory(slaveAddresses, slaveUsername, slavePassword, slaveVhost);}private ConnectionFactory doCreateConnectionFactory(String addresses,String username,String password,String vhost) {CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();cachingConnectionFactory.setAddresses(addresses);cachingConnectionFactory.setUsername(username);cachingConnectionFactory.setPassword(password);cachingConnectionFactory.setVirtualHost(vhost);return cachingConnectionFactory;}}
创建交换机名称枚举 DeclareQueueExchange
package com.wd.config;public enum DeclareQueueExchange {EXCHANGE("exchange"),DEAD_EXCHANGE("deadExchange"),DELAY_EXCHANGE("delayExchange");private final String exchangeName;DeclareQueueExchange(String exchangeName) {this.exchangeName = exchangeName;}public String getExchangeName() {return exchangeName;}
}
创建消息队列模板枚举 DeclareQueueName
package com.wd.config;public enum DeclareQueueName {DELAY_QUEUE_NAME_SUFFIX("_delay"),DEAD_QUEUE_NAME_SUFFIX("_dead"),QUEUE_NAME_TEMPLATE("wd.simple.queue.{0}");private final String queueName;DeclareQueueName(String queueName) {this.queueName = queueName;}public String getQueueName() {return queueName;}
}
创建消息VO和消息
package com.wd.controller.vo;import com.wd.pojo.Phone;
import lombok.Data;@Data
public class DelayMsgVo {private String queueId;private Phone phone;
}
package com.wd.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.Date;
import java.util.List;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Phone implements Serializable {private static final long serialVersionUID = -1L;private String id;private String name;private Date createTime;private List<User> userList;}
package com.wd.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.Date;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {private static final long serialVersionUID = -1L;private String username;private Date create;
}
定义队列id列表缓存,用于替换三方缓存,用于队列名称模板初始化
package com.wd.config;import java.util.ArrayList;
import java.util.List;public interface QueueIdListConfig {/*** 先用本地缓存维护队列id*/List<Integer> QUEUE_ID_LIST = new ArrayList<Integer>() {{add(111);add(222);add(333);}};
}
创建消息接受入口 controller
注意:此处就以web用户输入为入口,所以创建controller
package com.wd.controller;import com.alibaba.fastjson2.JSONObject;
import com.rabbitmq.client.*;
import com.wd.config.DeclareQueueExchange;
import com.wd.config.DeclareQueueName;
import com.wd.controller.vo.DelayMsgVo;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.web.bind.annotation.*;import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;@RestController
@ConditionalOnBean(value = ConnectionFactory.class, name = "masterConnectionFactory")
public class DynamicCreateQueueController {private final ConnectionFactory masterConnectionFactory;public DynamicCreateQueueController(@Qualifier(value = "masterConnectionFactory") ConnectionFactory masterConnectionFactory) {this.masterConnectionFactory = masterConnectionFactory;}@PostMapping(value = "sendDelayMsg")public String sendMsg2DelayQueue(@RequestBody DelayMsgVo delayMsgVo) throws IOException, TimeoutException {doSendMsg2DelayQueue(delayMsgVo);return "success";}private void doSendMsg2DelayQueue(DelayMsgVo delayMsgVo) throws IOException, TimeoutException {// 根据id 动态生成队列名称String queueNameTemplate = DeclareQueueName.QUEUE_NAME_TEMPLATE.getQueueName();String queueName = MessageFormat.format(queueNameTemplate, delayMsgVo.getQueueId());String delayQueueName = queueName + DeclareQueueName.DELAY_QUEUE_NAME_SUFFIX.getQueueName();String deadQueueName = queueName + DeclareQueueName.DEAD_QUEUE_NAME_SUFFIX.getQueueName();// 注意:下述声明交换机和队列的操作是可以重入的,MQ并不会报错try (Connection connection = masterConnectionFactory.createConnection();Channel channel = connection.createChannel(false)){// 声明死信交换机channel.exchangeDeclare(DeclareQueueExchange.DEAD_EXCHANGE.getExchangeName(), BuiltinExchangeType.DIRECT);// 声明死信队列AMQP.Queue.DeclareOk deadQueueDeclareOk = channel.queueDeclare(deadQueueName,true, false, false, null);// 定时任务 绑定消费者,避免出现多个消费者以及重启后无法消费存量消息的问题// 注意:因为需要保证消费顺序,所以此处仅声明一个消费者// 死信队列和交换机绑定channel.queueBind(deadQueueName, DeclareQueueExchange.DEAD_EXCHANGE.getExchangeName(), deadQueueName);// 声明延迟队列Map<String, Object> args = new HashMap<>();//设置延迟队列绑定的死信交换机args.put("x-dead-letter-exchange", DeclareQueueExchange.DEAD_EXCHANGE.getExchangeName());//设置延迟队列绑定的死信路由键args.put("x-dead-letter-routing-key", deadQueueName);//设置延迟队列的 TTL 消息存活时间args.put("x-message-ttl", 10 * 1000);channel.queueDeclare(delayQueueName, true, false, false, args);channel.exchangeDeclare(DeclareQueueExchange.DELAY_EXCHANGE.getExchangeName(), BuiltinExchangeType.DIRECT);channel.queueBind(delayQueueName, DeclareQueueExchange.DELAY_EXCHANGE.getExchangeName(), delayQueueName);// 发送消息到延迟队列channel.basicPublish(DeclareQueueExchange.DELAY_EXCHANGE.getExchangeName(), delayQueueName, null,JSONObject.toJSONString(delayMsgVo.getPhone()).getBytes(StandardCharsets.UTF_8));}}}
创建master延迟消息消费者
package com.wd.mq.consumer;import com.rabbitmq.client.*;
import com.wd.config.DeclareQueueExchange;
import com.wd.config.DeclareQueueName;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;import java.io.IOException;
import java.util.concurrent.TimeoutException;/*** 死信消费者,消费消息转发给targetConnectionFactory对应的目标MQ*/
public class MasterDeadQueueConsumer extends DefaultConsumer {private final ConnectionFactory targetConnectionFactory;public MasterDeadQueueConsumer(Channel channel, ConnectionFactory targetConnectionFactory) {super(channel);this.targetConnectionFactory = targetConnectionFactory;}@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {// 从死信队列的名称中截取队列名称,作为后续队列的名称String routingKey = envelope.getRoutingKey();String targetQueueName = routingKey.substring(0, routingKey.length() - DeclareQueueName.DEAD_QUEUE_NAME_SUFFIX.getQueueName().length());try (Connection targetConnection = targetConnectionFactory.createConnection();Channel targetChannel = targetConnection.createChannel(false)){// 声明交换机和队列targetChannel.exchangeDeclare(DeclareQueueExchange.EXCHANGE.getExchangeName(), BuiltinExchangeType.DIRECT);targetChannel.queueDeclare(targetQueueName, true, false, false, null);targetChannel.queueBind(targetQueueName, DeclareQueueExchange.EXCHANGE.getExchangeName(), targetQueueName);// 转发消息targetChannel.basicPublish(DeclareQueueExchange.EXCHANGE.getExchangeName(), targetQueueName, properties, body);} catch (TimeoutException e) {e.printStackTrace();// 注意此处获取的源队列的channelgetChannel().basicNack(envelope.getDeliveryTag(), false, true);}// 注意此处获取的源队列的channelgetChannel().basicAck(envelope.getDeliveryTag(), false);}
}
创建slave队列消息消费者
package com.wd.mq.consumer;import com.alibaba.fastjson2.JSONObject;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.wd.pojo.Phone;import java.io.IOException;public class SlaveQueueConsumer extends DefaultConsumer {public SlaveQueueConsumer(Channel channel) {super(channel);}@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {Phone phone = JSONObject.parseObject(new String(body), Phone.class);System.out.println("SlaveQueueConsumer consume ==> " + phone);getChannel().basicAck(envelope.getDeliveryTag(), false);}
}
创建定时任务,消费延迟消息
注意:因为采用的是死信队列的方式实现的延迟效果,此处只需要消费对应的死信队列即可
package com.wd.mq.quartz;import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.wd.config.DeclareQueueExchange;
import com.wd.config.DeclareQueueName;
import com.wd.config.QueueIdListConfig;
import com.wd.mq.consumer.MasterDeadQueueConsumer;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;import java.io.IOException;
import java.text.MessageFormat;
import java.util.concurrent.TimeoutException;@Configuration
@ConditionalOnBean(value = ConnectionFactory.class, name = {"slaveConnectionFactory", "masterConnectionFactory"})
public class MasterDeadQueueSubscribeProcessor {private final ConnectionFactory masterConnectionFactory;private final ConnectionFactory slaveConnectionFactory;public MasterDeadQueueSubscribeProcessor(@Qualifier(value = "masterConnectionFactory") ConnectionFactory masterConnectionFactory,@Qualifier(value = "slaveConnectionFactory") ConnectionFactory slaveConnectionFactory) {this.masterConnectionFactory = masterConnectionFactory;this.slaveConnectionFactory = slaveConnectionFactory;}/*** 消费死信队列信息,并且转发到其他mq*/@Scheduled(fixedDelay = 10 * 1000)public void subscribeMasterDeadQueue() throws IOException, TimeoutException {// 根据id 动态生成队列名称// 此处的queueIdList可以从第三方缓存查询得到,并且和sendDelayMsg接口保持同步刷新,此处先用本地缓存代替,id同步刷新机制不是重点,此处暂不讨论for (Integer id : QueueIdListConfig.QUEUE_ID_LIST) {String queueNameTemplate = DeclareQueueName.QUEUE_NAME_TEMPLATE.getQueueName();String deadQueueName = MessageFormat.format(queueNameTemplate, id) + DeclareQueueName.DEAD_QUEUE_NAME_SUFFIX.getQueueName();try (Connection connection = masterConnectionFactory.createConnection();Channel channel = connection.createChannel(false)){AMQP.Queue.DeclareOk queueDeclare = channel.queueDeclare(deadQueueName, true, false, false, null);if (queueDeclare.getConsumerCount() == 0) {channel.exchangeDeclare(DeclareQueueExchange.DEAD_EXCHANGE.getExchangeName(), BuiltinExchangeType.DIRECT);}channel.queueBind(deadQueueName, DeclareQueueExchange.DEAD_EXCHANGE.getExchangeName(), deadQueueName);channel.basicConsume(deadQueueName, false, new MasterDeadQueueConsumer(channel, slaveConnectionFactory));}}}}
创建定时任务,消费slave队列的消息
package com.wd.mq.quartz;import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.wd.config.DeclareQueueExchange;
import com.wd.config.DeclareQueueName;
import com.wd.config.QueueIdListConfig;
import com.wd.mq.consumer.SlaveQueueConsumer;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;import java.io.IOException;
import java.text.MessageFormat;
import java.util.concurrent.TimeoutException;@Configuration
@ConditionalOnBean(value = ConnectionFactory.class, name = "slaveConnectionFactory")
public class SlaveQueueSubscribeProcessor {private final ConnectionFactory slaveConnectionFactory;public SlaveQueueSubscribeProcessor(@Qualifier(value = "slaveConnectionFactory") ConnectionFactory slaveConnectionFactory) {this.slaveConnectionFactory = slaveConnectionFactory;}/*** 消费队列信息*/@Scheduled(fixedDelay = 10 * 1000)public void subscribeSlaveDeadQueue() throws IOException, TimeoutException {// 根据id 动态生成队列名称// 此处的queueIdList可以从第三方缓存查询得到,并且和sendDelayMsg接口保持同步刷新,此处先用本地缓存代替for (Integer id : QueueIdListConfig.QUEUE_ID_LIST) {String queueNameTemplate = DeclareQueueName.QUEUE_NAME_TEMPLATE.getQueueName();String queueName = MessageFormat.format(queueNameTemplate, id);try (Connection connection = slaveConnectionFactory.createConnection();Channel channel = connection.createChannel(false)){AMQP.Queue.DeclareOk queueDeclare = channel.queueDeclare(queueName, true, false, false, null);if (queueDeclare.getConsumerCount() == 0) {channel.basicConsume(queueName, false, new SlaveQueueConsumer(channel));}channel.exchangeDeclare(DeclareQueueExchange.EXCHANGE.getExchangeName(), BuiltinExchangeType.DIRECT);channel.queueBind(queueName, DeclareQueueExchange.EXCHANGE.getExchangeName(), queueName);}}}}
启动项目
请求接口发送消息 http://localhost:8080/sendDelayMsg
检查消息传递过程
先在master-mq延迟队列发现消息

再到master-mq死信队列中发现消息

再到slave-mq中发现消息

检查日志打印
发现SlaveQueueConsumer打印如下日志:![]()
结论
消息传递流程如下,验证通过

相关文章:
springboot对接rabbitmq并且实现动态创建队列和消费
背景 1、对接多个节点上的MQ(如master-MQ,slave-MQ),若读者需要自己模拟出两个MQ,可以部署多个VM然后参考 docker 安装rabbitmq_Steven-Russell的博客-CSDN博客 2、队列名称不是固定的,需要接受外部参数&…...
Spring的后处理器-BeanFactoryPostprocessor
目录 Spring后处理器 Bean工厂后处理器-BeanFactoryPostProcessor 修改beanDefinition对象 添加beanDefiniton对象 方法一 方法二 自定义Component Spring后处理器 Spring后处理器是Spring对外开放的重要拓展点(让我们可以用添加自己的逻辑)&…...
Flutter 必备知识点
Flutter 升级 确保在项目根目录下(含有 pubspec.yaml 的文件夹) 在命令行中输入命令: flutter channel输出: Flutter channels: * mastermainbetastable这个可以在 pubspec.yaml 中查看: 切换分支也很简单…...
什么是FMEA(失效模式和影响分析)?
失效模式和影响分析(FMEA)是一个在开发阶段,用于确定产品或流程可能的风险和失败点的有条理的过程。FMEA团队会研究失效模式,也就是产品或流程中可能出错的地方,以及这些失效可能带来的影响(如风险、损害、…...
Redis面试题(三)
文章目录 前言一、怎么理解 Redis 事务?二、Redis 事务相关的命令有哪几个?三、Redis key 的过期时间和永久有效分别怎么设置?四、Redis 如何做内存优化?五、Redis 回收进程如何工作的?六、 加锁机制总结 前言 怎么理…...
Python错误处理指南:优雅应对异常情况
目录 一. 异常是什么?二. 使用 try 和 except三. 捕获多个异常四. 使用 else五. 使用 finally六. 自定义异常七.Python中常见异常处理类型八.Python中常见异常处理实例九.异常处理最佳实践十.结论 当编写Python代码时,错误处理是一个重要的方面ÿ…...
MySQL学习笔记12
MySQL 查询语句: 1、查询五子句:(重点) mysql> select */字段列表 from 数据表名称 where 子句 group by 子句 having 子句 order by 子句 limit 子句; 1)where 子句;条件筛选。 2)group…...
【owt】构建m79的owt-client-native:使用vs2017
家里电脑换成了台式机,拷贝代码发现了三年前的owt客户端mfc工程。 不用下载第三方库,试着构建下: owt-client-native 我这里有3年前的代码,思索了下还是用vs2017构建吧: 重新构建一下 选用x86 的 vs2017 vs的命令行控制台 cls可以清理屏幕 之前构建过vs2022的webrtc原版 …...
Cpp/Qt-day020918Qt
目录 完善登录框 点击登录按钮后,判断账号(admin)和密码(123456)是否一致,如果匹配失败,则弹出错误对话框,文本内容“账号密码不匹配,是否重新登录”,给定两…...
Spring面试题10:Spring的XMLBeanFactory怎么使用
该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring的XMLBeanFactory怎么使用 XmlBeanFactory是Spring框架中的一个实现类,它是BeanFactory接口的一个具体实现。XmlBeanFactory的主要作用是通…...
自定义数据类型
前言:小伙伴们又见面啦,今天这篇文章,我们来谈谈几种自定义数据类型。 目录 一.都有哪些自定义数据类型 二.结构体 结构体内存对齐 1.如何对齐 2.为什么要对齐 3.节省空间和提升效率的方法 (1)让占用空间小的成员…...
产品团队的需求验证和确认
需求核实过程是确保软件满足特定的规格要求,而验证则侧重于软件是否达到了最终用户的期望和需求。 如果你正在开发一种医疗产品,这种区别也可能在法规和标准中有所体现,例如: 820.30(f):设计验证应确认设计的成果符合…...
【JVM】类加载的过程
文章目录 类的生命周期加载验证准备解析初始化简要概括 类的生命周期 一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载 (Loading)、验证(Verification)、准备…...
Golang 结构化日志包 log/slog 详解(四):分组、上下文和属性值类型
上一篇文章讲解了 log/slog 包中的自定义日志属性字段和日志级别,本文讲解下分组、上下文和属性值类型 分组输出 slog 支持将字段放在组中并且可以给分组指定名称。如何展示分组的内容,取决于使用的 handler,例如 TextHandler 使用点号分隔…...
小白学Python:提取Word中的所有图片,只需要1行代码
#python# 大家好,这里是程序员晚枫,全网同名。 最近在小破站账号:Python自动化办公社区更新一套课程:给小白的《50讲Python自动化办公》 在课程群里,看到学员自己开发了一个功能:从word里提取图片。这个…...
pip修改位于用户目录下的缓存目录
默认 pip 缓存目录: Windows: C:\Users\${用户名}\AppData\Local\pip\cache Linux: ~/.cache/pip 一、修改方式 1.命令方式 pip config set global.cache-dir "D:\kwok\data\pip-cache" 2.配置文件方式 ① Windows: C:\Users\${用…...
更新、修改
MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法: update 表名 列名该列新值, 列名该列新值, ... where 记录匹配条件; 说明:update 更新、修改 set 设置 …...
山西电力市场日前价格预测【2023-09-25】
日前价格预测 预测说明: 如上图所示,预测明日(2023-09-25)山西电力市场全天平均日前电价为442.30元/MWh。其中,最高日前电价为720.46元/MWh,预计出现在19: 00。最低日前电价为276.06元/MWh,预计…...
从collections库的Counter类看items()方法和enumerate()方法
下面的代码是针对文件的词频统计,使用了collections库及其Counter类 import collections def count_word_frequency(text): words text.lower().split() word_counts collections.Counter(words) return word_counts def count_fileword_frequency(fi…...
2023-09-24 LeetCode每日一题(LRU 缓存)
2023-09-24每日一题 一、题目编号 146. LRU 缓存二、题目链接 点击跳转到题目位置 三、题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存i…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
