WebSocket Day04 : 消息推送
前言
随着Web应用程序的不断发展,实时性和交互性成为了用户体验中至关重要的一部分。传统的HTTP协议在处理实时数据传输方面存在一些局限性,而WebSocket作为一种全双工通信协议,为实现实时、高效的消息推送提供了全新的解决方案。
在Web开发领域,消息推送是一项重要的功能,它使得服务器能够将实时更新的信息主动推送给客户端,而不需要客户端频繁地向服务器发送请求。借助于WebSocket技术,开发人员能够轻松构建具有实时交互功能的Web应用程序,例如在线聊天、实时数据监控、多人协作编辑等。
一、前期准备
1、新建项目,结构如下
2、导入依赖
<!-- websocket 依赖 --><dependency><groupId>javax.websocket</groupId><artifactId>javax.websocket-api</artifactId><version>1.1</version><scope>provided</scope></dependency><!-- 打印日志 --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.3.8</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><!-- ch02 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.2</version></dependency><!-- ch03 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version></dependency><!-- 在 spring 4.0 开始支持--><dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>5.3.23</version></dependency><!-- ch04 --><!-- 如果想要使用 Spring 的消息代理,则添加以下依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>5.3.23</version></dependency>
每一个依赖的作用:
javax.websocket-api: 这是Java API for WebSocket的依赖声明,版本为1.1。它提供了在Java应用程序中使用WebSocket所需的接口和类。
logback-classic: 这是Logback日志框架的经典模块,版本为1.3.8。Logback是一个灵活而功能强大的日志框架,它可以代替log4j系统。
lombok: Lombok是一个Java库,可以通过注解的方式来简化Java代码的开发。它通过消除样板代码(boilerplate code)来提高开发效率。
javax.servlet-api: 这是Java Servlet API的依赖声明,版本为4.0.1。它提供了使用Java语言编写的Web应用程序中的Servlet和JSP规范。
jackson-databind: Jackson是Java中用于处理JSON数据的流行库,databind模块提供了JSON和Java对象之间的转换功能。
spring-webmvc: 这是Spring框架中的Web MVC模块的依赖声明,版本为5.3.23。它提供了创建基于Spring的Web应用程序的支持。
spring-websocket: 这是Spring框架中的WebSocket模块的依赖声明,版本为5.3.23。它提供了对WebSocket的支持,使得在Spring应用程序中能够方便地集成和使用WebSocket。
spring-messaging: 这是Spring框架中的消息代理模块的依赖声明,版本为5.3.23。它提供了在Spring应用程序中实现消息代理的支持。
以上依赖项将会为您的项目引入WebSocket所需的API、日志、简化代码、Servlet支持以及Spring框架的相关模块,让您可以方便地开发基于WebSocket的Web应用程序,并且与Spring框架无缝集成。
3、配置配置类
1)MvcConfig 类
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}
}
让我解释一下它的作用:
@Configuration
: 这个注解表示这是一个配置类,它会被Spring容器识别并用来配置应用程序上下文。
@EnableWebMvc
: 这个注解启用了Spring MVC,它会在Spring中注册必要的组件,如HandlerMapping、HandlerAdapter等,以支持基于注解的控制器方法。
implements WebMvcConfigurer
: MvcConfig类实现了WebMvcConfigurer接口,这样可以重写一些默认配置,自定义MVC的行为。
configureDefaultServletHandling
: 这是WebMvcConfigurer接口中的一个方法,通过重写这个方法,我们可以配置静态资源的处理。在这里的配置中,configurer.enable()
启用了默认的Servlet处理,允许DispatcherServlet将对静态资源的请求转发到Servlet容器的default servlet。
总的来说,这段代码配置了Spring MVC,并且使得Spring能够处理静态资源的请求,从而使得静态资源可以被正确地访问和展示。
2)WebSocket 类
@Configuration
// 启用 webSocket 消息代理中间件
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {/*** 注册一个连接消息中间件的端点( 路径url )* @param registry*/@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("broker");}/*** 配置消息代理,主要是设置相关的主题* 消息代理是服务中心的核心,spring-websocket 内置了* 一个简单的消息代理,但也只能够满足基本要求,如果* 需要强大的消息中心的功能,通常都会集成第三方的消息队列* 例如:RabbitMQ 等* @param registry*/@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {// 启用 Spring 内置简单的消息代理并设置一个主题(topic)的前缀// 用于消息的发布和订阅registry.enableSimpleBroker("/news","video");// 如果需要集成外部其他的消息代理,使用下面等等方法// registry.enableStompBrokerRelay();}
}
让我来解释一下它的作用:
@Configuration
: 这个注解表示这是一个配置类,它会被Spring容器识别并用来配置应用程序上下文。
@EnableWebSocketMessageBroker
: 这个注解启用了基于消息代理的WebSocket支持,它会为您的应用程序提供了实时的、双向通信能力。
implements WebSocketMessageBrokerConfigurer
: WebSocketConfig类实现了WebSocketMessageBrokerConfigurer接口,这样可以重写一些默认配置,自定义WebSocket的行为。
registerStompEndpoints
: 在这个方法中,我们注册了一个STOMP端点(也就是WebSocket端点),客户端可以通过该端点进行连接。在这里的配置中,我们注册了一个名为"broker"的端点,客户端将使用这个端点来建立WebSocket连接。
configureMessageBroker
: 这个方法用来配置消息代理,主要是设置相关的主题。在这里的配置中,我们启用了Spring内置的简单消息代理,并设置了两个主题的前缀 "/news" 和 "/video",用于消息的发布和订阅。这样客户端就可以订阅这些主题,从而接收相关的消息。
总的来说,这段代码配置了Spring WebSocket的消息代理中间件,使得应用程序能够通过WebSocket进行实时的双向通信,同时设置了相关的主题,以便客户端可以订阅并接收相应的消息。
3)AppConfig 类
@Configuration
@ComponentScan(basePackages = "edu.nf.ch04")
@Import({MvcConfig.class,WebSocketConfig.class})
public class AppConfig {
}
让我来解释一下它的作用:
@Configuration
: 这个注解表示这是一个配置类,它会被Spring容器识别并用来配置应用程序上下文。
@ComponentScan(basePackages = "edu.nf.ch04")
: 这个注解指定了Spring容器在初始化时要扫描的包路径,以寻找带有特定注解的组件。在这里的配置中,容器会扫描"edu.nf.ch04"包及其子包,寻找带有@Component
、@Service
、@Repository
等注解的组件,并将它们纳入Spring容器管理。
@Import({MvcConfig.class, WebSocketConfig.class})
: 这个注解用于导入其他的配置类,将其配置加入到当前的配置类中。在这里的配置中,AppConfig类导入了MvcConfig和WebSocketConfig两个配置类,从而将它们的配置内容整合到当前的配置中。
总的来说,这段代码配置了Spring应用程序的整体配置信息,包括了组件扫描的包路径以及导入了其他的配置类,从而将整个应用程序的配置信息整合在一起。
4)WebConfig 类
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[0];}@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{AppConfig.class};}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}
}
这段代码是一个典型的Spring Web应用程序的配置类,它继承自AbstractAnnotationConfigDispatcherServletInitializer
,用于替代传统的web.xml文件,让我来解释一下它的作用:
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer
: 这个类是Web应用程序的初始化类,它相当于web.xml文件中的配置。
@Override protected Class<?>[] getRootConfigClasses() { return new Class[0]; }
: 在这个方法中,我们返回一个空数组,表示不需要加载根配置类。通常,根配置类用来配置数据源、持久层框架、安全框架等应用程序级别的组件,但在这里我们没有定义。
@Override protected Class<?>[] getServletConfigClasses() { return new Class[]{AppConfig.class}; }
: 在这个方法中,我们返回一个包含AppConfig类的数组,表示加载Web应用程序的配置类。在这里,我们将之前提到的AppConfig配置类加载到Servlet上下文中,这样就可以使用其中定义的Bean。
@Override protected String[] getServletMappings() { return new String[]{"/"}; }
: 这个方法返回一个包含"/"路径的字符串数组,表示DispatcherServlet要映射的路径。在这里的配置中,DispatcherServlet会映射到应用程序的根路径,即所有的请求都会交给DispatcherServlet进行处理。
总的来说,这段代码配置了Spring Web应用程序的初始化信息,包括加载Web应用程序的配置类、指定DispatcherServlet的映射路径等,从而取代了传统的web.xml文件。
4、封装一个信息类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {private String content;private String sendTime;}
让我来解释一下使用到的注解和它的作用:
@Data
: 这是Lombok库提供的一个注解,它会为类自动生成一些通用的方法,如toString()
、equals()
、hashCode()
等,以及针对每个字段的getters
和setters
方法。使用@Data
注解可以减少样板代码,让类看起来更简洁。
@AllArgsConstructor
: 这是Lombok库提供的另一个注解,它会为类生成一个包含所有字段的构造方法,这样就不需要手动编写构造方法。
@NoArgsConstructor
: 这也是Lombok库提供的注解,它会生成一个无参的构造方法。
private String content;
: 这行代码定义了一个私有字段content
,用于存储消息的内容。
private String sendTime;
: 这行代码定义了另一个私有字段sendTime
,用于存储消息的发送时间。
总的来说,这段代码使用了Lombok库的注解来自动生成通用方法和构造方法,从而简化了代码编写。同时,定义了一个简单的Java类Message
,用于表示消息对象,包括消息内容和发送时间两个属性。
二、编写 controller 类,实现通知
@RestController
@RequiredArgsConstructor
public class PublishController {/*** 消息处理模板,用于发布消息*/private final SimpMessagingTemplate template;/*** 后台发布消息* @param message*/@PostMapping("/publish/{topic}/{sub}")public void publish(@PathVariable("topic") String topic,@PathVariable("sub")String sub, String message){// 创建一个时间String sendTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());Message msg = new Message(message,sendTime);// 将消息发布到消息代理指定的主题中template.convertAndSend("/"+ topic +"/" + sub,msg);}}
这段代码是一个Spring框架中的REST控制器类PublishController
,它使用了一些注解和依赖注入,让我来逐步解释:
@RestController
: 这个注解表示该类是一个RESTful风格的控制器,它将处理传入的HTTP请求,并返回相应的HTTP响应。相比于@Controller
注解,它会自动将返回结果转换为JSON格式。
@RequiredArgsConstructor
: 这是Lombok库提供的注解,它会为类中标记了final
的字段生成一个构造方法,用于进行依赖注入。在这里,它的作用是为template
字段生成一个构造方法,实现依赖注入。
private final SimpMessagingTemplate template;
: 这行代码定义了一个私有的、不可变的SimpMessagingTemplate
类型的字段template
,用于向WebSocket消息代理发送消息。
@PostMapping("/publish/{topic}/{sub}")
: 这是一个用于处理HTTP POST请求的方法级注解,表示对应的publish
方法将处理POST请求,并且在路径中包含了两个占位符{topic}
和{sub}
。
public void publish(@PathVariable("topic") String topic, @PathVariable("sub") String sub, String message)
: 这是一个处理POST请求的方法,它接受三个参数,其中@PathVariable
注解表示从URL中获取路径参数。方法内部首先创建了消息对象msg
,然后使用SimpMessagingTemplate
将消息发布到指定的主题中。
总的来说,这个PublishController
类是一个RESTful风格的控制器,用于处理POST请求,并通过SimpMessagingTemplate
向WebSocket消息代理发布消息。
三、编写页面
1、admin.html --- 发送信息后台
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/JQuery文件.txt.js"></script>
</head>
<body>
<h1>后台管理</h1>
<form id="f1">
<select id="topic"><option value="sport">体育</option><option value="recreation">娱乐</option>
</select><input type="text" name="message" id="message"/>
<input type="button" value="发布">
</form><script>$(function () {$(':button').on('click',function () {let param = $('#f1').serialize();let subTopic = $('#topic').val();// alert(subTopic)$.ajax({url:'../publish/news/' + subTopic,type:'post',data:param,success:function ( data ) {$('#message').val('');}})})})
</script></body>
</html>
2、index.html --- 体育栏目
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/JQuery文件.txt.js"></script><script src="js/stomp.min.js"></script></head>
<body>
<h1>体育</h1><div id="msg"></div><script>$(function () {// 创建 WebSocket 对象var ws = new WebSocket("ws://localhost:8080/broker");// 将 WebSocket 包装成 stomp 客户端let stompClient = Stomp.over(ws);// 连接服务器并订阅消息stompClient.connect({},function () {// 执行订阅stompClient.subscribe('/news/sport',function ( data ) {// 接收发布的通知内容// alert(data);// 取出 stomp 中的 body 部分并解析为 json 对象let msg = $.parseJSON(data.body);$('#msg').append(msg.sendTime + '<br>');$('#msg').append(msg.content + '<br>')})})})
</script></body>
</html>
让我来逐行解释上述代码的含义:
var ws = new WebSocket("ws://localhost:8080/broker");
- 这一行创建了一个WebSocket对象,并指定了连接的URL为"ws://localhost:8080/broker"。这将尝试连接到本地主机上的WebSocket服务器,并订阅了"/broker"频道。
let stompClient = Stomp.over(ws);
- 这一行使用了STOMP(Simple Text Oriented Messaging Protocol)库,通过WebSocket创建了一个STOMP客户端对象。
stompClient.connect({}, function () {...});
- 这段代码表示当STOMP客户端成功连接到服务器时,执行后续的操作。
stompClient.subscribe('/news/sport', function (data) {...});
- 在连接成功后,客户端订阅了"/news/sport"频道,用于接收体育新闻。当有消息到达时,会执行回调函数,并将消息的发送时间和内容显示在页面上。
总体来说,这段代码的作用是在页面加载后,通过WebSocket连接到服务器,订阅体育新闻频道,并将接收到的消息动态显示在页面上。
2、index2.html --- 娱乐栏目
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/JQuery文件.txt.js"></script><script src="js/stomp.min.js"></script></head>
<body>
<h1>娱乐</h1><div id="msg"></div><script>$(function () {// 创建 WebSocket 对象var ws = new WebSocket("ws://localhost:8080/broker");// 将 WebSocket 包装成 stomp 客户端let stompClient = Stomp.over(ws);// 连接服务器并订阅消息stompClient.connect({},function () {// 执行订阅stompClient.subscribe('/news/recreation',function ( data ) {// 接收发布的通知内容// alert(data);// 取出 stomp 中的 body 部分并解析为 json 对象let msg = $.parseJSON(data.body);$('#msg').append(msg.sendTime + '<br>');$('#msg').append(msg.content + '<br>')})})})
</script></body>
</html>
这部分代码和体育栏目的是一样的。
四、测试
我们每次发送的通知都是实时的通知,在做一些有通知的功能时就能用到这个案例,实时的发布系统通知。
五、gitee 案例
地址:ch04 · qiuqiu/WebSocket-study - 码云 - 开源中国 (gitee.com)
相关文章:

WebSocket Day04 : 消息推送
前言 随着Web应用程序的不断发展,实时性和交互性成为了用户体验中至关重要的一部分。传统的HTTP协议在处理实时数据传输方面存在一些局限性,而WebSocket作为一种全双工通信协议,为实现实时、高效的消息推送提供了全新的解决方案。 在Web开发…...

【Hadoop】MapReduce详解
🦄 个人主页——🎐开着拖拉机回家_大数据运维-CSDN博客 🎐✨🍁 🪁🍁🪁🍁🪁🍁🪁🍁 🪁🍁🪁…...

ctf之流量分析学习
链接:https://pan.baidu.com/s/1e3ZcfioIOmebbUs-xGRnUA?pwd9jmc 提取码:9jmc 前几道比较简单,是经常见、常考到的类型 1.pcap——zip里 流量分析里有压缩包 查字符串或者正则表达式,在包的最底层找到flag的相关内容 我们追踪…...

Linux——vim简介、配置方案(附带超美观的配置方案)、常用模式的基本操作
vim简介、配置方案、常用模式的基本操作 本章思维导图: 注:本章思维导图对应的xmind和.png文件都已同步导入至资源 1. vim简介 vim是Linux常用的文本编辑器,每个Linux账户都独有一个vim编辑器 本篇我们介绍vim最常用的三种模式:…...

在线预览编辑PDF::RAD PDF for ASP.NET
RAD PDF for ASP.NET作为功能最齐全的基于 HTML 的 PDF 查看器、编辑器和 ASP.NET 表单填充器,RAD PDF 为传统 PDF 解决方案提供了灵活而强大的替代方案。与 Adobe Acrobat Reader 不同,RAD PDF 几乎可以在任何现代网络浏览器中运行,…...

【赠书第4期】机器学习与人工智能实战:基于业务场景的工程应用
文章目录 前言 1 机器学习基础知识 2 人工智能基础知识 3 机器学习和人工智能的实战案例 4 总结 5 推荐图书 6 粉丝福利 前言 机器学习与人工智能是当前最热门的领域之一,也是未来发展的方向。随着科技的不断进步,越来越多的企业开始关注和投入机…...

npm封装插件打包上传后图片资源错误
问题: npm封装插件:封装的组件页面涉及使用图片资源,在封装的项目里调用图片显示正常;但是打包上传后,其他项目引入使用报错找不到图片资源;图片路径也不对 获取图片的base64方法 解决方案: 将…...

[云原生案例2.3 ] Kubernetes的部署安装 【多master集群架构高可用 ---- (二进制安装部署)】
文章目录 1. Kubernetes多Master集群高可用方案1.1 多节点Master高可用的实现过程1.2 实现高可用方法 2. 新Master节点的部署2.1 前置准备2.2 系统初始化操作2.2.1 关闭防火墙、selinux和swap分区2.2.2 修改主机名,添加域名映射2.2.3 修改内核参数2.2.4 时间同步 2.…...

归并排序(含递归和非递归版)
以梦为马,不负韶华 文章目录 引入:实现原理问题引出:递归实现:迭代实现稳定性分析:总结: 引入: 如何将两个有序数组(假设为升序)合并为一个有序数组? 双指针…...

微服务的注册发现和微服务架构下的负载均衡
文章目录 微服务注册模型服务注册与发现怎么保证高可用【1. 服务端崩溃检测】【2. 客户端容错】【3. 注册中心选型】 微服务架构下的负载均衡【1.轮询与加权轮询】【2.随机与加权随机】【3.哈希与一致性哈希】【4.最少连接数】【5.最少活跃数】【6.最快响应时间】【总结】 负载…...
从混沌到有序:sortedcontainers库的数据魔法改变你的编程体验
前言 在当今数据爆炸的时代,高效地处理和操作数据成为每位Python开发者的核心任务。在这个背景下,sortedcontainers库以其强大的有序数据结构为程序员提供了处理大规模数据的优越选择。本文将深入研究sortedcontainers库中的主要有序数据结构࿰…...
读取pdf、docx、doc、ppt、pptx并转为txt
文章目录 一、思路构建二、开始实现三、存在的问题3.1 解析doc文档遇到问题及解决方法:3.2 解析ppt文档遇到问题及解决方法: 四、读取pdf中的图片 一、思路构建 Zip文件和初始化文件放在同一个文件夹下;然后解析zip文件读取到一个新的文件夹…...

11.13/14 理解SDK框架遇到的问题
1.1.浮点数打印问题 float red_increment (target_red_value - initial_red_value) / STEPS; u8 STEPS 100; printf("绿色值每一次增量------%f\n", red_increment); 后面三个参数均为u8类型 希望采用 %f打印出每次的步进值。但是结果为空白 希望采用 %.2f打印…...

计算机网络——b站王道考研笔记
第一章 计算机网络体系结构 1.计算机网络概述 (1)概念 计算机网络是一个将分散的,具有独立功能的计算机系统,通过通信设备与线路连接起来,由功能完善的软件实现资源共享和信息传递的系统; 是互连的&#…...
Stm32_标准库_18_串口蓝牙模块_手机与蓝牙模块通信_控制LED灯亮灭
通过输入LED_ON和LED_OFF分别控制LED灯的亮与灭 接线: LED的正极接正电,负极接GPIOA_Pin1 蓝牙模块TXD接GPIOA_Pin3,VCC接正电,GND接负电 注意:USART2是APB1外设,汉字占用字节数是字符的两倍 使用: 手…...
低代码与传统开发:综合比较
近年来,低代码开发作为软件开发的趋势获得了显着的发展势头。根据 MarketsandMarkets 的数据,低代码开发市场预计将实现 28.1% 的大幅增长率,到 2025 年价值将达到 455 亿美元。这一显着增长表明了各行业和企业对低代码平台的需求和采用不断增…...

pyqt环境搭建
创建虚拟环境 # 用管理员身份运行 conda create --prefixE:\Python\envs\pyqt5stu python3.6 # 激活虚拟环境 conda activate E:\Python\envs\pyqt5stu # 退出虚拟环境 conda deactivate安装包 pip install PyQt5 -i https://pypi.douban.com/simple pip install PyQt5-tools…...

JavaScript数据类型和存储区别
目录 一、原始数据类型 二、引用数据类型 三、存储区别 四、常见错误 JavaScript是一种动态类型语言,这意味着变量可以在程序执行过程中改变其数据类型。了解JavaScript中的数据类型和它们的存储方式对于编写高效和可维护的代码至关重要。 在JavaScript中&…...

Java学习笔记(七)——面向对象编程(中级)
一、IDEA (一)常用的快捷键 (二)模版/自定义模版 二、包 (一)包的命名 (二)常用的包 (三)如何引入(导入)包 (四&am…...
详细推导MOSFET的跨导、小信号模型、输出阻抗、本征增益
目录 前言 什么是跨导 什么是小信号模型 什么是输入阻抗和输出阻抗 什么是MOS管的输出阻抗 什么是MOS管的本征增益 共源极放大电路的输入和输出阻抗 一些其它MOS拓扑电路的增益 负载为恒流源 负载为二极管 前言 相信很多人在学习集成电路领域的时候 都对MOS管的…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...