Ota++框架学习
一:框架结构
这是一幅展现 Web 应用程序架构的示意图,以下是对图中各部分的详细解释:
外部交互部分
Request(请求):位于架构图的左上角,用黄色虚线框表示 。代表来自客户端(如浏览器、移动应用等)的请求,是整个流程的起始点,触发服务器端的处理逻辑。
CROS(跨域资源共享):以红色矩形呈现。当浏览器发起跨域请求时,CROS 机制会处理跨域相关的配置和验证,确保不同源之间的资源请求符合安全策略。它是保障浏览器跨域请求正常进行的关键组件。
Response(响应):在左下角,以紫色虚线框展示。是服务器处理完请求后,返回给客户端的数据或状态信息,携带处理结果。
服务器内部组件
Controller(控制器):绿色矩形,处于 OAT++ SERVER(浅蓝色大框,代表服务器端整体环境 )内。它接收来自 CROS 的请求,负责接收和解析请求参数,调用相应的 Service 层方法,并决定返回给客户端的数据格式和内容。是请求进入服务器后的第一站,起到调度和控制流程的作用。
DTO(数据传输对象):蓝色矩形,与 Controller 有交互。用于在不同层之间传输数据,对数据进行封装和转换,保证数据在传输过程中的一致性和规范性,避免直接传递复杂的业务对象。
Service(服务):粉色矩形。主要处理业务逻辑,接收 Controller 的调用请求,进行具体的业务操作,如数据的增删改查等。它可以调用其他组件(如 Other 代表的其他服务或模块)来完成业务功能。
Other(其他组件):黄色矩形,与 Service 有双向交互。代表系统中其他可能被 Service 调用的组件或服务,比如外部 API、数据库访问层、缓存服务等,用于扩展业务功能。
Application(应用):橙色矩形,位于服务器环境内。可理解为应用程序的整体上下文或容器,承载上述各个组件,提供运行时环境,管理组件的生命周期等。
整个架构图体现了一个典型的分层架构思想,从请求的接收到业务逻辑处理,再到数据的传输和响应返回,各组件分工明确,协同完成 Web 应用程序的功能。
二:
DOT数据传输对象
(1)DTO 基础概念
DTO(Data Transfer Object)是一种设计模式,用于在不同层(如客户端与服务器、服务与服务之间)传输数据。
在 Oat++ 中,DTO 是实现数据序列化和反序列化的核心组件,它提供了以下优势:
数据结构标准化:定义清晰的接口规范
安全的数据交换:避免直接暴露业务对象
性能优化:通过选择性序列化减少传输数据量
类型安全:编译时类型检查
跨语言兼容性:支持多种格式(JSON、XML 等)
(2)DTO 定义与结构
2.1基本 DTO 定义
在 Oat++ 中,DTO 是通过继承 oatpp::DTO
并使用代码生成宏来定义的:
#include "oatpp/core/macro/codegen.hpp"
#include "oatpp/core/Types.hpp"/* 开始 DTO 代码生成 */
#include OATPP_CODEGEN_BEGIN(DTO)/*** 用户数据传输对象*/
class UserDto : public oatpp::DTO {DTO_INIT(UserDto, DTO)DTO_FIELD(Int32, id); // 整数类型字段DTO_FIELD(String, name, "user-name"); // 字符串类型字段,指定 JSON 字段名DTO_FIELD(Boolean, active); // 布尔类型字段DTO_FIELD(DateTime, created); // 日期时间类型字段};/* 结束 DTO 代码生成 */
#include OATPP_CODEGEN_END(DTO)
2.2字段属性详解
基本数据类型。Oat++ 支持多种基本数据类型:
DTO_FIELD(Int8, int8Field); // 8位整数
DTO_FIELD(Int16, int16Field); // 16位整数
DTO_FIELD(Int32, int32Field); // 32位整数
DTO_FIELD(Int64, int64Field); // 64位整数
DTO_FIELD(Float32, float32Field); // 32位浮点数
DTO_FIELD(Float64, float64Field); // 64位浮点数
DTO_FIELD(Boolean, boolField); // 布尔值
DTO_FIELD(String, stringField); // 字符串
DTO_FIELD(DateTime, dateTimeField); // 日期时间
复杂数据类型。支持嵌套 DTO 和集合类型:
// 嵌套 DTO DTO_FIELD(Object<AddressDto>, address);
// 集合类型
DTO_FIELD(List<String>, tags);
DTO_FIELD(Fields<String>, metadata);
DTO_FIELD(Vector<Object<ItemDto>>, items);
字段选项。可以为字段设置默认值、验证规则等:
// 设置默认值
DTO_FIELD(String, language, "lang") = "en";
// 标记为必需字段
DTO_FIELD_REQUIRED(Int32, age);
// 可选字段(默认值为 nullptr)
DTO_FIELD(String, phone);
(3) DTO 高级特性
3.1 自定义序列化 / 反序列化
可以通过 DTO_FIELD_GET
和 DTO_FIELD_SET
宏自定义字段的序列化和反序列化逻辑:
class CustomDto : public oatpp::DTO {DTO_INIT(CustomDto, DTO)DTO_FIELD(String, encryptedField);// 自定义序列化逻辑DTO_FIELD_GET(encryptedField) {// 模拟加密return encrypt(value);}// 自定义反序列化逻辑DTO_FIELD_SET(encryptedField) {// 模拟解密value = decrypt(inValue);}};
3.2 验证与约束
Oat++ 提供了基本的验证功能:
class ValidatedUserDto : public oatpp::DTO {DTO_INIT(ValidatedUserDto, DTO)// 必需字段,最小长度为 3DTO_FIELD_REQUIRED(String, username)->addValidator(Validator::minLength(3));// 邮箱格式验证DTO_FIELD_REQUIRED(String, email)->addValidator(Validator::email());// 年龄范围验证DTO_FIELD_REQUIRED(Int32, age)->addValidator(Validator::min(18))->addValidator(Validator::max(100));};
3.3 继承与多态
DTO 支持继承,可以创建基类 DTO 和派生类 DTO:
/* 基类 DTO */
class AnimalDto : public oatpp::DTO {DTO_INIT(AnimalDto, DTO)DTO_FIELD(String, type);DTO_FIELD(String, name);};/* 派生类 DTO */
class DogDto : public AnimalDto {DTO_INIT(DogDto, AnimalDto)DTO_FIELD(String, breed);};class CatDto : public AnimalDto {DTO_INIT(CatDto, AnimalDto)DTO_FIELD(Boolean, lazy);};
(4)DTO 与 API 集成
4.1 在 API 中使用 DTO
在控制器中,可以直接使用 DTO 作为请求体和响应体:
ENDPOINT("POST", "user", createUser,BODY_DTO(Object<UserDto>, userDto)) {// 处理用户创建逻辑auto createdUser = userService->createUser(userDto);return createDtoResponse(Status::CODE_201, createdUser);
}ENDPOINT("GET", "user/{id}", getUser,PATH(Int32, id)) {// 获取用户逻辑auto user = userService->getUserById(id);return createDtoResponse(Status::CODE_200, user);
}
4.2 集合类型响应
返回列表或集合类型:
ENDPOINT("GET", "users", getUsers) {auto users = userService->getAllUsers();return createDtoResponse(Status::CODE_200, users);
}
4.3 分页响应
class PageDto : public oatpp::DTO {DTO_INIT(PageDto, DTO)DTO_FIELD(Vector<Object<UserDto>>, items);DTO_FIELD(Int32, page);DTO_FIELD(Int32, size);DTO_FIELD(Int32, total);};ENDPOINT("GET", "users", getUsers,QUERY(Int32, page, "page", 0),QUERY(Int32, size, "size", 10)) {auto page = userService->getUsersPage(page, size);return createDtoResponse(Status::CODE_200, page);
}
(5)DTO 与数据库集成
5.1 DTO 与数据库实体映射
通常需要在 DTO 和数据库实体之间进行映射:
// 数据库实体
class User {
public:int id;std::string name;std::string email;bool active;
};// DTO 到实体的映射
User userDtoToEntity(const std::shared_ptr<UserDto>& dto) {User user;user.id = dto->id;user.name = dto->name->c_str();user.email = dto->email->c_str();user.active = dto->active;return user;
}// 实体到 DTO 的映射
std::shared_ptr<UserDto> userEntityToDto(const User& user) {auto dto = UserDto::createShared();dto->id = user.id;dto->name = user.name;dto->email = user.email;dto->active = user.active;return dto;
}
5.2 使用 ORM 简化映射
// 定义数据库模式
#include OATPP_CODEGEN_BEGIN(DbClient)class UserDbClient : public oatpp::orm::DbClient {
public:QUERY(createUser,"INSERT INTO User (name, email, active) VALUES (:user.name, :user.email, :user.active);",PARAM(oatpp::Object<UserDto>, user))QUERY(getUserById,"SELECT * FROM User WHERE id=:id;",PARAM(Int32, id))};#include OATPP_CODEGEN_END(DbClient)
(6)DTO 最佳实践
6.1 命名规范
使用清晰的命名,避免缩写(如 userId
而非 uid
)
保持与数据库字段或前端约定一致
使用 PascalCase 命名 DTO 类(如 UserProfileDto
)
6.2 字段设计原则
仅包含需要传输的数据
避免敏感信息(如密码哈希)
使用有意义的字段名,避免技术术语
考虑未来扩展性,预留字段
6.3 性能优化
避免过度嵌套,保持扁平化结构
使用集合类型代替重复嵌套
对于大数据量,考虑分页或流式传输
使用字段组选择性序列化(如仅返回必要字段)
(7)常见问题与解决方案
7.1 序列化 / 反序列化错误
-
问题:JSON 字段名与 DTO 字段名不匹配
-
解决方案:使用
DTO_FIELD
的第三个参数指定 JSON 字段名 -
问题:类型不匹配
-
解决方案:确保 DTO 字段类型与 JSON 数据类型一致
7.2 嵌套 DTO 处理
问题:复杂嵌套结构导致性能问题
解决方案:考虑扁平化设计或使用单独的 API 获取嵌套数据
问题:循环引用
解决方案:使用 ID 引用代替直接嵌套,或在序列化时忽略循环引用字段
7.3 验证失败
问题:验证规则不满足
解决方案:检查验证规则,确保数据符合要求
进阶方案:自定义验证器处理复杂业务规则
ENDPOINT
ENDPOINT 是 OAT++ 框架中用于定义 HTTP API 端点(路由) 的核心机制。它通过声明式语法将 HTTP 请求映射到具体的处理函数,并自动完成参数绑定、数据序列化/反序列化、错误处理等流程。以下是对其作用的详细讲解:
(1)ENDPOINT 的核心作用
1、定义路由规则
将特定的 HTTP 方法(如 GET、POST)和 URL 路径(如 /users/{id}
)绑定到一个处理函数。
示例:ENDPOINT("GET", "/users", getUsers)
表示当客户端发送 GET 请求到 /users
时,调用 getUsers
函数处理。
2、参数自动绑定
自动从 HTTP 请求中提取参数(路径参数、查询参数、请求体等),并转换为 C++ 类型或 DTO 对象。
示例:PATH(Int64, id)
自动将 URL 路径中的 {id}
转换为 int64_t
类型。
3、标准化响应生成
通过 createResponse
生成符合 HTTP 规范的响应(状态码、头部、数据体),并自动将 C++ 对象序列化为 JSON 等格式。
4、依赖注入与中间件支持
支持注入全局组件(如数据库连接池、日志服务),并可集成中间件(如身份验证、CORS 处理)。
(2)ENDPOINT 的语法结构
在 OAT++ 中,ENDPOINT
是一个宏(Macro),其基本语法如下:
ENDPOINT(
HTTP方法, // 如 "GET", "POST", "PUT", "DELETE"
URL路径, // 如 "/users", "/users/{id}"
处理函数名, // 自定义的函数名,如 getUserById
参数绑定列表... // 如 PATH(...), QUERY(...), BODY_DTO(...)
) {
// 业务逻辑代码
return createResponse(...); // 生成HTTP响应
}
(3)执行流程
-
请求接收:OAT++ Server 监听并解析 HTTP 请求。
-
路由匹配:根据 URL 和方法匹配到对应的
ENDPOINT
处理函数。 -
参数绑定:自动提取路径、查询等参数,并进行类型转换与校验。
-
业务执行:控制器调用服务层处理逻辑,可能涉及数据库或外部服务。
-
响应生成:将结果序列化为标准格式(如 JSON),附加头部并返回客户端。
(4)ENDPOINT的关键特性
(一)支持的 HTTP 方法
所有标准方法:GET
, POST
, PUT
, DELETE
, PATCH
, HEAD
, OPTIONS
。
示例:ENDPOINT("POST", "/users", createUser, BODY_DTO(...))
。
(二)参数绑定类型
参数类型 | 宏 | 示例 |
路径参数 | PATH(Type, Name) | PATH(Int64, id) |
查询参数 | QUERY(Type, Name) | QUERY(String, name) |
请求体(DTO) | BODY_DTO(...) | BODY_DTO(UserDto, user) |
HTTP 头部 | HEADER(Type, Name) | HEADER(String, authToken) |
表单字段 | FORM_FIELD(...) | FORM_FIELD(File, avatar) |
(三) 自动错误处理
类型不匹配:若客户端传递的参数无法转换为声明类型(如将字符串传给 Int64
),OAT++ 自动返回 400 Bad Request
。
参数缺失:若未提供必需参数(如未指定 PATH
参数),返回 404 Not Found
或 400 Bad Request
。
(四)依赖注入
通过 OATPP_COMPONENT
注入全局依赖(如数据库连接、配置对象):
ENDPOINT("GET", "/users", getAllUsers,
// 注入数据库组件
OATPP_COMPONENT(std::shared_ptr<Database>, db)) {
auto users = db->queryAllUsers();
return createResponse(Status::CODE_200, users);
}
(5)最佳实践与注意事项
(一)保持Controller轻量
在 ENDPOINT
中仅处理参数绑定和响应生成,业务逻辑应交给 Service 层。
(二)合理使用DTO
对于复杂请求体,优先通过 DTO 定义数据结构,确保类型安全和可维护性。
(三)统一错误响应
使用 createResponse
返回标准化的错误格式:
return createResponse(Status::CODE_404, "User not found");
(四)路由分组与模块化
按功能将端点分组到不同的 Controller 类中(如 UserController
、OrderController
)
(五)性能优化
避免在 ENDPOINT
中进行阻塞操作(如复杂计算),使用异步任务或线程池处理耗时逻辑。
API Controller
Oat++ API 控制器详解:构建强大的 RESTful 服务
(1)API 控制器基础概念
1.1什么是API 控制器?
在 Oat++ 中,API 控制器 是处理 HTTP 请求的核心组件,它负责:
1、定义 API 端点的路径、方法和参数
2、接收客户端请求并解析数据
3、调用相应的业务逻辑
4、返回格式化的响应给客户端
控制器通过继承 oatpp::web::server::api::ApiController
并使用代码生成宏来定义,使代码简洁且类型安全。
1.2 控制器与 MVC 模式
在 MVC(模型 - 视图 - 控制器)架构中,Oat++ 的控制器对应 MVC 中的 "C" 角色:
模型(Model):DTO 和业务逻辑
视图(View):通常由客户端处理,Oat++ 专注于数据返回
控制器(Controller):处理请求和响应
这种分离使代码结构清晰,易于维护和测试。
(2)控制器的基本结构
2.1 定义控制器类
#include "oatpp/web/server/api/ApiController.hpp"
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
#include "oatpp/core/macro/codegen.hpp"/* 开始控制器代码生成 */
#include OATPP_CODEGEN_BEGIN(ApiController)/*** 示例 API 控制器*/
class ExampleController : public oatpp::web::server::api::ApiController {
public:/*** 构造函数,需要传入 ObjectMapper 用于序列化/反序列化*/ExampleController(const std::shared_ptr<ObjectMapper>& objectMapper): oatpp::web::server::api::ApiController(objectMapper){}/* 端点定义将在这里 */};/* 结束控制器代码生成 */
#include OATPP_CODEGEN_END(ApiController)
2.2 注册控制器到路由器
// 创建路由器
auto router = HttpRouter::createShared();// 创建 ObjectMapper
auto objectMapper = oatpp::parser::json::mapping::ObjectMapper::createShared();// 创建并注册控制器
auto controller = ExampleController::createShared(objectMapper);
controller->addEndpointsToRouter(router);
(3)端点(Endpoint)定义
上一节已介绍并讲解了Endpoint,此处不再赘述。
(4)请求处理与响应
4.1 请求对象
可以直接访问完整的请求对象:
ENDPOINT("GET", "request-info", getRequestInfo,REQUEST(std::shared_ptr<IncomingRequest>, request)) {auto path = request->getPath();auto headers = request->getHeaders();auto method = request->getMethod();// 构建响应auto responseDto = RequestInfoDto::createShared();responseDto->path = path;responseDto->method = method;responseDto->headers = headers;return createDtoResponse(Status::CODE_200, responseDto);
}
4.2 响应类型
4.2.1 简单文本响应
return createResponse(Status::CODE_200, "Plain text response");
4.2.2 DTO 响应
return createDtoResponse(Status::CODE_200, userDto);
4.2.3 自定义响应头
auto response = createResponse(Status::CODE_200, "Custom header response"); response->putHeader("X-Custom-Header", "Custom Value");
return response;
4.2.4 文件响应
auto response = createResponse(Status::CODE_200, "File content");
response->putHeader(Header::CONTENT_TYPE, "application/octet-stream");
response->putHeader(Header::CONTENT_DISPOSITION, "attachment; filename=example.txt");
return response;
4.2.5 错误响应
return createResponse(Status::CODE_404, "Resource not found");
(5)中间件与拦截器
5.1 请求拦截器
可以为控制器或特定端点添加拦截器:
class AuthInterceptor : public oatpp::web::server::handler::RequestInterceptor {
public:std::shared_ptr<OutgoingResponse> intercept(const std::shared_ptr<IncomingRequest>& request) override {auto authHeader = request->getHeader("Authorization");if(!authHeader || !authService->validateToken(authHeader)) {return ResponseFactory::createResponse(Status::CODE_401, "Unauthorized");}// 将用户信息添加到请求上下文中request->putBundleData("userId", authService->getUserIdFromToken(authHeader));return nullptr; // 继续处理请求}};
5.2 注册拦截器
// 为控制器添加全局拦截器
ENDPOINT("GET", "protected", getProtected,INTERCEPTOR(AuthInterceptor, authInterceptor)) {// 只有通过认证的请求才能到达这里auto userId = request->getBundleData("userId");return createResponse(Status::CODE_200, "Access granted");
}// 为控制器所有端点添加全局拦截器
void ExampleController::addEndpointsToRouter(const std::shared_ptr<HttpRouter>& router) {auto authInterceptor = std::make_shared<AuthInterceptor>();// 为所有端点添加拦截器router->addGlobalRequestInterceptor(authInterceptor);// 添加端点ApiController::addEndpointsToRouter(router);
}
(6)错误处理
6.1 自定义错误处理器
class CustomErrorHandler : public oatpp::web::server::handler::ErrorHandler {
public:std::shared_ptr<OutgoingResponse> handleError(const Status& status,const oatpp::String& message,const Headers& headers) override {auto errorDto = ErrorDto::createShared();errorDto->statusCode = status.code;errorDto->message = message;auto response = createDtoResponse(status, errorDto);// 添加额外的响应头for(auto& pair : headers.getAll()) {response->putHeader(pair.first.toString(), pair.second.toString());}return response;}};
6.2 注册错误处理器
// 创建并设置错误处理器
auto errorHandler = std::make_shared<CustomErrorHandler>();
serverConnectionHandler->setErrorHandler(errorHandler);
6.3 在控制器中抛出错误
ENDPOINT("GET", "user/{id}", getUser,PATH(Int32, id)) {auto user = userService->getUserById(id);if(!user) {throw oatpp::web::protocol::http::HttpError(Status::CODE_404,"User not found");}return createDtoResponse(Status::CODE_200, user);
}
(7)控制器组织与最佳实践
7.1 按业务功能拆分控制器
// 项目结构示例
src/
├── controller/
│ ├── UserController.hpp // 用户相关 API
│ ├── ProductController.hpp // 产品相关 API
│ └── OrderController.hpp // 订单相关 API
7.2 使用服务层分离业务逻辑
class UserController : public ApiController {
private:std::shared_ptr<UserService> m_userService;
public:UserController(const std::shared_ptr<ObjectMapper>& objectMapper,const std::shared_ptr<UserService>& userService): ApiController(objectMapper), m_userService(userService){}ENDPOINT("GET", "user/{id}", getUser,PATH(Int32, id)) {return createDtoResponse(Status::CODE_200, m_userService->getUserById(id));}};
7.3 版本控制
// V1 控制器
class UserControllerV1 : public ApiController {// 旧版本 API
};// V2 控制器
class UserControllerV2 : public ApiController {// 新版本 API
};// 注册时区分路径
v1Router->addController(std::make_shared<UserControllerV1>(objectMapper));
v2Router->addController(std::make_shared<UserControllerV2>(objectMapper));
7.4 代码复用与基类
class BaseController : public ApiController {
protected:std::shared_ptr<AuthService> m_authService;bool isAuthenticated(const std::shared_ptr<IncomingRequest>& request) {// 认证逻辑}std::shared_ptr<UserDto> getCurrentUser(const std::shared_ptr<IncomingRequest>& request) {// 获取当前用户}
};class UserController : public BaseController {// 继承认证和用户获取功能
};
相关文章:

Ota++框架学习
一:框架结构 这是一幅展现 Web 应用程序架构的示意图,以下是对图中各部分的详细解释: 外部交互部分 Request(请求):位于架构图的左上角,用黄色虚线框表示 。代表来自客户端(如浏览器…...

Chrome安装最新vue-devtool插件
本vue-devtool版本是官方的 v7.6.8版本,兼容性好、功能齐全且稳定。 操作步骤: 方法一: 打开谷歌浏览器 --> 右上角三个点 --> 扩展程序 --> 管理扩展程序 --> 加载已解压的扩展程序, 然后选择解压后的文件夹即可。…...
Android锁
引言 🔒 在 Android 应用的开发过程中,随着业务需求的复杂度不断提升,多线程并发场景层出不穷。为了保证数据一致性与线程安全,锁(Lock)成为了不可或缺的工具。本篇博客将深入剖析 Android 中常用的锁机制…...

bfs-最小步数问题
最小步长模型 特征: 主要是解决权值为1且状态为字符串类型的最短路问题,实质上是有向图的最短路问题,可以简化为bfs求最短路问题。 代表题目: acwing 845 八数码问题: 八数码题中由于每次交换的状态是由x进行上下左右…...
sqlalchemy库详细使用
SQLAlchemy 是 Python 中最强大、最受欢迎的 ORM(对象关系映射)库,它允许你使用 Python 对象来操作数据库,而不需要直接编写 SQL 语句。同时,它也提供了对底层 SQL 的完全控制能力,适用于从简单脚本到大型企…...

java----------->代理模式
目录 什么是代理模式? 为什么会有代理模式? 怎么写代理模式? 实现代理模式总共需要三步: 什么是代理模式? 代理模式:给目标对象提供一个代理对象,并且由代理对象控制目标对象的引用 代理就是…...
ET ProcessInnerSender类(实体) 分析
ProcessInnerSender 作用是进程内部发送Actor消息 字段 TIMEOUT_TIME 超时时间RpcId 用来累加requestCallback 存储RPC的回调事件list 用来获取MessageQueue中的Actor消息 方法 Awake 初始化在MessageQueue中注册待处理的消息队列Destroy 移除在MessageQueue中的消息队列U…...

Untiy基础学习(十四)核心系统—物理系统之碰撞检测代码篇 刚体,碰撞体,材质
目录 一、碰撞器(Collider)与触发器(Trigger) 二、碰撞检测条件 三、碰撞事件与触发器事件,可以理解为特殊的生命周期函数。 四、讲讲如何选择 编辑 五、总结 一、碰撞/触发事件函数对照表 二、Collider 与 …...

SAP学习笔记 - 开发08 - Eclipse连接到 BTP Cockpit实例
有关BTP,之前学了一点儿,今天继续学习。 SAP学习笔记 - 开发02 - BTP实操流程(账号注册,BTP控制台,BTP集成开发环境搭建)_sap btp开发-CSDN博客 如何在Eclipse中连接BTP Cockpit开发环境实例。 1…...
如何用Redis实现分布式锁?RedLock算法的核心思想?Redisson的看门狗机制原理?
一、Redis分布式锁基础实现 public class RedisDistributedLock {private JedisPool jedisPool;private String lockKey;private String clientId;private int expireTime 30; // 默认30秒public boolean tryLock() {try (Jedis jedis jedisPool.getResource()) {// NX表示不…...
Java项目层级介绍 java 层级 层次
java 层级 层次 实体层 控制器层 数据连接层 Service : 业务处理类 Repository :数据库访问类 Java项目层级介绍 https://blog.csdn.net/m0_67574906/article/details/145811846 在Java项目中,层级结构(Layered Architecture…...

Git的安装和配置(idea中配置Git)
一、Git的下载和安装 前提条件:IntelliJ IDEA 版本是2023.3 ,那么配置 Git 时推荐使用 Git 2.40.x 或更高版本 下载地址:CNPM Binaries Mirror 操作:打开链接 → 滚动到页面底部 → 选择2.40.x或更高版本的 .exe 文件…...

【2025版】Spring Boot面试题
文章目录 1. Spring, Spring MVC, SpringBoot是什么关系?2. 谈一谈对Spring IoC的理解3. Component 和 Bean 的区别?4. Autowired 和 Resource 的区别?5. 注入Bean的方法有哪些?6. 为什么Spring 官方推荐构造函数注入?…...

火山引擎实时音视频 高代码跑通日志
实时音视频 SDK 概览--实时音视频-火山引擎 什么是实时音视频 火山引擎实时音视频(Volcengine Real Time Communication,veRTC)提供全球范围内高可靠、高并发、低延时的实时音视频通信能力,实现多种类型的实时交流和互动。 通…...
atoi函数,sprintf函数,memcmp函数,strchar函数的具体原型,功能,返回值;以及使用方法
以下是这四个C语言标准库函数的详细说明: 1. atoi() - 字符串转整数 **原型**: int atoi(const char *str); **功能**: 将字符串参数str转换为整数(int类型)。函数会跳过前面的空白字符(如空格、制表符&am…...
C++学习之打车软件git版本控制
目录 01 3-git的简介 02 4-git的下载和提交代码 03 5-git添加一个新文件 04 5-删除一个文件 05 6-git的批量添加和提交文件 06 7-git重命名文件名 07 8-git解决代码冲突 08 9-git的分支的概念 09 10-创建项目代码仓库 10 1-git提交代码复习 01 3-git的简介 1 --------…...
基于 PostgreSQL 的 ABP vNext + ShardingCore 分库分表实战
🚀 基于 PostgreSQL 的 ABP vNext ShardingCore 分库分表实战 📑 目录 🚀 基于 PostgreSQL 的 ABP vNext ShardingCore 分库分表实战✨ 背景介绍🧱 技术选型🛠️ 环境准备✅ Docker Compose(多库 & 读…...

jenkins 启动报错
java.lang.UnsatisfiedLinkError: /opt/application/jdk-17.0.11/lib/libfontmanager.so: libfreetype.so.6: cannot open shared object file: No such file or directory。 解决方案: yum install freetype-devel 安装完成之后重启jenkins。...
C++ 套接字函数详细介绍
目录 头文件1. 套接字创建与配置2. 绑定地址与端口3. 连接建立4. 数据传输5. 套接字选项6. 地址转换7. 套接字关闭8. 其他实用函数 C 套接字函数详细介绍 套接字(Socket)是网络通信的基本端点,C中通常使用BSD套接字API进行网络编程。以下是主要的套接字相关函数及其…...

【合新通信】无人机天线拉远RFOF(射频光纤传输)解决方案
无人机天线拉远RFOF方案通过光纤替代传统射频电缆,实现无人机与地面控制站之间的高保真、低损耗信号传输,尤其适用于高频段(如毫米波)、远距离或复杂电磁环境下的无人机作业场景。 核心应用场景 军事侦察与电子战 隐蔽部署&…...

程序设计语言----软考中级软件设计师(自用学习笔记)
目录 1、解释器和编译器 2、程序的三种控制结构 3、程序中的数据必须具有类型 4、编译、解释程序翻译阶段 5、符号表 6、编译过程 7、上下文无关文法 8、前、中、后缀表达式 9、前、后缀表达式计算 10、语法树中、后序遍历 11、脚本语言和动态语言 12、语法分析方法…...
火山RTC 7 获得远端裸数据
一、获得远端裸数据 1、获得h264数据 1)、远端编码后视频数据监测器 /*** locale zh* type callback* region 视频管理* brief 远端编码后视频数据监测器<br>* 注意:回调函数是在 SDK 内部线程(非 UI 线程)同步抛出来的&a…...

通过SMTP协议实现Linux邮件发送配置指南
一、环境准备与基础配置 1. SMTP服务开通(以qq邮箱为例) 登录qq邮箱网页端,进入「设置」-「POP3/SMTP/IMAP」 开启「SMTP服务」并获取16位授权码(替代邮箱密码使用) 记录关键参数: SMTP服务器地址&#…...

若依框架页面
1.页面地址 若依管理系统 2.账号和密码 管理员 账号admin 密码admin123 运维 账号yuwei 密码123456 自己搭建的地址方便大家学习,不要攻击哦,谢谢啊...

44、私有程序集与共享程序集有什么区别?
私有程序集(Private Assembly)与共享程序集(Shared Assembly)是.NET框架中程序集部署的两种不同方式,它们在部署位置、版本控制、访问权限等方面存在显著差异,以下是对二者的详细比较: 1. 部署…...

【Java面试题】——this 和 super 的区别
🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:【Java】内容概括 【前言】 在Java的世界里,this和 super是两个非常重要且容易混淆的关键字。无论是在日常…...
记录 QT 在liunx 下 QFileDialog 类调用问题 ()Linux下QFileDialog没反应)
1. 2025.05.14 踩坑记录 因为QT 在 liunx 文件系统不同导致的 Windows : QString filePath QFileDialog::getOpenFileName(nullptr, "选择文件", ".", "文本文件 (*.txt);所有文件 (*.*)"); 没问题 liunx 下 打不开ÿ…...

CentOS 7 内核升级指南:解决兼容性问题并提升性能
点击上方“程序猿技术大咖”,关注并选择“设为星标” 回复“加群”获取入群讨论资格! CentOS 7 默认搭载的 3.10.x 版本内核虽然稳定,但随着硬件和软件技术的快速发展,可能面临以下问题: 硬件兼容性不足:新…...
【前端】:单 HTML 去除 Word 批注
在现代办公中,.docx 文件常用于文档编辑,但其中的批注(注释)有时需要在分享或归档前被去除。本文将从原理出发,深入剖析如何在纯前端环境下实现对 .docx 文件注释的移除,并提供完整的实现源码。最后&#x…...

解决 PicGo 上传 GitHub图床及Marp中Github图片编译常见难题指南
[目录] 0.行文概述 1.PicGo图片上传失败 2.*关于在Vscode中Marp图片的编译问题* 3.总结与启示行文概述 写作本文的动机是本人看到了Awesome Marp,发现使用 Markdown \texttt{Markdown} Markdown做PPT若加持一些 CSS , JavaScript \texttt{CSS},\texttt{JavaScript} …...