ODB 2.5 从安装到实战:C++ ORM 工具手把手教程

ODB 2.5 从安装到实战:C++ ORM 工具手把手教程

作为一名 C++ 开发者,你是否还在为手写 SQL、处理数据库连接、维护表结构与代码实体的映射关系而头疼?ODB(Object-Relational Mapping)作为 Code Synthesis 推出的 C++ ORM 工具,能帮我们把 C++ 类直接映射到数据库表,彻底摆脱重复的数据库操作代码。这篇文章会从 ODB 2.5 的安装踩坑,到实战代码解析,带你完整掌握这个工具 —— 文末还附了可直接复用的 DAO 层封装,新手也能快速上手。

一、先搞懂:ODB 到底能帮我们做什么?

简单说,ODB 是 “C++ 类” 和 “数据库表” 之间的桥梁:

  • 不用手写 CREATE TABLE,ODB 能根据 C++ 类自动生成数据库 schema;
  • 不用写 INSERT/UPDATE/SELECT,调用 ODB 的persist()/update()/query()就能操作数据;
  • 自动处理 C++ 类型与 MySQL 类型的映射(比如std::string对应VARCHARboost::posix_time对应TIMESTAMP);
  • 支持事务、连接池,解决多线程下的数据库操作安全问题。

本文用到的示例代码来自 “比特就业课” 的 C++ 聊天系统项目,完整代码可在 Gitee 获取:cpp-chatsystem

二、ODB 2.5 安装:避坑指南(Linux 环境)

ODB 安装依赖build2编译工具,整个过程大概 3-5 小时(主要耗在网络下载),重点注意版本兼容性和网络超时问题

2.1 第一步:安装 build2(编译基础)

build2 是 ODB 的依赖工具,用来构建后续的 ODB 编译器和运行时库。注意:build2 版本会更新(比如从 0.17 升到 0.18),安装前先去build2 官网确认最新步骤,这里以 0.17.0 为例:

  1. 下载并执行安装脚本(在 PowerShell 或终端执行):
# 进入工作目录(比如~/workspace) cd ~/workspace # 下载安装脚本 curl -sSfO https://download.build2.org/0.17.0/build2-install-0.17.0.sh # 执行脚本(默认安装到/usr/local/bin) sh build2-install-0.17.0.sh 
  1. 踩坑点 1:网络超时如果执行脚本时卡在 “下载文件” 步骤,提示 “timeout”,给脚本加--timeout 1800(超时时间设为 30 分钟):
sh build2-install-0.17.0.sh --timeout 1800 

2.2 第二步:安装 ODB 编译器(odb-compiler)

ODB 编译器的作用是:把带#pragma db指令的 C++ 类(比如Person),生成数据库操作的支持代码(比如person-odb.cxx)。

  1. 先装 gcc 插件开发包(注意替换成你系统的 gcc 版本):
# 查看gcc版本:gcc --version,比如我的是gcc-11 sudo apt-get install gcc-11-plugin-dev 
  1. 创建构建目录并初始化编译配置:
# 创建odb-build目录,避免污染源码 mkdir odb-build && cd odb-build # 初始化cc编译环境,指定g++为编译器,优化等级O3,安装路径/usr bpkg create -d odb-gcc-N cc \ config.cxx=g++ \ config.cc.coptions=-O3 \ config.bin.rpath=/usr/lib \ config.install.root=/usr/
  1. 编译并安装 ODB 编译器:
# 进入配置好的环境目录 cd odb-gcc-N # 从官方源编译odb(beta版,稳定可用) bpkg build config.install.sudo=sudo odb@https://pkg.cppget.org/1/beta # 测试编译结果(可选,确保没问题) bpkg test odb # 安装odb bpkg install odb
  1. 踩坑点 2:执行 odb --version 提示 “找不到命令”这是因为 ODB 安装到了/usr/local/bin,但系统 PATH 没包含这个路径。执行以下命令添加(永久生效):
