RabbitMQ发布订阅模式Publish/Subscribe详解
订阅模式Publish/Subscribe
- 基于API的方式
- 1.使用AmqpAdmin定制消息发送组件
- 2.消息发送者发送消息
- 3.消息消费者接收消息
- 基于配置类的方式
- 基于注解的方式
- 总结
SpringBoot整合RabbitMQ中间件实现消息服务,主要围绕3个部分的工作进行展开:定制中间件、消息发送者发送消息、消息消费者接收消息。其中,定制中间件是比较麻烦的工作,且必须预先定制。
下面以用户注册成功后,同时发送邮件通知和短信通知这一场景为例, 分别使用基于API、基于配置类和基于注解这3种方式,来实现Publish/Subscribe工作模式的整合。
基于API的方式
基于API的方式,是指使用Spring框架提供的API管理类AmqpAdmin定制消息发送组件,并进行消息的发送。这种定制消息发送组件的方式,与在RabbitMQ可视化界面上通过对应面板进行组件操作的实现基本一样,都是通过管理员的身份,预先手动声明交换器、队列、路由键等,然后组装消息队列供应用程序调用,从而实现消息服务。下面我们就对这种基于API的方式进行讲解和演示。
1.使用AmqpAdmin定制消息发送组件
我们先打开chapter08项目的测试类Chapter08ApplicationTests,在该测试类中先引入AmqpAdmin管理类定制Publish/Subscribe工作模式所需的消息组件。
package com.ytx;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class Chapter08ApplicationTests {@Autowiredprivate AmqpAdmin amqpAdmin;@Testvoid contextLoads() {}/** 使用AmqpAdmin管理员API定制消息组件 */@Testpublic void amqpAdmin() {// 1.定义fanout类型的交换器amqpAdmin.declareExchange(new FanoutExchange("fanout_exchange"));// 2.定义两个默认持久化队列,分别处理email和smsamqpAdmin.declareQueue(new Queue("fanout_queue_email"));amqpAdmin.declareQueue(new Queue("fanout_queue_sms"));// 3.将队列分别与交换器进行绑定amqpAdmin.declareBinding(new Binding("fanout_queue_email", Binding.DestinationType.QUEUE, "fanout_exchange", "", null));amqpAdmin.declareBinding(new Binding("fanout_queue_sms", Binding.DestinationType.QUEUE, "fanout_exchange", "", null));}
}
执行上述单元测试方法amqpAdmin(),验证RabbitMQ消息组件的定制效果。单元测试方法执行成功后,通过RabbitMQ可视化管理页面的Exchanges面板查看效果。

从上图可以看出,在RabbitMQ可视化管理页面的Exchanges面板中,新出现了一个名称为fanout_exchange的交换器(其他7个交换器是RabbitMQ自带的),且其类型是我们设置的fanout类型。我们可以单击fanout_exchange交换器进入查看。

从上图可以看出,在fanout_exchange交换器详情页面中展示有该交换器的具体信息,还有与之绑定的两个消息队列fanout_queue_email和fanout_queue_sms,并且与程序中设置的绑定规则一致。切换到Queues面板页面,查看定制生成的消息队列信息。

从上图可以看出,在Queues队列面板页面中,展示有定制的消息队列信息,这与程序中定制的消息队列一致,我们可以单击消息队列名称查看每个队列的详情。
通过上述操作可以发现,在管理页面中提供了消息组件交换器、队列的定制功能。在程序中使用Spring框架提供的管理员API组件AmqpAdmin,定制消息组件和在管理页面上手动定制消息组件的本质是一样的。
2.消息发送者发送消息
完成消息组件的定制工作后,创建消息发送者发送消息到消息队列中。发送消息时,我们可以借助一个实体类传递消息,需要预先创建一个实体类对象。
首先,在chapter08项目中创建名为com.cy.domain的包,并在该包下创建一个实体类User。
package com.ytx.domain;/** 发布消息的实体类可以通过实现Serializable序列化接口进行发布 */
public class User {private Integer id;private String username;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +'}';}
}
其次,我们在项目测试类Chapter08ApplicationTests中,使用Spring框架提供的RabbitTemplate模板类实现消息发送。
@Autowired
private RabbitTemplate rabbitTemplate;/** 1.Publish/Subscribe工作模式消息发送端 */
@Test
public void subPublisher() {User user = new User();user.setId(1);user.setUsername("小明");rabbitTemplate.convertAndSend("fanout_exchange", "", user);
}
上述代码中,我们先使用@Autowired注解,引入消息中间件管理的RabbitTemplate组件对象,然后使用该模板工具类的convertAndSend(String exchange, String routingKey, Object object)方法进行消息发布。此方法中的第1个参数表示发送消息的交换器,这个参数值要与之前定制的交换器名称一致;第2个参数表示路由键,因为实现的是Publish/Subscribe工作模式,所以不需要指定;第3个参数是发送的消息内容,接收Object类型。
然后,执行上述消息发送的测试方法subPublisher(),控制台执行效果见下图所示。

