通过protoc工具生成proto的pb.go文件以及使用protoc-go-inject-tag工具注入自定义标签

1.ProtoBuf认识,安装以及用法

参考:[golang 微服务] 3. ProtoBuf认识,安装以及golang 中ProtoBuf使用

2. 使用protoc-go-inject-tag工具注入自定义标签

这里有一个案例:

syntax=proto3;
package test;

option go_package = ".;test";

message MyMessage {
    int64 Code = 1;
}

执行protoc --proto_path=. --go_out=. test.proto导出的test.pb.go里的MyMessage这个结构体的定义会是这样:

type MyMessage struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Code int64 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"`
}

可以看到Code字段的protobuf和json的tag都是固定的(目前还没有找到方法能通过protoc命令的参数来设置tag),但是这样的struct有时候并不是我们所期待的,比如下面的代码片段:

msg := &MyMessage{Code: 0}
bdata, _ := json.Marshal(msg)
fmt.Println(string(bdata))

这段代码最终的输出会是{},因为Code的json tag设置了omitempty,这种情况在开发过程中有时候是很蛋疼的,因为即便Code是默认值0,我们也还是希望能打印出来的。因此我们需要一种方法能通过在编写proto文件的时候,在里面注入tag,然后导出成go的时候这个被注入的字段的tag可以自定义。

这时,就可以使用protoc-go-inject-tag工具了, 这个库可以在proto文件中注入tag,然后在导出的时候相应的字段的tag就可以被修改掉了,,步骤如下:

(1).proto-go-inject-tag工具介绍

protoc-go-inject-tag 是一个用于在生成的 Go 结构体中注入自定义标签的工具。在使用 Protocol Buffers(protobuf)生成 Go 代码时,默认情况下生成的.go文件里的结构体标签是没办法灵活设置的。protoc-go-inject-tag 工具允许开发者在生成的 Go 文件中注入自定义的标签,从而提高代码的灵活性和可维护性

(2).下载并安装protoc-go-inject-tag

首先,确保已经安装了 protoc 和 protoc-gen-go,然后安装 protoc-go-inject-tag

go install github.com/favadi/protoc-go-inject-tag@latest

(3)..proto文件创建

这里举个例子: agent.proto文件部分原始代码如下:

syntax = "proto3";
package agent.pb;

// 代理数据-统计日报
option go_package = "agent/proto/agentpb";

//分组成员(组,成员)详细代理数据model Body
message GroupDetailDataModelBody{
   
    repeated GroupDetailDataModel list = 1;
}

//获取分组成员(组长,成员)对应的代理相关数据
//分组成员(组,成员)详细代理数据model
message GroupDetailDataModel{
    
    uint64 id = 1; // 组id(group_id)/成员id(manager_id)
     
    string name = 2;  // 名称
    
    uint64 new_agent_num = 3; // 新增代理人数
   
    uint64 effect_agent_num = 4; // 有效新增代理人数: exp > 0的人数
   
    uint64 exp = 5; // 代理充值金额
    
    bool is_group = 6; //  当is_group为false时,id表示成员id(也就是manager_id),点击"详情"时,访问的是daily/detailAccount接口; 当is_group为true时,id表示组id(也就是group_id), 点击"详情"时,访问的是daily/detailGroup接口
}

(4).生成.pb.go文件

cd 到proto文件下面,执行下面命令即可:

protoc --go_out=./ agent.proto  //一般情况下使用这个命令
protoc --go_out=plugins=grpc:. agent.proto  //有RPC服务的情况下使用这个命令

(5).查看.pb.go文件

通过protoc --go_out 生成的agent.pb.go部分结构体如下:

// 获取分组成员(组长,成员)对应的代理相关数据
// 分组成员(组,成员)详细代理数据model
type GroupDetailDataModel struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	
	Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // 组id(group_id)/成员id(manager_id)
	
	Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // 名称
	
	NewAgentNum uint64 `protobuf:"varint,3,opt,name=new_agent_num,json=newAgentNum,proto3" json:"new_agent_num,omitempty"` // 新增代理人数
	
	EffectAgentNum uint64 `protobuf:"varint,4,opt,name=effect_agent_num,json=effectAgentNum,proto3" json:"effect_agent_num,omitempty"` // 有效新增代理人数: exp > 0的人数
	
	Exp uint64 `protobuf:"varint,5,opt,name=exp,proto3" json:"exp,omitempty"` // 代理充值金额
	
	IsGroup bool `protobuf:"varint,6,opt,name=is_group,json=isGroup,proto3" json:"is_group,omitempty"` //  当is_group为false时,id表示成员id(也就是manager_id),点击"详情"时,访问的是daily/detailAccount接口; 当is_group为true时,id表示组id(也就是group_id), 点击"详情"时,访问的是daily/detailGroup接口
}