# 把路径写入bashrc sudo echo 'export PATH=${PATH}:/usr/local/bin' >> ~/.bashrc # 立即生效 export PATH=${PATH}:/usr/local/bin # 验证:成功显示版本号则没问题 odb --version # 正确输出示例: # ODB object-relational mapping (ORM) compiler for C++ 2.5.0-b.25 # Copyright (c) 2009-2023 Code Synthesis Tools CC.

2.3 第三步:安装 ODB 运行时库

ODB 运行时库是代码里实际调用的 API(比如odb::databaseodb::transaction),需要安装核心库、MySQL 驱动和 boost 支持库。

  1. 创建运行时库的构建目录并初始化:
# 回到odb-build目录 cd .. # 初始化cc环境,指定安装路径和sudo权限 bpkg create -d libodb-gcc-N cc \ config.cxx=g++ \ config.cc.coptions=-O3 \ config.install.root=/usr/ \ config.install.sudo=sudo
  1. 添加 ODB 官方源并安装依赖库:
# 进入libodb-gcc-N目录 cd libodb-gcc-N # 添加ODB的beta源 bpkg add https://pkg.cppget.org/1/beta # 拉取最新包信息 bpkg fetch # 安装核心库(libodb) bpkg build libodb # 安装MySQL驱动(libodb-mysql) bpkg build libodb-mysql # 安装boost支持库(处理boost日期等类型) bpkg build libodb-boost
  1. 统一安装所有库:
bpkg install --all --recursive 

2.4 第四步:配置 MySQL(必做)

ODB 需要 MySQL 环境,包括服务端、客户端开发包,以及字符集配置。

  1. 安装 MySQL 和开发包:
# 安装MySQL服务端 sudo apt install mysql-server # 安装客户端开发包(编译时需要头文件和库) sudo apt install -y libmysqlclient-dev
  1. 配置 MySQL 字符集(避免中文乱码):
# 编辑my.cnf(有哪个路径用哪个) sudo vim /etc/my.cnf 或者 sudo vim /etc/mysql/my.cnf # 在文件末尾添加以下内容: [client] default-character-set=utf8 [mysql] default-character-set=utf8 [mysqld] character-set-server=utf8 bind-address = 0.0.0.0 # 允许远程连接(可选)
  1. 修改 MySQL root 密码(默认 root 密码可能为空或未知):
# 先查看debian-sys-maint用户的密码(MySQL默认维护用户) sudo cat /etc/mysql/debian.cnf # 输出里会有:password = UWcn9vY0NkrbJMRC(复制这个密码) # 用debian-sys-maint登录MySQL sudo mysql -u debian-sys-maint -p # 输入刚才复制的密码,进入MySQL命令行 # 修改root密码(把xxxxxx换成你的密码,比如123456) ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'xxxxxx'; # 刷新权限 FLUSH PRIVILEGES; # 退出 quit
  1. 重启 MySQL 并设置开机启动:
sudo systemctl restart mysql sudo systemctl enable mysql 

三、ODB 实战:从代码到运行

接下来我们用一个Person类的例子,完整走一遍 “定义实体→生成代码→编写业务逻辑→编译运行” 的流程。

3.1 第一步:定义持久化类(Person.hxx)

持久化类就是 “能映射到数据库表的 C++ 类”,核心是通过#pragma db指令告诉 ODB 如何映射。

#pragma once #include <string> #include <cstddef> // 用于std::size_t #include <boost/date_time/posix_time/posix_time.hpp> #include <odb/core.hxx> // ODB核心头文件 // 简化boost时间类型的别名 typedef boost::posix_time::ptime ptime; // 关键指令:声明Person是持久化类(对应数据库一张表) #pragma db object class Person { public: // 自定义构造函数(用于创建对象) Person(const std::string &name, int age, const ptime &update) : _name(name), _age(age), _update(update) {} // getter/setter(封装私有成员) void age(int val) { _age = val; } int age() { return _age; } void name(const std::string& val) { _name = val; } std::string name() { return _name; } void update(const ptime &update) { _update = update; } std::string update() { return boost::posix_time::to_simple_string(_update); } private: // 关键:让odb::access成为友元,ODB需要访问私有成员和默认构造函数 friend class odb::access; // ODB要求的默认构造函数(必须私有,避免外部调用) Person () {} // 关键指令:声明_id是主键,auto表示数据库自动生成(自增) #pragma db id auto unsigned long _id; // 普通成员:会自动映射到表的列(列名默认和成员名一致) unsigned short _age; std::string _name; // 关键指令:指定数据库类型为TIMESTAMP,且不允许为空 #pragma db type("TIMESTAMP") not_null boost::posix_time::ptime _update; }; 