从上图可以看出,发送实体类对象消息时程序发生异常,从异常信息“SimpleMessageConverter only supports String, byte[] and Serializable payloads”可以看出,消息发送过程中默认使用了SimpleMessageConverter转换器进行消息转换存储,该转换器只支持字符串或实体类对象序列化后的消息。而测试类中发送的是User实体类对象消息,所以发生异常。
如果要解决上述消息中间件发送实体类消息出现的异常,我们通常可以采用两种解决方案:第一种是执行JDK自带的Serializable序列化接口;第二种是定制其他类型的消息转化器。两种实现方式都可行,相对于第二种实现方式而言,第一种方式实现后的可视化效果较差,转换后的消息无法辨识,所以一般使用第二种方式。
接着我们在chapter08项目中创建名为com.ytx.config的包,并在该包下创建一个RabbitMQ消息配置类RabbitMQConfig。
package com.ytx.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/** RabbitMQ消息配置类 */
@Configuration
public class RabbitMQConfig {/** 定制JSON格式的消息转换器 */@Beanpublic MessageConverter messageConverter() {return new Jackson2JsonMessageConverter();}
}
代码中创建一个RabbitMQ消息配置类RabbitMQConfig,并在该配置类中通过@Bean注解自定义一个Jackson2JsonMessageConverter类型的消息转换器组件,该组件的返回值必须为MessageConverter类型。
再次执行subPublisher()方法,该方法执行成功后,查看RabbitMQ可视化管理页面Queues面板信息。

从上图可以看出,消息发送完成后,Publish/Subscribe工作模式下绑定的两个消息队列中各自拥有一条待接收的消息, 由于目前尚未提供消息。

3.消息消费者接收消息
在chapter08项目中创建名为com.ytx.service的包,并在该包下创建一个针对RabbitMQ消息中间件进行消息接收和处理的业务类RabbitMQService。
package com.ytx.chapter08.service;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;/** RabbitMQ消息接收处理的业务类 */
@Service
public class RabbitMQService {/** Publish/Subscribe工作模式接收,处理邮件业务 */@RabbitListener(queues = "fanout_queue_email")public void subConsumerEmail(Message message) {byte[] body = message.getBody();String msg = new String(body);System.out.println("邮件业务接收到消息:" + msg);}/** Publish/Subscribe工作模式接收,处理短信业务 */@RabbitListener(queues = "fanout_queue_sms")public void subConsumerSms(Message message) {byte[] body = message.getBody();String msg = new String(body);System.out.println("短信业务接收到消息:" + msg);}
}
上述代码中,创建了一个接收处理RabbitMQ消息的业务处理类RabbitMQService,在该类中使用Spring框架提供的@RabbitListener注解,我们可以监听队列名称为fanout_queue_email和fanout_queue_sms的消息,监听的这两个队列是前面指定发送并存储消息的消息队列。
需要说明的是,使用@RabbitListener注解监听队列消息后,一旦服务启动且监听到指定的队列中有消息存在(目前两个队列中各有一条相同的消息),对应注解的方法就会立即接收并消费队列中的消息。另外,在接收消息的方法中,参数类型可以与发送的消息类型保持一致,或者使用Object类型和Message类型。如果使用与消息类型对应的参数接收消息的话,只能够得到具体的消息体信息;如果使用Object或者Message类型参数接收消息的话,还可以获得除了消息体外的消息参数信息MessageProperties。
启动chapter08项目,控制台显示的消息消费效果如下图所示。

