(十四)C++自制植物大战僵尸游戏windows平台视频播放实现
植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/8UFMs
VLC库
在Cocos2d-x游戏开发框架中,没有实现windows平台视频播放的功能,需要自定义实现。在本项目中使用vlc库实现windows平台的视频播放功能。
vlc官网:网址
下载完成后,找到所下载文件的sdk目录 ,里面有实现视频播放的库文件。将头文件和库文件配置到项目中,然后使用其播放视频。
代码文件位置
代码文件的位置在Class\Based文件夹中。
VideoPlayer.h
在实现的头文件中引入vlc库的头文件。
#include "Based/vlc/vlc.h"
将用到的库文件进行声明。
#pragma comment (lib, "libvlc.lib")
#pragma comment (lib, "libvlccore.lib")
定义VideoPlayer类实现视频播放,继承Sprite。
class VideoPlayer : public Sprite
{
public:~VideoPlayer();static VideoPlayer* instance(void);bool init(void);void play(const char* path);void play();void stop(void);void pause(void);void draw(Renderer* renderer, const Mat4& transform, uint32_t flags);void changeVideoState();void setPrecent(const float precent);float getPrecent();void setVolume(int volume);int getVolume() const;void setVideoTime(const libvlc_time_t time);libvlc_time_t getVideoTime() const;protected:VideoPlayer();private:libvlc_instance_t* vlc;libvlc_media_player_t* vlc_player;libvlc_media_list_player_t* vlc_list_player;libvlc_media_list_t* vlc_list;libvlc_media_t* vlc_media;libvlc_time_t video_length;unsigned int width;unsigned int height;static VideoPlayer* _instance;
};
以下是
VideoPlayer
类的成员函数和成员变量:
成员函数:
- 析构函数
~VideoPlayer()
:用于销毁VideoPlayer
对象。- 静态成员函数
instance()
:返回VideoPlayer
类的单例对象。init()
:初始化视频播放器。play(const char* path)
:播放指定路径的视频。play()
:播放当前视频。stop()
:停止视频播放。pause()
:暂停视频播放。draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
:绘制函数,用于渲染视频画面。changeVideoState()
:改变视频状态。setPrecent(const float precent)
:设置视频播放进度。getPrecent()
:获取当前视频播放进度。setVolume(int volume)
:设置音量大小。getVolume() const
:获取当前音量大小。setVideoTime(const libvlc_time_t time)
:设置视频播放时间。getVideoTime() const
:获取当前视频播放时间。成员变量:
vlc
:libvlc实例。vlc_player
:libvlc媒体播放器。vlc_list_player
:libvlc媒体列表播放器。vlc_list
:libvlc媒体列表。vlc_media
:libvlc媒体。video_length
:视频长度。width
:视频宽度。height
:视频高度。- 静态成员变量
_instance
:VideoPlayer
类的单例对象。
VideoPlayer.cpp
构造函数
VideoPlayer::VideoPlayer() :vlc(0), vlc_player(0), video_length(-1)
{init();
}
在构造函数中,初始化了
VideoPlayer
类的成员变量。具体来说:
vlc
、vlc_player
和video_length
被初始化为0或-1。调用
init()
函数进行初始化。构造函数的主要目的是设置初始状态和准备视频播放器的环境。由于构造函数调用了
init()
函数,在init()
函数中进行了与视频播放器相关的初始化操作。
析构函数
VideoPlayer::~VideoPlayer()
{CCSprite::~CCSprite();free(videobuf);libvlc_media_player_stop(vlc_player);libvlc_media_player_release(vlc_player);libvlc_release(vlc);
}
析构函数用于在对象销毁时执行清理操作。具体来说:
调用基类
CCSprite
的析构函数CCSprite::~CCSprite()
,以释放基类的资源。使用
free()
函数释放videobuf
的内存。调用
libvlc_media_player_stop()
函数停止视频播放。调用
libvlc_media_player_release()
函数释放视频播放器相关的资源。调用
libvlc_release()
函数释放libvlc
实例的资源。这些操作用于确保在销毁
VideoPlayer
对象时,相关的资源得到正确释放,避免内存泄漏和资源泄漏。
instance函数
VideoPlayer* VideoPlayer::instance()
{if (_instance == nullptr)_instance = new VideoPlayer();return _instance;
}
这个函数实现了单例模式,用于获取
VideoPlayer
类的唯一实例。
- 首先,它检查静态成员变量
_instance
是否为空指针。- 如果
_instance
为空指针,则创建一个新的VideoPlayer
对象,并将其赋值给_instance
。- 最后,返回
_instance
指针。这样,每次调用
instance()
函数时,只会返回同一个VideoPlayer
对象的指针,确保只有一个VideoPlayer
实例存在。
init函数
bool VideoPlayer::init(void)
{vlc = libvlc_new(0, nullptr);vlc_player = libvlc_media_player_new(vlc);Size size = Director::getInstance()->getWinSize();width = size.width;height = size.height;videobuf = (char*)malloc((width * height) << 2);memset(videobuf, 0, (width * height) << 2);libvlc_video_set_callbacks(vlc_player, lock, unlock, display, nullptr);libvlc_video_set_format(vlc_player, "RGBA", width, height, width << 2);Texture2D* texture = new Texture2D();texture->initWithData(videobuf, sizeof(videobuf), Texture2D::PixelFormat::RGBA8888, width, height, size);return initWithTexture(texture);
}
该函数用于初始化视频播放器。具体来说:
调用
libvlc_new()
函数创建一个新的libvlc
实例,并将其赋值给成员变量vlc
。使用
libvlc_media_player_new()
函数创建一个新的libvlc_media_player
,并将其赋值给成员变量vlc_player
。获取窗口的大小,并将宽度和高度存储在成员变量
width
和height
中。使用
malloc()
函数分配内存给videobuf
,大小为(width * height) << 2
字节(即每个像素占4字节)。使用
memset()
函数将videobuf
的内存清零。使用
libvlc_video_set_callbacks()
函数设置视频回调函数lock
、unlock
和display
,以及传递nullptr
作为用户数据。使用
libvlc_video_set_format()
函数设置视频格式为RGBA,宽度和高度为width
和height
,行字节数为width << 2
。使用
Texture2D
类创建一个新的纹理对象texture
,并使用initWithData()
函数初始化纹理数据,包括videobuf
的数据、像素格式为RGBA8888、宽度和高度为width
和height
。最后,调用基类
initWithTexture()
函数初始化VideoPlayer
对象的纹理,并返回初始化结果。该函数的作用是设置视频播放器的初始化状态,包括创建
libvlc
实例、创建libvlc_media_player
、设置视频回调函数、设置视频格式,并初始化纹理对象。
play(path)函数
void VideoPlayer::play(const char* path)
{vlc_list = libvlc_media_list_new(vlc);vlc_media = libvlc_media_new_path(vlc, path);libvlc_media_list_add_media(vlc_list, vlc_media);vlc_list_player = libvlc_media_list_player_new(vlc);libvlc_media_list_player_set_media_list(vlc_list_player, vlc_list);libvlc_media_list_player_set_media_player(vlc_list_player, vlc_player);libvlc_media_list_player_set_playback_mode(vlc_list_player, libvlc_playback_mode_loop);libvlc_media_list_player_play(vlc_list_player);
}
该函数用于播放指定路径的视频。具体来说:
使用
libvlc_media_list_new()
函数创建一个新的libvlc_media_list
对象,并将其赋值给成员变量vlc_list
。使用
libvlc_media_new_path()
函数根据提供的路径创建一个新的libvlc_media
对象,并将其赋值给成员变量vlc_media
。使用
libvlc_media_list_add_media()
函数将vlc_media
添加到vlc_list
中。使用
libvlc_media_list_player_new()
函数创建一个新的libvlc_media_list_player
对象,并将其赋值给成员变量vlc_list_player
。使用
libvlc_media_list_player_set_media_list()
函数将vlc_list
设置为vlc_list_player
的媒体列表。使用
libvlc_media_list_player_set_media_player()
函数将vlc_player
设置为vlc_list_player
的媒体播放器。使用
libvlc_media_list_player_set_playback_mode()
函数设置vlc_list_player
的播放模式为循环播放模式。使用
libvlc_media_list_player_play()
函数开始播放vlc_list_player
中的媒体。该函数的作用是设置视频播放器的相关参数,并开始播放指定路径的视频。它使用了
libvlc
库中的函数来实现视频播放的功能。
play()、stop()、pause()函数
void VideoPlayer::play()
{libvlc_media_player_play(vlc_player);
}void VideoPlayer::stop(void)
{libvlc_media_player_stop(vlc_player);
}void VideoPlayer::pause(void)
{libvlc_media_player_pause(vlc_player);
}
这些函数用于控制视频播放的操作。具体来说:
play()
函数调用libvlc_media_player_play()
函数,开始播放当前视频。
stop()
函数调用libvlc_media_player_stop()
函数,停止当前视频的播放。
pause()
函数调用libvlc_media_player_pause()
函数,暂停当前视频的播放。这些函数使用
libvlc
库中的函数来控制视频播放器的播放、停止和暂停操作。
draw函数
void VideoPlayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
{CC_PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");CC_NODE_DRAW_SETUP();GL::blendFunc(_blendFunc.src, _blendFunc.dst);if (_texture != NULL){GL::bindTexture2D(_texture->getName());glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (uint8_t*)videobuf);}else{GL::bindTexture2D(static_cast<GLuint>(0));}//// Attributes//GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);#define kQuadSize sizeof(_quad.bl)long offset = (long)&_quad;// vertexint diff = offsetof(ccV3F_C4B_T2F, vertices);glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));// texCoodsdiff = offsetof(ccV3F_C4B_T2F, texCoords);glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));// colordiff = offsetof(ccV3F_C4B_T2F, colors);glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);CHECK_GL_ERROR_DEBUG();CC_INCREMENT_GL_DRAWS(1);CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw");
}
该函数用于绘制视频帧。具体来说:
使用
CC_PROFILER_START_CATEGORY()
函数开始性能分析。使用
CC_NODE_DRAW_SETUP()
函数设置绘制环境。使用
GL::blendFunc()
函数设置混合函数。如果纹理
_texture
不为空,则绑定纹理并使用glTexImage2D()
函数将视频帧数据写入纹理。如果纹理
_texture
为空,则绑定一个空的纹理。使用
GL::enableVertexAttribs()
函数启用顶点属性。计算顶点属性的偏移量,并使用
glVertexAttribPointer()
函数设置顶点属性的指针。使用
glDrawArrays()
函数绘制四边形。使用
CHECK_GL_ERROR_DEBUG()
函数检查OpenGL错误。使用
CC_INCREMENT_GL_DRAWS()
函数增加绘制计数。使用
CC_PROFILER_STOP_CATEGORY()
函数停止性能分析。该函数的作用是在OpenGL上下文中绘制视频帧。它使用了OpenGL的函数和引擎中的辅助函数来实现绘制操作。
changeVideoState函数
void VideoPlayer::changeVideoState()
{switch (libvlc_media_get_state(vlc_media)){case libvlc_state_t::libvlc_Playing: pause(); break;case libvlc_state_t::libvlc_Paused: play(); break;default: break;}
}
该函数用于切换视频的播放状态。具体来说:
使用
libvlc_media_get_state()
函数获取当前视频的状态。根据视频的状态进行切换操作:
- 如果视频正在播放(
libvlc_Playing
状态),则调用pause()
函数暂停视频。- 如果视频已暂停(
libvlc_Paused
状态),则调用play()
函数继续播放视频。- 对于其他状态,不执行任何操作。
该函数根据当前视频的状态来切换播放状态,从而实现暂停和继续播放的功能。它使用了
libvlc
库中的函数和VideoPlayer
类中的相应函数来控制视频的播放和暂停。
setVideoTime、getVideoTime函数
void VideoPlayer::setVideoTime(const libvlc_time_t time)
{libvlc_media_player_set_time(vlc_player, time);
}libvlc_time_t VideoPlayer::getVideoTime() const
{return libvlc_media_player_get_time(vlc_player);
}
这些函数用于设置和获取视频的播放时间。具体来说:
setVideoTime()
函数调用libvlc_media_player_set_time()
函数,将指定的时间time
设置为视频播放的时间。
getVideoTime()
函数调用libvlc_media_player_get_time()
函数,返回当前视频的播放时间。这些函数使用了
libvlc
库中的函数来设置和获取视频播放器的时间信息。setVideoTime()
函数用于设置视频的播放时间,而getVideoTime()
函数用于获取当前视频的播放时间。
setPrecent、 getPrecent函数
void VideoPlayer::setPrecent(const float precent)
{video_length < 0 ? video_length = libvlc_media_get_duration(vlc_media) : video_length;libvlc_media_player_set_time(vlc_player, static_cast<libvlc_time_t>(video_length * precent));
}float VideoPlayer::getPrecent()
{auto videoCurrentTime = libvlc_media_player_get_time(vlc_player);video_length < 0 ? video_length = libvlc_media_get_duration(vlc_media) : video_length;if (videoCurrentTime != -1 && video_length != -1){return videoCurrentTime * 1.0f / video_length * 100;}return -1;
}
这些函数用于设置和获取视频的播放进度百分比。具体来说:
setPrecent()
函数根据当前视频的总时长(video_length
)和传入的百分比(precent
)计算出对应的时间,然后调用libvlc_media_player_set_time()
函数将视频的播放时间设置为计算得到的时间。
getPrecent()
函数获取当前视频的播放时间(videoCurrentTime
)和总时长(video_length
),然后根据这两个值计算出播放进度的百分比。如果视频的播放时间和总时长都有效,则返回计算得到的进度百分比;否则返回-1。这些函数使用了
libvlc
库中的函数来获取视频的总时长和当前播放时间,并通过计算得到播放进度的百分比。setPrecent()
函数用于设置视频的播放进度,而getPrecent()
函数用于获取当前的播放进度百分比。
setVolume、getVolume 函数
void VideoPlayer::setVolume(int volume)
{if (volume < 0) volume = 0;if (volume > 100)volume = 100;libvlc_audio_set_volume(vlc_player, volume);
}int VideoPlayer::getVolume() const
{return libvlc_audio_get_volume(vlc_player);
}
这些函数用于设置和获取视频的音量。具体来说:
setVolume()
函数用于设置视频的音量。它首先对音量进行范围检查,确保音量值在0到100之间。然后,使用libvlc_audio_set_volume()
函数将音量设置为指定的值。
getVolume()
函数用于获取当前视频的音量。它调用libvlc_audio_get_volume()
函数来获取当前音量值,并将其返回。这些函数使用了
libvlc
库中的函数来设置和获取视频播放器的音量信息。setVolume()
函数用于设置视频的音量,而getVolume()
函数用于获取当前视频的音量。
相关文章:

(十四)C++自制植物大战僵尸游戏windows平台视频播放实现
植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/8UFMs VLC库 在Cocos2d-x游戏开发框架中,没有实现windows平台视频播放的功能,需要自定义实现。在本项目中使用vlc库实现windows平台的视频播放功能。 vlc官网:网址 下载完成后&#x…...

深入理解GCC/G++在CentOS上的应用
文章目录 深入理解GCC/G在CentOS上的应用编译C和C源文件C语言编译C语言编译 编译过程的详解预处理编译汇编链接 链接动态库和静态库静态库和动态库安装静态库 结论 深入理解GCC/G在CentOS上的应用 在前文的基础上,我们已经了解了CentOS的基本特性和如何在其上安装及…...
C语言【复合类型(自定义类型)】
一、结构体 结构体(struct)可以理解为用户自定义的特殊的复合的“数据类型”; 1. 结构体变量的定义和初始化 定义结构体变量的方式: 先声明结构体类型再定义变量名 在声明类型的同时定义变量 // 结构体类型的定义 struct stu {char name[50];int age;…...
【python】初识爬虫
Python爬虫介绍 目录 一、概述二、Python爬虫的基本构成爬虫引擎解析器数据存储三、Python爬虫的主要技术请求与响应URL管理页面解析数据存储四、Python爬虫的应用场景数据采集搜索引擎竞品分析价格监控五、Python爬虫的开发流程六、常用的库...

