本文从如下几个方面,对Proto结构的定义、编程以及存储进行详细说明:
- Proto文件定义
- 生成proto结构对应的读、写接口
- proto 与 string 相互转换
- proto与json相互转换
- 数据库存取proto结构
- (1)以json格式对proto结构信息进行存取
- (2)以自定义类型 对proto结构信息进行存取
定义 test.proto 文件,文件内容为:
syntax = "proto3";
package SDF;
message ADF_TrafficControlAttr
{
// 管制原因
enum TrafficCtlType{
UNKNOWN_INDUCED = 0; //未知或其他
ROAD_INDUCED = 1; //道路原因
ADMIN_INDUCED = 2; //管理员原因
};
enum TrafficCtlMode{
UNKNOWN = 0; //未知或其他
SPEED_LIMIT = 1; //限制速度
NOPASSING = 2; //禁止通行
};
//受管制车型
enum AffectedType{
ALL = 0; //所有车辆
AUTO = 1; // 所有自动驾驶车辆
MANUAL = 2; // 所有有人车辆
};
TrafficCtlType ctrlType = 1; //
AffectedType affectedType = 2; //syntax = "proto3";
TrafficCtlMode trafficCtlMode = 3; //限制类型 #改
repeated string listOfAffected = 4; //受管制清单 #增删改
int32 speedLimitValue = 5; //限制速
}
message EDF_TrafficControl
{
string eventID = 1; //事件ID #增
ADF_TrafficControlAttr eventAttr = 2; //事件属性 #改2
string warningMessage = 3; //预警提示 #增删改
}
1.2 格式说明
定义消息的语法很简单,message 关键字后跟上消息名称:
message xxx
{
}
定义 message 具有的属性,有如下关键字:
(1)字段规则
required -> 字段只能也必须出现 1 次
optional -> 字段可出现 0 次或1次
repeated -> 字段可出现任意多次(包括 0)
(2)字段类型
int32、int64、sint32、sint64、string、32-bit …
(3)字段编号
范围:0 ~ 536870911(除去 19000 到 19999 之间的数字)
(4)定义格式:
字段规则 类型 名称 = 字段编号;
可通过如下命令生成相应的接口代码:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto
- $SRC_DIR: .proto 所在的源目录
- --cpp_out: 生成 c++ 代码
- $DST_DIR: 生成代码的目标目录
- xxx.proto: 要针对哪个 proto 文件生成接口代码
再如本例:
注意:首先cd 到test.proto所在目录。
protoc -I=./ --cpp_out=./ ./test.proto
执行命令后,会在当前目录下生成test.pb.cc、test.pb.h文件。
C 或 C++程序中,直接使用生成的这两个即可。
3、proto 与 string 相互转换在 .proto 文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输。当需要把这些数据进行存储或传输时,就需要将这些结构数据进行序列化、反序列化以及读写。
#include4、proto与json相互转换#include #include "test.pb.h" using namespace std; void SetProtoValue(SDF::EDF_TrafficControl &trafficContolInfo) { SDF::EDF_TrafficControl trafficContolInfo; auto eventAttr = trafficContolInfo.mutable_eventattr(); eventAttr->set_ctrltype(SDF::ADF_TrafficControlAttr::ROAD_INDUCED); eventAttr->set_affectedtype(SDF::ADF_TrafficControlAttr::MANUAL); eventAttr->set_trafficctlmode(SDF::ADF_TrafficControlAttr::SPEED_LIMIT); eventAttr->add_listofaffected("affectedItem1"); eventAttr->add_listofaffected("affectedItem2"); eventAttr->set_speedlimitvalue(60); trafficContolInfo.set_warningmessage("warningMessage_888"); } int main(int argc, char** argv) { std::string str_protoString = ""; SDF::EDF_TrafficControl trafficContolInfo; SetProtoValue(trafficContolInfo); //Proto结构 转 字符串 std::string str_protoString = trafficContolInfo.SerializeAsString(); //字符串 转 Proto结构 SDF::EDF_TrafficControl trafficContolInfoNew; trafficContolInfoNew.ParseFromString(str_protoString) }
#include5、数据库存取proto结构 5.1 以json格式对proto结构信息进行存取#include #include //是用json转换工具 #include "test.pb.h" using namespace std; void SetProtoValue(SDF::EDF_TrafficControl &trafficContolInfo) { SDF::EDF_TrafficControl trafficContolInfo; auto eventAttr = trafficContolInfo.mutable_eventattr(); eventAttr->set_ctrltype(SDF::ADF_TrafficControlAttr::ROAD_INDUCED); eventAttr->set_affectedtype(SDF::ADF_TrafficControlAttr::MANUAL); eventAttr->set_trafficctlmode(SDF::ADF_TrafficControlAttr::SPEED_LIMIT); eventAttr->add_listofaffected("affectedItem1"); eventAttr->add_listofaffected("affectedItem2"); eventAttr->set_speedlimitvalue(60); trafficContolInfo.set_warningmessage("warningMessage_888"); } int main(int argc, char** argv) { std::string str_protoJsonString = ""; SDF::EDF_TrafficControl trafficContolInfo; SetProtoValue(trafficContolInfo); //Proto结构 转 Json字符串 google::protobuf::util::JsonPrintOptions options; options.add_whitespace = true; options.always_print_primitive_fields = true; options.preserve_proto_field_names = true; if(!MessageToJsonString(traffic_control, &str_protoJsonString, options).ok()) {//parse traffic_control to json string std::cerr << " MessageToJsonString() convert failed" << std::endl; } //Json字符串 转 Proto结构 SDF::EDF_TrafficControl trafficContolInfoNew; if(!google::protobuf::util::JsonStringToMessage(str_protoJsonString, &trafficContolInfoNew).ok()) { printf("MessageToJsonString() convert failed"); } }
数据库存取过程中,除了需要将数据库字段类型定义为json或jsonb外,增、删、改数据库的方法,均与普通字符串类型一致。
json会输出和输入完全相同的文本,而jsonb 则不会保留语义上没有意义的细节(例如空格)。
PostgresSQL从9.2版本开始支持JSON数据类型,并提供很多函数和操作符维护json数据。
本文以postgres数据库为例,进一步说明 转换为json格式后的 proto结构,在数据库中的格式定义及存取方式。
5.1.1 建表:jsonb 或 json 字段类型create table if not exists test_table(event_id serial not null PRIMARY KEY, msg_content_jsonb jsonb, msg_content_json json, time_stamp timestamptz not null);5.1.2 插入数据
insert into test_table(msg_content_jsonb, msg_content_json) values(str_protoJsonString, str_protoJsonString, NOW());5.1.3 查询数据
select event_id, msg_content_jsonb, msg_content_json from test_table;
关于Postgres存储 Json类型字段的详细说明,详见:
《 Postgres - JSON 类型实例示例》
https://aduandniuniu.blog.csdn.net/article/details/125304811?spm=1001.2014.3001.5502
关于Postgres数据库字段 类型定义,详见:
《Postgres - 数据库字段 类型定义》
https://aduandniuniu.blog.csdn.net/article/details/125305244?spm=1001.2014.3001.5502#t7
5.2以自定义类型 对proto结构信息进行存取也可以通过自定义类型的方式,为proto结构定义对应的字段进行存取。
比如:
create type TrafficCtlType as ENUM(
'UNKNOWN_INDUCED' ,
'ROAD_INDUCED',
'ADMIN_INDUCED'
);
create type TrafficCtlMode as ENUM(
'UNKNOWN' ,
'SPEED_LIMIT',
'NOPASSING'
);
create type AffectedType as ENUM(
'ALL' ,
'AUTO',
'MANUAL'
);
create type ADF_TrafficControlAttr as(
ctrlType TrafficCtlType,
affectedType AffectedType,
trafficCtlMode TrafficCtlMode,
listOfAffected text[],
speedLimitValue integer
);
create table traffic_control_ctrl(
eventID serial not null PRIMARY KEY,
eventAttr ADF_TrafficControlAttr,
warningMessage varchar(128),
status RecordStatus
);
关于 Postgres数据库自定义类型 的增、删、改、查 ,更为详细的说明,详见:
《Postgres - 自定义类型》
https://aduandniuniu.blog.csdn.net/article/details/125244683?spm=1001.2014.3001.5502