从上图可以看出,项目启动成功后,消息消费者监听到消息队列中存在的两条消息,并进行了各自的消费。与此同时,通过RabbitMQ可视化管理页面的Queues面板查看队列消息情况,会发现两个队列中存储的消息已经被消费。至此,一条完整的消息发送、 消息中间件存储、消息消费的Publish/Subscribe(发布订阅模式)工作模式的业务案例已经实现。
注意,如果没有引入Spring Web模块的依赖,启动chapter08项目时,消息消费者接收消息会报以下错误。
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.amqp.support.converter.MessageConverter]: Factory method 'messageConverter' threw exception; nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/ObjectMapperat org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.3.25.jar:5.3.25]at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.25.jar:5.3.25]... 18 common frames omitted
小提示:
上述代码中,使用的是开发中常用的@RabbitListener注解,来监听指定名称队列的消息情况,这种方式会在监听到指定队列存在消息后立即进行消费处理。除此之外,我们还可以使用RabbitTemplate模板类的receiveAndConvert(String queueName)方法手动消费指定队列中的消息。
基于配置类的方式
基于配置类的方式,主要讲的是使用SpringBoot框架提供的@Configuration注解,配置定制消息发送组件,并进行消息发送。下面我们来对这种基于配置类的方式进行讲解和演示。
打开RabbitMQ消息配置类RabbitMQConfig,在该配置类中使用基于配置类的方式定制消息发送相关组件。
package com.ytx.config;
import org.springframework.amqp.core.*;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/** RabbitMQ消息配置类 */
@Configuration
public class RabbitMQConfig {/** 定制JSON格式的消息转换器 */@Beanpublic MessageConverter messageConverter() {return new Jackson2JsonMessageConverter();}/** 使用基于配置类的方式定制消息中间件 */// 1.定义fanout类型的交换器@Beanpublic Exchange fanoutExchange() {return ExchangeBuilder.fanoutExchange("fanout_exchange").build();}// 2.定义两个不同名称的消息队列@Beanpublic Queue fanoutQueueEmail() {return new Queue("fanout_queue_email");}@Beanpublic Queue fanoutQueueSms() {return new Queue("fanout_queue_sms");}// 3.将两个不同名称的消息队列与交换器进行绑定@Beanpublic Binding bindingEmail() {return BindingBuilder.bind(fanoutQueueEmail()).to(fanoutExchange()).with("").noargs();}@Beanpublic Binding bindingSms() {return BindingBuilder.bind(fanoutQueueSms()).to(fanoutExchange()).with("").noargs();}
}
上述代码中,使用@Bean注解定制了3种类型的Bean组件,这3种组件分别表示交换器、消息队列和消息队列与交换器的绑定。这种基于配置类方式定制的消息组件,其实现和基于API方式定制的消息组件完全一样,只不过是实现方式不同而已。
按照消息服务整合实现步骤,完成消息组件的定制后,还需要编写消息发送者和消息消费者,而在基于API的方式中已经实现了消息发送者和消息消费者,并且基于配置类方式定制的消息组件名称,和之前测试用的消息发送和消息消费组件名称都是一致的,所以这里我们可以直接重复使用。
重新运行消息发送者测试方法subPublisher(),消息消费者可以自动监听并消费消息队列中存在的消息,效果与基于API的方式测试效果一样。
基于注解的方式
基于注解的方式指的是使用Spring框架的@RabbitListener注解定制消息发送组件并发送消息。
在消息接收和处理的业务类RabbitMQService中,将针对邮件业务和短信业务处理的消息消费者方法进行注释,使用@RabbitListener注解及其相关属性定制消息发送组件。
package com.ytx.chapter08.service;
import com.ytx.chapter08.domain.User;
import org.springframework.amqp.core.Message;
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.Service;/** RabbitMQ消息接收处理的业务类 */
@Service
public class RabbitMQService {/** Publish/Subscribe工作模式接收,处理邮件业务 *//*@RabbitListener(queues = "fanout_queue_email")public void subConsumerEmail(Message message) {byte[] body = message.getBody();String msg = new String(body);System.out.println("邮件业务接收到消息:" + msg);}*//** Publish/Subscribe工作模式接收,处理短信业务 *//*@RabbitListener(queues = "fanout_queue_sms")public void subConsumerSms(Message message) {byte[] body = message.getBody();String msg = new String(body);System.out.println("短信业务接收到消息:" + msg);}*//** 使用基于注解的方式实现消息服务 */// 1.1 Publish/Subscribe工作模式接收,处理邮件业务@RabbitListener(bindings = @QueueBinding(value = @Queue("fanout_queue_email"),exchange = @Exchange(value = "fanout_exchange", type = "fanout")))public void subConsumerEmailAno(User user) {System.out.println("邮件业务接收到消息:" + user);}// 1.2 Publish/Subscribe工作模式接收,处理短信业务@RabbitListener(bindings = @QueueBinding(value = @Queue("fanout_queue_sms"),exchange = @Exchange(value = "fanout_exchange", type = "fanout")))public void subConsumerSmsAno(User user) {System.out.println("短信业务接收到消息:" + user);}
}
上述代码中,使用@RabbitListener注解及其相关属性定制了两个消息组件的消费者,这两个消费者都接收实体类User并消费。在@RabbitListener注解中,bindings属性用于创建并绑定交换器和消息队列组件,需要注意的是,为了能使两个消息组件的消费者接收到实体类User,需要我们在定制交换器时将交换器类型type设置为fanout。另外,bindings属性的@QueueBinding注解除了有value、exchange属性外,还有key属性用于定制路由键routingKey(当前发布订阅模式不需要)。
重启测试方法subPublisher(),消息消费者可以自动监听并消费消息队列中存在的消息,效果与基于API的方式测试效果一样。
至此,我们就在SpringBoot中完成了基于API、基于配置类和基于注解这3种方式,来实现Publish/Subscribe工作模式的整合讲解。在这3种实现消息服务的方式中,基于API的方式相对简单、直观,但容易与业务代码产生耦合;基于配置类的方式相对隔离、容易统一管理、符合Spring Boot框架思想;基于注解的方式清晰明了、方便各自管理,但是也容易与业务代码产生耦合。
在实际开发中,使用基于配置类的方式和基于注解的方式较为常见,基于API的方式则偶尔使用,当然大家要根据实际情况进行具体选择。
总结
今天介绍了基于API方式、配置类方式和注解的3种消息队列,并展示了实现发布订阅Publish/Subscribe模式的整合及代码实现,基于注解方式的实现需要重点掌握。有关RabbitMQ的其他内容,袁老后续更新
相关文章:
RabbitMQ发布订阅模式Publish/Subscribe详解
订阅模式Publish/Subscribe 基于API的方式1.使用AmqpAdmin定制消息发送组件2.消息发送者发送消息3.消息消费者接收消息 基于配置类的方式基于注解的方式总结 SpringBoot整合RabbitMQ中间件实现消息服务,主要围绕3个部分的工作进行展开:定制中间件、消息发…...
Android8.1源码下对APK进行系统签名
在Android8.1上面对APK进行Android系统源码环境下的签名,发现签名时出现如下错误: Exception in thread "main" java.lang.ExceptionInInitializerError at org.conscrypt.OpenSSLBIOInputStream.(OpenSSLBIOInputStream. at org.conscrypt.OpenSSLX509Certificat…...
2024年城市客运安全员考试题库及答案
一、单选题 376.根据《机动车运行安全技术条件》(GB7258---2017),每个应急出口应在其附近设有"应急出口"字样,字体高度应大于或等于()mm。 A.20 B.30 C.40 D.50 答案:C 377.根…...
全网最全面的Nginx内容(理论与实践相结合)
一、Web服务 1.1 web服务访问流程 1.2 Web服务 1.2.1 Web服务器分类 Web服务分为Apache和Nginx 1.2.2 Apache经典的Web服务器 1.2.2.1 Apache介绍 Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,可以…...
(七)Flink Watermark
Flink 的 Watermark 是用来标识数据流中的一个时间点。Watermark 的设计是为了解决乱序数据处理的问题,尤其是涉及到多个分区的 Kafka 消费者时。在 Watermark 的作用下,即使某些数据出现了延迟到达的情况,也不会导致整个处理流程的中断。此外,Watermark 还能防止过期的数据…...
springboot 上传文件失败:The temporary upload location
Caused by: java.io.IOException: The temporary upload location [/tmp/tomcat.379776875189163783.8081/work/Tomcat/localhost/jcys-core] is not valid 原因: Linux下会自动清除tmp目录下10天没有使用过的文件,SpringBoot启动的时候会在/tmp目录下生…...
UNiapp之微信小程序导出Excel
效果如下 参考小程序:日常记一记 ---账单页面 主要功能是根据筛选条件导出账单明细列表,实现该功能主要借助一个工具(excel.js),可在文章顶部下载或者一下网盘下载 https://pan.baidu.com/s/1RLisuG4_7FGD0Cnwewyabg?pwdpd2a 提取码: pd2a…...
fsadsadsad
adsadsafsada...
高效录制新选择:2024年Windows录屏软件
录屏能帮助我们捕捉屏幕上的精彩瞬间,作为老师可以用来录制课程,作为会议记录员可以用来录制远程会议。那么有什么软件是适合windows录屏的呢?这次我们一起来探讨一下吧。 1.福昕录屏大师 链接:www.foxitsoftware.cn/REC/ 这款软…...
Java技术面试(一面)
1、相面对象 1、面相对象语言/Java三大特性是什么? 引出 封装、继承和多态。 2、多态有哪些形式?多态使用过吗? 重载、重写,接口和抽象类的多个实现。考察工作经验、代码重构经验、习惯。 3、Java接口和抽象类有什么区别?你是如何选择使用的? 考察OOP的理解和工作…...
docker修改数据目录
新建docker数据目录 mkdir /data/docker-data停止docker服务 systemctl stop docker把docker数据迁移到新目录 cp -r /var/lib/docker/* /data/docker-data/修改docker配置 vi /etc/docker/daemon.json #添加data-root参数 {"data-root":"/data/docker-dat...
Appium学习
一、基础配置 import unittest from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support …...
回顾 | 瑞云科技亮相ICIC2024,虚拟仿真实训云平台引关注
2024年8月7日,天津市虚拟仿真学会主办的第二十届智能计算国际会议(ICIC2024)——虚拟仿真技术交流平行会议暨天津市虚拟仿真学会2024年暑期技术交流会在天津盛大召开。本次大会汇聚来自全国的顶尖专家、学者和行业领袖,共同探讨虚…...
libLZMA库iOS18平台编译
1.下载xz源码: 使用autogen.sh生成configure文件 2.生成makefile rm -rf ./build/iOS && mkdir -p ./build/iOS && cd ./build/iOS && ../../configure --host=arm-apple-darwin64 --prefix=`pwd`/Frameworks/lzma CC="xcrun -sdk iphoneos cl…...
《AI办公类工具PPT系列之二——iSlide AI》
一.简介 官网:iSlide- 让PPT设计简单起来 | PPT模板下载平台 iSlide AI是一款基于人工智能技术的PPT制作工具,它可以帮助用户快速高效地创建演示文稿 二.功能介绍 1. AI一键生成PPT 文档导入与解析:用户可以直接上传本地文档(如Word、Markdown、思维导图等),iSlide A…...
C语言基础(六)
一维数组: C语言中的数组是一种基本的数据结构,用于在计算机内存中连续存储相同类型的数据。 数组中的每个元素可以通过索引(或下标)来访问,索引通常是从0开始的。 数组的大小在声明时确定,并且之后不能改…...
什么是词向量?如何得到词向量?Embedding 快速解读
我第一次接触 Embedding 是在 Word2Vec 时期,那时候还没有 Transformer 和 BERT 。Embedding 给我的印象是,可以将词映射成一个数值向量,而且语义相近的词,在向量空间上具有相似的位置。 有了 Embedding ,就可以对词进…...
AI视频创作应用
重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…...
JAVA常见的工具类之Object类(超详细)
1、Java API简介 Java API(Java Application Programming Interface)是Java应用程序编程接口的缩写。Java中的API,就是JDK提供的具有各种功能的Java类,灵活使用Java API能够大大提高使用Java语言编写程序的效率。 Java API的帮助文档可到 http://docs.or…...
深度学习(YOLO、DETR) 十折交叉验证
二:交叉验证 在 K 折验证之前最常用的验证方法就是交叉验证,即把数据划分为训练集、验证集和测试集。一般的划分比例为 7:1:2。但如何合理的抽取样本就成为了使用交叉验证的难点,不同的抽取方法会导致截然不同的训练性…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
《基于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…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