提高小红书底层逻辑认知+短视频思路打爆笔记+纯带货笔记起号(8节课)
课程内容: 小红书如何0押金开通店铺 .mp4 店铺基础搭建.mp4 小红营的流量从哪里来? 如何用养号发现优质的对标笔记?养号的真正意义是什么?.mp4 什么叫垂类标签? 账号如何打上正确的标签 .mp4 前期笔记是否挂车?不同类型的笔记审核标准是什么?.mp4 如何用…...

力扣:219. 存在重复元素 II
力扣:219. 存在重复元素 II 给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在,返回 true ;否则,返回 false 。 …...
程序安装 - 笔记
1 程序IOServer,依赖自己开发libs7.so.如何安装程序 要安装依赖于自己开发的 libs7.so 的程序 IOServer,你需要执行以下步骤: 编译 IOServer 程序:确保 IOServer 程序的源代码处于可用状态,并且已经编译成可执行文件。这可能需要执行诸如 make 或者其他编译命令,具体取决…...
文心一言 vs. GPT-4: 全面比较
1. 训练数据和预训练 文心一言 训练数据:文心一言是由中国研究人员开发的中文语言模型。它主要在大量古典中文文学作品上进行训练,包括诗歌、散文和历史文本。这些文学作品涵盖了丰富的中文语言和文化,使得文心一言在传统文化方面具有独特优…...