核心解析

  • #pragma db object:告诉 ODB “这个类要映射到数据库表”,表名默认是person(小写);
  • friend class odb::access:ODB 生成代码时需要访问私有成员(比如_id_update),必须加这个;
  • #pragma db id auto:标记主键,auto让 MySQL 自动生成自增 ID;
  • #pragma db type("TIMESTAMP") not_null:强制指定数据库列类型为TIMESTAMP,且非空(默认 C++ 成员是 NOT NULL)。

3.2 第二步:生成 ODB 支持代码

ODB 编译器会分析Person.hxx里的#pragma db指令,生成 3 个关键文件:

  • person-odb.hxx:支持代码的头文件;
  • person-odb.cxx:支持代码的实现;
  • person.sql:自动生成的建表 SQL(CREATE TABLE 语句)。

执行以下命令生成:

# 进入代码目录(比如~/workspace/odb-test) cd ~/workspace/odb-test # 生成支持代码 odb -d mysql --std c++11 --generate-query --generate-schema --profile boost/date-time person.hxx

命令参数解析

  • -d mysql:指定数据库类型为 MySQL;
  • --std c++11:使用 C++11 标准;
  • --generate-query:生成查询相关的代码(支持odb::query);
  • --generate-schema:生成建表 SQL(person.sql);
  • --profile boost/date-time:支持 boost 的日期时间类型(否则 ODB 不认识ptime)。

执行后用ls查看,会看到 4 个文件:person.hxxperson-odb.hxxperson-odb.cxxperson.sql

3.3 第三步:编写业务代码(test.cc)

这一步我们写实际的数据库操作:创建连接、插入数据、查询数据,核心是用 ODB 的databasetransactionquery类。

#include <string> #include <memory> // 用于std::shared_ptr #include <iostream> #include <odb/database.hxx> // ODB核心数据库类 #include <odb/mysql/database.hxx> // MySQL数据库实现 #include <boost/date_time/posix_time/posix_time.hpp> // boost时间 #include "person.hxx" #include "person-odb.hxx" // ODB生成的支持代码 int main() { // 1. 创建MySQL数据库连接(参数:用户名、密码、数据库名、主机、端口、字符集) std::shared_ptr<odb::core::database> db( new odb::mysql::database( "root", // MySQL用户名(刚才改的root) "123456", // MySQL密码(替换成你的) "mytest", // 数据库名(需要先手动创建:mysql> CREATE DATABASE mytest;) "127.0.0.1", // 主机地址 0, // 端口(0表示默认3306) 0, // 未使用参数 "utf8" // 字符集 ) ); if (!db) { std::cerr << "数据库连接失败!" << std::endl; return -1; } // 2. 准备数据:获取当前时间 ptime current_time = boost::posix_time::second_clock::local_time(); Person zhang("小张", 18, current_time); // 创建Person对象 Person wang("小王", 19, current_time); // 3. 插入数据(必须用事务包裹,保证原子性) { // 开启事务 odb::core::transaction t(db->begin()); // 插入数据:persist()会自动生成INSERT语句 size_t zid = db->persist(zhang); // 返回插入的主键ID size_t wid = db->persist(wang); std::cout << "插入成功!小张的ID:" << zid << ",小王的ID:" << wid << std::endl; // 提交事务(不提交则数据不生效) t.commit(); } // 4. 查询数据:查询update时间在[2024-05-22 09:09:39, 2024-05-22 09:13:29]之间的记录 { // 定义查询时间范围 ptime start_time = boost::posix_time::time_from_string("2024-05-22 09:09:39"); ptime end_time = boost::posix_time::time_from_string("2024-05-22 09:13:29"); // 开启事务(查询也建议用事务,避免脏读) odb::core::transaction t(db->begin()); // 定义查询条件:update在start_time和end_time之间 typedef odb::query<Person> query; typedef odb::result<Person> result; // 执行查询:query::update是ODB自动生成的成员查询变量 result res(db->query<Person>(query::update > start_time && query::update < end_time)); // 遍历查询结果 std::cout << "\n查询结果:" << std::endl; for (result::iterator it = res.begin(); it != res.end(); ++it) { std::cout << "姓名:" << it->name() << ",年龄:" << it->age() << ",更新时间:" << it->update() << std::endl; } // 提交事务 t.commit(); } return 0; } 

