一种多策略下RabbitMQ的延时队列实现
1.为什么会用到延时队列?
场景: 最近在开发一款系统中遇到这样一个场景,A系统开通套餐需要把套餐信息以邮件的形式发送给相关工作人员,经过人工审核通过后,在B系统里面开通,A系统会调B系统套餐列表接口查询套餐是否开通成功,开通成功则从A系统去完成订单,假如超过设定时间未开通成功,则关闭订单并退费.
(这东西俗称"套娃")
这时候用RabbitMQ的延时队列就可以完美的解决这个问题
2.为什么会提到多策略?
场景: 假如A系统还有别的功能添加需要经过人工审核之后在B系统中添加成功之后,A系统才会显示添加成功,但是又不想写很多队列啊消费者等代码.就可以用到这种策略模式,换句话说 就是类似 if… else …能明白了吧.
3.进入今天主题
整体流程图:

生产者生产一条延时消息,根据需要延时时间的不同,利用routingkey将消息路由到延时队列,队列都设置了TTL属性,并绑定到死信交换机中,消息过期后,根据routingkey又会被路由到死信队列中,消费者只需要监听死信队列,拿到消息去具体的策略实现类进行后续业务处理即可。
有了这个图写代码就简单了.
mq配置类 声明队列,路由键,交换机之间的关系;以及生产者消费者 rabbitmq等Bean
RabbitMqConfig
注意 监听我也写在配置类里面SimpleMessageListenerContainer用的这个类去设置的队列
simpleMessageListenerContainer.setQueueNames(DEAD_LETTER_QUEUE_NAME);
package com.king.alice.rabbitmq.config;import com.king.alice.rabbitmq.delay.consumer.MessageConsumer;
import com.king.alice.rabbitmq.delay.consumer.Strategy;
import com.king.alice.rabbitmq.delay.provider.MessageProvider;
import org.springframework.amqp.core.*;
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.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @Author wlt* @Description rabbitmq配置类* @Date 2022/9/4* @Param* @return**/@Configuration
public class RabbitMqConfig {public static final String DELAY_EXCHANGE_NAME = "delay.alice.exchange";public static final String DELAY_QUEUE_NAME = "delay.alice.queue";public static final String DELAY_QUEUE_ROUTING_KEY = "delay.alice.queue.routing.key";public static final String DEAD_LETTER_EXCHANGE = "ttl.alice.exchange";public static final String DEAD_LETTER_QUEUE_ROUTING_KEY = "ttl.alice.queue.routing.key";public static final String DEAD_LETTER_QUEUE_NAME = "ttl.alice.queue";/*** 声明延时Exchange* @return*/@Bean("delayExchange")public DirectExchange delayExchange(){return new DirectExchange(DELAY_EXCHANGE_NAME);}/*** 功能描述: <br>* <声明死信Exchange>*/@Bean("deadLetterExchange")public DirectExchange deadLetterExchange(){return new DirectExchange(DEAD_LETTER_EXCHANGE);}/*** 声明延时队列 并绑定到对应的死信交换机* @return*/@Bean("delayQueue")public Queue delayQueue(){Map<String, Object> args = new HashMap<>(2);// x-dead-letter-exchange 这里声明当前队列绑定的死信交换机args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);// x-dead-letter-routing-key 这里声明当前队列的死信路由keyargs.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUE_ROUTING_KEY);// x-message-ttl 声明队列的TTL
// args.put("x-message-ttl", 6000);return QueueBuilder.durable(DELAY_QUEUE_NAME).withArguments(args).build();}/*** 功能描述: <br>* <声明死信队列用于接收延时处理的消息>*/@Bean("deadLetterQueue")public Queue deadLetterQueue(){return new Queue(DEAD_LETTER_QUEUE_NAME);}/*** 功能描述: <br>* <声明延时队列绑定关系>* @Param:* @Return:* @Author: 大魔王* @Date: 2023/8/15 20:00*/@Beanpublic Binding delayBinding(@Qualifier("delayQueue") Queue queue,@Qualifier("delayExchange") DirectExchange exchange){return BindingBuilder.bind(queue).to(exchange).with(DELAY_QUEUE_ROUTING_KEY);}/*** 功能描述: <br>* <声明死信队列A绑定关系>* @Param:* @Return:* @Author: 大魔王* @Date: 2023/8/15 20:01*/@Beanpublic Binding deadLetterBinding(@Qualifier("deadLetterQueue") Queue queue,@Qualifier("deadLetterExchange") DirectExchange exchange){return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUE_ROUTING_KEY);}@Bean@ConditionalOnMissingBeanpublic MessageProvider messageProvider(@Qualifier("delayRabbitTemplate") RabbitTemplate template) {return new MessageProvider(template);}@Bean@ConditionalOnMissingBeanpublic MessageConsumer messageConsumer(ObjectProvider<List<Strategy>> provider) {return new MessageConsumer(provider);}@Bean@ConditionalOnMissingBeanpublic RabbitTemplate delayRabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate template = new RabbitTemplate(connectionFactory);template.setMessageConverter(new Jackson2JsonMessageConverter());return template;}@BeanSimpleMessageListenerContainer simpleMessageListenerContainer(MessageConsumer messageConsumer, ConnectionFactory factory) {SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(factory);simpleMessageListenerContainer.setQueueNames(DEAD_LETTER_QUEUE_NAME);simpleMessageListenerContainer.setExposeListenerChannel(true);simpleMessageListenerContainer.setMessageListener(messageConsumer);return simpleMessageListenerContainer;}public static final String EXCHANGE_NAME = "alice_topic_exchange";public static final String QUEUE_NAME = "alice_queue";@Bean("aliceExchange")public Exchange aliceExchange() {return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();}@Bean("aliceQueue")public Queue aliceQueue() {return QueueBuilder.durable(QUEUE_NAME).build();}@Beanpublic Binding bindQueueExchange(@Qualifier("aliceQueue") Queue queue, @Qualifier("aliceExchange") Exchange exchange) {return BindingBuilder.bind(queue).to(exchange).with("alice.#").noargs();}}
生产者:
MessageProvider
package com.king.alice.rabbitmq.delay.provider;import cn.hutool.core.date.DateUtil;
import com.king.alice.common.json.JSON;
import com.king.alice.rabbitmq.config.RabbitMqConfig;
import com.king.alice.rabbitmq.delay.bean.DelayMessage;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Date;/*** @author 大魔王*/
@Slf4j
@Component
public class MessageProvider {@Autowiredprivate final RabbitTemplate rabbitTemplate;public MessageProvider(RabbitTemplate rabbitTemplate) {this.rabbitTemplate = rabbitTemplate;}/*** send delay message*/public void sendMessage(DelayMessage delayMessage) {Assert.assertNotNull(delayMessage);log.info(" now date {},delay {} seconds to write to the message queue", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"), delayMessage.getDelay());rabbitTemplate.convertAndSend(RabbitMqConfig.DELAY_EXCHANGE_NAME, RabbitMqConfig.DELAY_QUEUE_ROUTING_KEY, delayMessage,message -> {message.getMessageProperties().setExpiration(String.valueOf(delayMessage.getDelay() * 1000));return message;});}}
消费者:
package com.king.alice.rabbitmq.delay.consumer;import cn.hutool.core.util.ObjectUtil;
import com.king.alice.common.json.JSONObject;
import com.king.alice.rabbitmq.delay.bean.AliceMessage;
import com.king.alice.rabbitmq.delay.bean.DelayMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;/*** @author 大魔王*/
@Slf4j
public class MessageConsumer implements MessageListener {private final Map<Type, List<Strategy>> strategyMap = new ConcurrentHashMap<>();public MessageConsumer(ObjectProvider<List<Strategy>> stategyProvider) {List<Strategy> handleList = stategyProvider.getIfAvailable();Optional<? extends List<Strategy>> optionalStrategies = Optional.ofNullable(handleList);optionalStrategies.ifPresent(strategies -> strategies.stream().filter(strategy -> {Type genericInterface = strategy.getClass().getGenericInterfaces()[0];return genericInterface instanceof ParameterizedType;}).map(strategy -> ((ParameterizedType) strategy.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0]).collect(Collectors.toSet()).forEach(delayMessages -> {List<Strategy> collect = strategies.stream().filter(strategy -> {Type genericInterface = strategy.getClass().getGenericInterfaces()[0];if (genericInterface instanceof ParameterizedType) {Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];return delayMessages.getTypeName().equals(actualTypeArgument.getTypeName());}return false;}).collect(Collectors.toList());strategyMap.put(delayMessages, collect);}));}@Overridepublic void onMessage(Message message) {MessageConverter messageConverter = new Jackson2JsonMessageConverter();DelayMessage delayMessage = (DelayMessage) messageConverter.fromMessage(message);List<Strategy> strategyList = strategyMap.get(delayMessage.getClass());if (!CollectionUtils.isEmpty(strategyList)) {strategyList.forEach(strategy -> strategy.handle(delayMessage));} else {log.info("Missing message processing class");}}}
策略相关Bean,接口以及实现类
DelayMessage
package com.king.alice.rabbitmq.delay.bean;/*** @author 大魔王*/
public interface DelayMessage{/*** 获得延迟时间(单位秒)** @return 延迟时间单位秒*/int getDelay();}
AliceMessage
package com.king.alice.rabbitmq.delay.bean;import lombok.Getter;
import lombok.Setter;/*** @author 大魔王*/
@Getter
@Setter
public class AliceMessage implements DelayMessage {/*** 用户邮箱*/String email;/*** 订单类型*/String orderType;/*** 执行次数*/Integer dealCount;/*** 延时秒数*/int delay;@Overridepublic int getDelay() {return this.delay;}public void setDelay(int delay) {this.delay = delay;}
}
UserMessage
package com.king.alice.rabbitmq.delay.bean;import lombok.Getter;
import lombok.Setter;/*** @author 大魔王*/
@Getter
@Setter
public class UserMessage implements DelayMessage{/*** 用户*/String username;/*** token*/String token;/*** 执行次数*/Integer dealCount;/*** 延时秒数*/int delay;@Overridepublic int getDelay() {return this.delay;}public void setDelay(int delay) {this.delay = delay;}
}
Strategy
package com.king.alice.rabbitmq.delay.consumer;import com.king.alice.rabbitmq.delay.bean.DelayMessage;/*** @author 大魔王*/
public interface Strategy<T extends DelayMessage> {/*** 处理消息的方法** @param delayMessage 收到的消息*/void handle(T delayMessage);
}
AliceMessageHandler
package com.king.alice.rabbitmq;import com.king.alice.common.json.JSON;
import com.king.alice.common.json.JSONObject;
import com.king.alice.rabbitmq.delay.bean.AliceMessage;
import com.king.alice.rabbitmq.delay.consumer.Strategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @author 大魔王*/
@Component
@Slf4j
public class AliceMessageHandler implements Strategy<AliceMessage> {@Overridepublic void handle(AliceMessage delayMessage) {log.info("AliceMessage响应体{}", JSONObject.parseObject(JSON.toJSONString(delayMessage)));}
}
UserMessageHandler
package com.king.alice.rabbitmq;import com.king.alice.common.json.JSON;
import com.king.alice.common.json.JSONObject;
import com.king.alice.rabbitmq.delay.bean.UserMessage;
import com.king.alice.rabbitmq.delay.consumer.Strategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @author 大魔王*/
@Slf4j
@Component
public class UserMessageHandler implements Strategy<UserMessage> {@Overridepublic void handle(UserMessage delayMessage) {log.info("UserMessage响应体{}", JSONObject.parseObject(JSON.toJSONString(delayMessage)));}
}
接下来 我们写个controller测试一下
SysAccountController
package com.king.alice.manage.sys.controller;import cn.hutool.core.date.DateUtil;
import com.king.alice.manage.sys.entity.SysAccount;
import com.king.alice.manage.sys.service.SysAccountService;
import com.king.alice.rabbitmq.delay.bean.AliceMessage;
import com.king.alice.rabbitmq.delay.bean.UserMessage;
import com.king.alice.rabbitmq.delay.provider.MessageProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.Date;/*** 账号表(SysAccount)表控制层** @author makejava* @since 2023-08-09 11:40:16*/
@RestController
@Slf4j
public class SysAccountController {/*** 服务对象*/@Resourceprivate SysAccountService sysAccountService;@Autowiredprivate MessageProvider messageProvider;@PostMapping("/send-alice-message")public String sendMsg(@RequestBody AliceMessage aliceMessage) {messageProvider.sendMessage(aliceMessage);log.info("当前时间:{},收到aliceMessage请求,msg:{}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"), aliceMessage);return "success";}@PostMapping("/send-user-message")public String sendMsg(@RequestBody UserMessage userMessage) {messageProvider.sendMessage(userMessage);log.info("当前时间:{},收到userMessage请求,msg:{}", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"), userMessage);return "success";}
}
调接口
第一个策略:

控制台打印

第二个策略:

延时12秒成功接收到消息

相关文章:
一种多策略下RabbitMQ的延时队列实现
1.为什么会用到延时队列? 场景: 最近在开发一款系统中遇到这样一个场景,A系统开通套餐需要把套餐信息以邮件的形式发送给相关工作人员,经过人工审核通过后,在B系统里面开通,A系统会调B系统套餐列表接口查询套餐是否开通成功,开通成功则从A系统去完成订单,假如超过设定时间未开…...
解密 AI 客服;在不同硬件设备上运行大型语言模型的可能性
🦉 AI新闻 🚀 微软必应首席执行官称必应聊天优于OpenAI的GPT-4,但成本更高 摘要:微软必应的首席执行官米哈伊尔・帕拉欣表示,必应聊天表现优于OpenAI的GPT-4,但使用了更高成本的检索增强推理技术。必应聊…...
问题:【IntelliJ IDEA】解决idea自动声明变量加finall修饰符问题
问题:【IntelliJ IDEA】解决idea自动声明变量加finall修饰符问题 场景复现 1 new String() 2 快捷方式生成变量 final修饰的 final String s new String();步骤一:确保settings配置信息 settings-----》Editor------》Code Style--------》java下的这两个选项不…...
SpringBoot基于Zookeeper实现分布式锁
文章目录 问题背景前言实现搭建Zookeeper容器引入依赖ZK客户端的配置类ZK客户端的工厂类注入bean构建测试类 问题背景 研究分布式锁,基于ZK实现,需要整合到SpringBoot使用 前言 参考自SpringBoot集成Curator实现Zookeeper基本操作,Zookeeper入…...
AT89C51单片机实现单片机串口互动(中断方式,单片机--单片机,应答)
说一下功能:客户机发送0x01到服务机 2服务单片机应答0xf2到客户机 3客户机接收到0xf2,发送信息153432这6个数字到服务机 4client发送完信息后发送0xaa结束通信 5server接收到0xaa后回复0xaa结束通信,从此老死不相往来 看代码: //发送端…...
九耶丨阁瑞钛伦特-请说说你在工作中的PRD文档是如何撰写的?
1、背景说明(解释清楚为什么要做这样一件事,以及做这件事的价值,先把观点拉齐,才方便接下来的工作开展) 简要介绍与项目相关的背景信息、项目要满足的用户需求、开展项目的主要原因、项目期望上线时间、项目涉及的具体…...
Android免打包多渠道统计如何实现
摘要: 实际上只要完成1-2步即可实现多渠道打包,这也意味着,只要每次更新App时给出一个原始包,运营人员就能在后台自己进行操作管理,简单快捷到全程无需开发人员参与。 我们都知道,Android 市场被分割成几十…...
Apipost CICD怎么配置?
配置CI/CD Apipost自动化测试新增CI/CD,配置运行环境、循环次数、间隔停顿后点击保存会生成命令,在安装Apipost的服务器中输入命令即可运行测试脚本。 自动化测试 创建自动化测试脚本在创建好的测试用例中选择「CICD」,点击新建,…...
utf-8和utf-8 mb4区别
UTF-8(Unicode Transformation Format-8)和UTF-8MB4(UTF-8 Multibyte 4-byte)是字符编码方案,用于表示 Unicode 字符集中的字符。它们之间的主要区别在于编码范围。 UTF-8:UTF-8 是一种变长编码方式&#x…...
考研 408 | 【计算机网络】 应用层
导图 网络应用模型 客户/服务器(c/s)模型 P2P模型 DNS 域名 域名服务器 域名解析过程 文件传输协议FTP FTP服务器和用户端 FTP工作原理 电子邮件 电子邮件的信息格式 组成结构 邮件服务器的功能: 1.发送&接收邮件 2.给发件人报告邮…...
设计模式-单例
概述 在类加载后,整个系统只有一个实例类 饿汉式 public class Mg1 {private static final Mg1 INSTANCE new Mg1();private Mg1(){}public static Mg1 getInstance(){return INSTANCE;}public static void main(String[] args) {System.out.println(Mg1.getIns…...
mysql截取最后一个字符之前的数据
1、mysql截取最后一个字符之前的数据 select --截取斜杠之前的数据REVERSE(SUBSTR(REVERSE(SPNH-dfg-2012) ; --截取斜杠后的数据 INSTR(REVERSE(SPNH-fg-2012),-)1))2、mysql获取最后一个字符后的数据 select SUBSTRING_INDEX(SPNH-dfg-2012,-,-1) 3、mysql更新某个字段…...
Flutter 中,ListView 中需要放置 ListView 需要怎么处理才高效?
问题及场景 ListView 是 Flutter 开发者第一个学习到的 Widget,因为它可以滑动。一切都会运行得很好,直到 ListView 中的 Item 本身也是一个 ListView。你可能会看到 Flutter 建议你将内部的 ListView 的ShrinkWrap 属性设置为 True。虽然错误消除了&am…...
Appium Desktop安装
【提示:官方已不再维护,建议命令行方式安装,但可以学习了解一下】 Appium Desktop是一款适用于Mac、Windows和Linux的应用程序,它以漂亮灵活的UI为您提供Appium自动化服务器的强大功能。它基本上是Appium Server的图形界面。您可…...
Open3D 最小二乘拟合平面(SVD分解法)
目录 一、算法原理二、代码实现三、结果展示1、点云2、拟合结果四、优秀博客本文由CSDN点云侠原创,原文链接。爬虫网站自重。 一、算法原理 本文实现矩阵奇异值分解方法的最小二乘拟合平面。原理如下: 对于得到的 n n...
Pytorch源码搜索与分析
PyTorch的的代码主要由C10、ATen、torch三大部分组成的。其中: C10 C10,来自于Caffe Tensor Library的缩写。这里存放的都是最基础的Tensor库的代码,可以运行在服务端和移动端。PyTorch目前正在将代码从ATen/core目录下迁移到C10中。C10的代…...
运维监控学习笔记9
2、画出拓扑图的小案例: 3、在连接的线上显示网络流量,使用了一个简单的公式: {nginx-server:net.if.out[ens33].last(0)} 4、在screens中显示nginx的状态页面: 5、zabbix报警: 发送邮件的选项。Email可以使用…...
gulimall-缓存-缓存使用
文章目录 前言一、本地缓存与分布式缓存1.1 使用缓存1.2 本地缓存1.3 本地模式在分布式下的问题1.4 分布式缓存 二、整合redis测试2.1 引入依赖2.2 配置信息2.3 测试 三、改造三级分类业务3.1 代码改造 四、高并发下缓存失效问题4.1 缓存穿透4.2 缓存雪崩4.3 缓存击穿 五、分布…...
概述、搭建Redis服务器、部署LNP+Redis、创建Redis集群、连接集群、集群工作原理
Top NSD DBA DAY09 案例1:搭建redis服务器案例2:常用命令限案例3:部署LNPRedis案例4:创建redis集群 1 案例1:搭建redis服务器 1.1 具体要求如下 在主机redis64运行redis服务修改服务运行参数 ip 地址192.168.88.6…...
redis数据类型与底层数据结构对应关系
对应关系如下 SDSZipListHashTableQuickListintsetSkipListString✔Hash✔✔List✔Set✔✔Zset✔✔ String SDS Hash ZipList 对应对象编码 OBJ_ENCODING_ZIPLIST HashTable 对应对象编码 OBJ_ENCODING_HT 当一个Hash对象的键值对数据量增加到一定数量时就会触发编码转换…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
P10909 [蓝桥杯 2024 国 B] 立定跳远
# P10909 [蓝桥杯 2024 国 B] 立定跳远 ## 题目描述 在运动会上,小明从数轴的原点开始向正方向立定跳远。项目设置了 $n$ 个检查点 $a_1, a_2, \cdots , a_n$ 且 $a_i \ge a_{i−1} > 0$。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时࿰…...
Android Framework预装traceroute执行文件到system/bin下
文章目录 Android SDK中寻找traceroute代码内置traceroute到SDK中traceroute参数说明-I 参数(使用 ICMP Echo 请求)-T 参数(使用 TCP SYN 包) 相关文章 Android SDK中寻找traceroute代码 设备使用的是Android 11,在/s…...