上述结构体中,json格式中的omitempty表示:如果该属性没有值,则不会显示,也就是说,当对应属性为nil或者没有赋值时,不会返回给前端接口

但是,有时候,却需要返回给前端接口对应的值,不论其值是否存在,这里就需要使用protoc-go-inject-tag工具来自定义标签了,操作如下步骤

(5).使用protoc-go-inject-tag工具注入自定义标签

首先,需要修改proto代码,自定义标签使用语法如下:  // @gotags: json:"属性名", 通过设置,然后通过protoc-go-inject-tag -input=./xxx.pb.go 就可以自定义设置属性标签了,修改proto文件如下:

syntax = "proto3";
package agent.pb;

// 代理数据-统计日报
option go_package = "agent/proto/agentpb";

message GroupDetailDataModelBody{
    // @gotags: json:"list"
    repeated GroupDetailDataModel list = 1;
}

//获取分组成员(组长,成员)对应的代理相关数据
//分组成员(组,成员)详细代理数据model
message GroupDetailDataModel{
    // @gotags: json:"id"
    uint64 id = 1; // 组id(group_id)/成员id(manager_id)
     // @gotags: json:"name"
    string name = 2;  // 名称
    // @gotags: json:"new_agent_num"
    uint64 new_agent_num = 3; // 新增代理人数
    // @gotags: json:"effect_agent_num"
    uint64 effect_agent_num = 4; // 有效新增代理人数: exp > 0的人数
    // @gotags: json:"exp"
    uint64 exp = 5; // 代理充值金额
    // @gotags: json:"is_group"
    bool is_group = 6; //  当is_group为false时,id表示成员id(也就是manager_id),点击"详情"时,访问的是daily/detailAccount接口; 当is_group为true时,id表示组id(也就是group_id), 点击"详情"时,访问的是daily/detailGroup接口
}

上面自定义对应的属性标签,json中只有对应的属性,去掉了 omitempty,也就是说:不论对应的属性是否有值,其属性名称都应该返回,没有值时返回的是默认值

通过protoc-go-inject-tag -input=命令注入自定义标签修该.pb.go文件如下:

protoc-go-inject-tag -input=./agent.pb.go

修改后的.pb.go部分代码如下:

// 分组成员(组,成员)详细代理数据model
type GroupDetailDataModel struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	// @gotags: json:"id"
	Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id"` // 组id(group_id)/成员id(manager_id)
	// @gotags: json:"name"
	Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` // 名称
	// @gotags: json:"new_agent_num"
	NewAgentNum uint64 `protobuf:"varint,3,opt,name=new_agent_num,json=newAgentNum,proto3" json:"new_agent_num"` // 新增代理人数
	// @gotags: json:"effect_agent_num"
	EffectAgentNum uint64 `protobuf:"varint,4,opt,name=effect_agent_num,json=effectAgentNum,proto3" json:"effect_agent_num"` // 有效新增代理人数: exp > 0的人数
	// @gotags: json:"exp"
	Exp uint64 `protobuf:"varint,5,opt,name=exp,proto3" json:"exp"` // 代理充值金额
	// @gotags: json:"is_group"
	IsGroup bool `protobuf:"varint,6,opt,name=is_group,json=isGroup,proto3" json:"is_group"` //  当is_group为false时,id表示成员id(也就是manager_id),点击"详情"时,访问的是daily/detailAccount接口; 当is_group为true时,id表示组id(也就是group_id), 点击"详情"时,访问的是daily/detailGroup接口
}

和原始.pb.go比较可看出, json发生了变化, omitempty没有了,这就达到了自定义标签的效果

你可能感兴趣的:(golang,#,golang基础,golang,开发语言,后端,protobuf,protoc,go-inject-tag)