核心解析

  1. 数据库连接odb::mysql::database的构造参数要和你的 MySQL 配置匹配,注意mytest数据库需要手动创建(CREATE DATABASE mytest;);
  2. 事务:所有写操作(persist/update/erase)必须用transaction包裹,查询建议用事务 ——ODB 的事务默认是 “读已提交” 隔离级别,避免数据不一致;
  3. 插入数据db->persist(zhang)会生成INSERT INTO person (age, name, update) VALUES (18, '小张', '2024-05-22 09:10:00'),返回主键 ID;
  4. 查询数据odb::query<Person>是类型安全的查询方式,query::update对应Person类的_update成员,不用手写 SQL,避免注入风险。

3.4 第四步:编译与运行

编译时需要链接 ODB 的核心库、MySQL 驱动和 boost 库,执行以下命令:

  1. 编译代码:
# 编译test.cc和生成的person-odb.cxx c++ -o test test.cpp person-odb.cxx -lodb-mysql -lodb -lodb-boost

链接参数解析

  • -lodb-mysql:ODB 的 MySQL 驱动库;
  • -lodb:ODB 核心库;
  • -lodb-boost:ODB 的 boost 类型支持库。
  1. 踩坑点 3:运行时提示 “找不到 libodb-2.5.0-b.25.so”这是因为 ODB 库安装在/usr/local/lib,系统加载共享库时没找到。执行以下命令临时生效(永久生效需写入/etc/``ld.so``.conf):
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
  1. 运行程序:
./test 

正确输出示例

插入成功!小张的ID:1,小王的ID:2 查询结果: 姓名:小张,年龄:18,更新时间:2024-May-22 09:10:00 姓名:小王,年龄:19,更新时间:2024-May-22 09:10:00 

去 MySQL 里验证一下,确实能看到数据:

mysql -u root -p # 输入密码后执行 use mytest; select * from person; # 输出: # +----+-----+--------+---------------------+ # | id | age | name | update | # +----+-----+--------+---------------------+ # | 1 | 18 | 小张 | 2024-05-22 09:10:00 | # | 2 | 19 | 小王 | 2024-05-22 09:10:00 | # +----+-----+--------+---------------------+

四、ODB 核心知识点:必背手册

4.1 C++ 类型 ↔ MySQL 类型映射表

C++ 类型MySQL 类型默认 NULL 语义
boolTINYINT(1)NOT NULL
charCHAR(1)NOT NULL
signed charTINYINTNOT NULL
unsigned charTINYINT UNSIGNEDNOT NULL
shortSMALLINTNOT NULL
unsigned shortSMALLINT UNSIGNEDNOT NULL
intINTNOT NULL
unsigned intINT UNSIGNEDNOT NULL
long / long longBIGINTNOT NULL
unsigned long / long longBIGINT UNSIGNEDNOT NULL
floatFLOATNOT NULL
doubleDOUBLENOT NULL
std::stringTEXT/VARCHAR(255)NOT NULL
char[N]VARCHAR(N-1)NOT NULL
boost::gregorian::dateDATENULL
boost::posix_time::ptimeDATETIMENULL
boost::posix_time::time_durationTIMENULL

4.2 常用 #pragma db 指令