图书管理系统概述
自友图书馆管理系统解决方案适用于中小学、大中专院校以及企事业单位中小型图书馆的自动化管理需求,其功能覆盖了图书馆自动化集成管理业务流程所包括的所有环节。《图书馆管理系统》首先应该按照我国图书馆行业通用CNMARC格式及《中图法第四版》行业标准开发而成,支…...

中国老铁路增开对国际旅客列车开行
4月13日,中老铁路国际旅客列车开行一周年之际,中老两国铁路部门在中国西双版纳至老挝琅勃拉邦两大著名旅游城市间增开1对国际旅客列车,旅客乘火车可实现两地间当日往返。标题:古道新程——中国老铁路增开国际旅客列车 在这个日新月…...

搭建个人智能家居 4 -WS2812B-RGB灯
搭建个人智能家居 4 - WS2812B-RGB灯 前言说明ESPHomeHomeAssistant 前言 上一篇文章我们已经完成了第一个外设的添加(一个LED灯),今天接着来“壮大”这个系统,添加第二个外设“RGB灯”。 环境搭建可以回顾前面的文章。前文回顾&…...

C++类与对象(中)②
目录 1.赋值运算符重载 1.1运算符重载 1.2赋值运算符重载 1.2.1赋值运算符重载格式 1.2.2赋值运算符只能重载成成员函数不能重载成全局函数 1.2.3同拷贝函数一样,如果类是形如日期类这样变量全是内置类型的,赋值运算符就必须自己实现,…...
Qt——xml文件生成DBus接口
1. 如何根据xml文件生成Dbus接口 要使用 XML 文件生成 D-Bus 接口,你可以按照以下步骤操作: 步骤 1: 准备 XML 文件 确保你的 XML 文件遵循 D-Bus 的接口描述规范。这通常包括定义接口、方法、信号和属性。一个基本的例子如下: <!DOCTYPE…...