指令作用
#pragma db object声明类为持久化类(映射到数据库表)
#pragma db table("tab_name")指定类映射的表名(默认是类名小写),比如#pragma db table("t_person")
#pragma db id声明主键,可加auto(自动生成)、sequence(序列)等
#pragma db column("col_name")指定成员映射的列名,比如#pragma db column("user_name")
#pragma db type("mysql_type")指定数据库列类型,比如#pragma db type("VARCHAR(100)")
#pragma db not_null强制列非空(默认 C++ 成员是 NOT NULL,除非用nullable<T>
#pragma db unique给列加唯一约束,比如#pragma db unique(避免重复值)
#pragma db transient声明成员不持久化(不映射到数据库列)
#pragma db index("idx_name")给列加索引,比如#pragma db index("idx_person_age")

4.3 核心类与方法

类名作用关键方法
odb::database数据库连接的抽象类begin()(开启事务)、persist()(插入)
odb::mysql::databaseMySQL 的具体实现类构造函数(创建连接)
odb::transaction事务管理类commit()(提交)、rollback()(回滚)
odb::query<T>类型安全的查询类支持 &&/
odb::result<T>查询结果集类begin()/end()(遍历)、size()(数量)
odb::nullable<T>支持 NULL 的类型封装(比如nullable<int>get()(获取值)、operator->(指针访问)

五、进阶:DAO 层封装(可直接复用)

实际项目中,我们会把数据库操作封装成 DAO(Data Access Object)层,避免代码重复。这里基于前文的Person例子,封装一个通用的MysqlClient(连接池 + 事务)和PersonDao(具体业务操作):

#include <odb/database.hxx> #include <odb/mysql/database.hxx> #include <odb/mysql/connection-pool.hxx> // 连接池头文件 #include <memory> #include <vector> // 1. MySQL客户端工具类(单例,管理连接池和事务) class MysqlClient { public: // 创建数据库连接(带连接池) static std::shared_ptr<odb::database> create( const std::string& user, const std::string& passwd, const std::string& db_name, const std::string& host, int port, size_t max_conn = 3 // 连接池最大连接数 ) { // 初始化连接池 std::unique_ptr<odb::mysql::connection_pool_factory> pool( new odb::mysql::connection_pool_factory(max_conn) ); // 创建MySQL连接 return std::make_shared<odb::mysql::database>( user.c_str(), passwd.c_str(), db_name.c_str(), host.c_str(), port, 0, "utf8", 0, std::move(pool) // 传入连接池 ); } // 开启事务 static std::shared_ptr<odb::transaction> begin_transaction(const std::shared_ptr<odb::database>& db) { return std::make_shared<odb::transaction>(db->begin()); } // 提交事务 static void commit(const std::shared_ptr<odb::transaction>& tx) { tx->commit(); } // 回滚事务 static void rollback(const std::shared_ptr<odb::transaction>& tx) { tx->rollback(); } }; // 2. Person的DAO类(封装具体业务操作) class PersonDao { public: PersonDao( const std::string& user, const std::string& passwd, const std::string& db_name, const std::string& host, int port ) : _db(MysqlClient::create(user, passwd, db_name, host, port)) {} // 插入Person bool insert(const Person& person) { try { auto tx = MysqlClient::begin_transaction(_db); _db->persist(person); MysqlClient::commit(tx); return true; } catch (const std::exception& e) { std::cerr << "插入失败:" << e.what() << std::endl; return false; } } // 根据姓名查询Person std::vector<Person> query_by_name(const std::string& name) { std::vector<Person> res; try { auto tx = MysqlClient::begin_transaction(_db); typedef odb::query<Person> query; typedef odb::result<Person> result; // 查询条件:name等于传入值 result rs = _db->query<Person>(query::name == name); for (auto& p : rs) { res.push_back(p); } MysqlClient::commit(tx); } catch (const std::exception& e) { std::cerr << "查询失败:" << e.what() << std::endl; } return res; } // 根据ID删除Person bool delete_by_id(unsigned long id) { try { auto tx = MysqlClient::begin_transaction(_db); // 先查询再删除(也可以用erase_query) Person p; if (_db->load(id, p)) { // load()根据ID查询 _db->erase(p); // erase()删除 MysqlClient::commit(tx); return true; } MysqlClient::commit(tx); return false; } catch (const std::exception& e) { std::cerr << "删除失败:" << e.what() << std::endl; return false; } } private: std::shared_ptr<odb::database> _db; // 数据库连接 }; // 使用示例 int main() { // 初始化DAO PersonDao dao("root", "123456", "mytest", "127.0.0.1", 0); // 插入 ptime now = boost::posix_time::second_clock::local_time(); Person li("小李", 20, now); dao.insert(li); // 查询 auto persons = dao.query_by_name("小李"); for (auto& p : persons) { std::cout << "姓名:" << p.name() << ",年龄:" << p.age() << std::endl; } // 删除(假设ID是3) dao.delete_by_id(3); return 0; }

封装优势

  • 连接池:odb::mysql::connection_pool_factory管理连接,避免频繁创建 / 销毁连接的开销;
  • 事务封装:begin_transaction/commit/rollback统一管理,减少重复代码;
  • 业务与数据分离:DAO 层只负责数据库操作,业务层不用关心连接和事务细节。

六、总结与参考资料

ODB 作为 C++ 的 ORM 工具,虽然学习成本比 Java 的 MyBatis 高,但能极大提升 C++ 项目的数据库操作效率 —— 尤其是中大型项目,避免手写 SQL 带来的维护成本和错误。

关键回顾

  1. 安装时注意build2版本和网络超时,odb命令找不到就配置 PATH;
  2. 持久化类必须加#pragma db object和友元odb::access
  3. 所有数据库操作(尤其是写操作)必须用事务包裹;
  4. 运行时找不到共享库就配置LD_LIBRARY_PATH

官方资料

如果在使用中遇到问题,建议先查官方手册 —— 大部分坑都能在手册里找到解决方案。动手试试吧,用 ODB 重构你的 C++ 数据库代码!

Read more

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

摘要:本文聚焦OpenClaw从测试环境走向生产环境的核心痛点,围绕“性能优化、安全加固、监控运维”三大维度展开实操讲解。先明确生产环境硬件/系统选型标准,再通过硬件层资源管控、模型调度策略、缓存优化等手段提升响应速度(实测响应效率提升50%+);接着从网络、权限、数据三层构建安全防护体系,集成火山引擎安全方案拦截高危操作;最后落地TenacitOS可视化监控与Prometheus告警体系,配套完整故障排查清单和虚拟实战案例。全文所有配置、代码均经实测验证,兼顾新手入门实操性和进阶读者的生产级部署需求,帮助开发者真正实现OpenClaw从“能用”到“放心用”的跨越。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:

By Ne0inhk
ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门: 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》 ❄专栏传送门: 《freertos专栏》《STM32 HAL库专栏》 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言  一、实验基础说明 1.1、互斥体简介 1.2 本次实验设计思路 二、硬件原理分析(看过之前博客的可以忽略) 三、实验程序编写 3.1 互斥体 LED 驱动代码(mutex.c) 3.2.1、设备结构体定义(28-39

By Ne0inhk
Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做? 1. 对着文档,手写 Dart Model 类(容易写错字段类型)。 2. 手写 Retrofit/Dio 的 API 接口定义(容易拼错 URL)。 3. 当后端修改了字段名,你对着报错修半天。 这是重复劳动的地狱。 swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括: * Model 类:支持 json_serializable,带 fromJson/

By Ne0inhk
Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

文章目录 * 前言 * make/makefile * 文件的三个时间 * Linux第一个小程序-进度条 * 回车和换行 * 缓冲区 * 程序的代码展示 * git指令 * 关于gitee * Linux调试器-gdb使用 * 作业部分 前言 做 Linux 开发时,你是不是也遇到过这些 “卡脖子” 时刻?写 makefile 时,明明语法没错却报错,最后发现是依赖方法行没加 Tab;想提交代码到 gitee,记不清 git add/commit/push 的 “三板斧”,还得反复搜教程;用 gdb 调试程序,输了命令没反应,才想起编译时没加-g生成 debug 版本;甚至连写个进度条,都搞不懂\r和\n的区别,导致进度条乱跳…… 其实这些问题,

By Ne0inhk