初识SpringMVC(SpringMVC学习笔记一)
1 、还是熟悉的配方,先创建一个父Maven项目(忘记怎么创建项目了就去前面翻笔记),导入通用的配置依赖 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…...

FreeRTOS任务管理
1. 任务状态理论讲解 定时器职中断周期此处的1000Hz表示的是没次间隔1毫秒就记一次数(在FreeConfig.h)文件中进行配置 #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) 判断是否需要任务切换在FreeRTOS里面每次间隔1毫秒切换一次(程序…...

Qwen1.5大语言模型微调实践
在人工智能领域,大语言模型(Large Language Model,LLM)的兴起和广泛应用,为自然语言处理(NLP)带来了前所未有的变革。Qwen1.5大语言模型作为其中的佼佼者,不仅拥有强大的语言生成和理…...

购物车实现
目录 1.购物车常见的实现方式 2.购物车数据结构介绍 3.实例分析 1.controller层 2.service层 1.购物车常见的实现方式 方式一:存储到数据库 性能存在瓶颈方式二:前端本地存储 localstorage在浏览器中存储 key/value 对,没有过期时间。s…...

HTML5漫画风格个人介绍源码
源码介绍 HTML5漫画风格个人介绍源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面,重定向这个界面 效果截图 源码下载 HTML5漫画风格…...

工业数学模型——高炉煤气发生量预测(三)
1、工业场景 冶金过程中生产的各种煤气,例如高炉煤气、焦炉煤气、转炉煤气等。作为重要的副产品和二次能源,保证它们的梯级利用和减少放散是煤气能源平衡调控的一项紧迫任务,准确的预测煤气的发生量是实现煤气系统在线最优调控的前提。 2、…...

pnpm - Failed to resolve loader: cache-loader. You may need to install it.
起因 工作原因需要研究 vue-grid-layout 的源码,于是下载到本地。因为我习惯使用 pnpm,所以直接用 pnpm i 安装依赖,npm run serve 启动失败。折腾了一番没成功。 看到源码里有 yarn.lock,于是重新用 yarn install 安装依赖&…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...