通过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没有了,这就达到了自定义标签的效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity 2D实战小游戏开发跳跳鸟 - 跳跳鸟碰撞障碍物逻辑

在有了之前创建的可移动障碍物之后,就可以开始进行跳跳鸟碰撞到障碍物后死亡的逻辑,死亡后会产生一个对应的效果。 跳跳鸟碰撞逻辑 创建Obstacle Tag 首先跳跳鸟在碰撞到障碍物时,我们需要判定碰撞到的是障碍物,可以给障碍物的Prefab预制体添加一个Tag为Obstacle,添加步…

记录 | Docker的windows版安装

目录 前言一、1.1 打开“启用或关闭Windows功能”1.2 安装“WSL”方式1:命令行下载方式2:离线包下载 二、Docker Desktop更新时间 前言 参考文章:Windows Subsystem for Linux——解决WSL更新速度慢的方案 参考视频:一个视频解决D…

[SAP ABAP] 在ABAP Debugger调试器中设置断点

在命令框输入/H,点击回车以后,调试被激活,点击触发任意事件进入ABAP Debugger调试器界面 点击按钮,可以在Debugger调试器中新增临时断点 我们可以从ABAP命令、方法、功能、表单、异常、消息、源代码等多个维度在Debugger调试器中设…

深度学习之“线性代数”

线性代数在深度学习中是解决多维数学对象计算问题的核心工具。这些数学对象包括标量、向量、矩阵和张量,借助它们可以高效地对数据进行操作和建模。以下将详细介绍这些数学对象及其在深度学习中的典型用途。 数学对象概述 标量 标量是最简单的数学对象&#xff0…

【面经】字节南京一面部分题目记录

南京字节一面题,可能因为项目不太匹配,全程八股比较多,也有两道手撕代码题,强度还是有的。为了方便大家学习,大部分答案由GPT整理,有些题给出了我认为回答比较好的博客链接。 文章目录 一、python2 和 pyth…

17.3.4 颜色矩阵

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 17.3.4.1 矩阵基本概念 矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,类似于数组。 由…

LabVIEW在电机自动化生产线中的实时数据采集与生产过程监控

在电机自动化生产线中,实时数据采集与生产过程监控是确保生产效率和产品质量的重要环节。LabVIEW作为一种强大的图形化编程平台,可以有效实现数据采集、实时监控和自动化控制。详细探讨如何利用LabVIEW实现这一目标,包括硬件选择、软件架构设…

mybatis(78/134)

前天学了很多&#xff0c;关于java的反射机制&#xff0c;其实跳过了new对象&#xff0c;然后底层生成了字节码&#xff0c;创建了对应的编码。手搓了一遍源码&#xff0c;还是比较复杂的。 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE …

【NLP251】Transformer精讲 残差链接与层归一化

精讲部分&#xff0c;主要是对Transformer的深度理解方便日后从底层逻辑进行创新&#xff0c;对于仅应用需求的小伙伴可以跳过这一部分&#xff0c;不影响正常学习。 1. 残差模块 何凯明在2015年提出的残差网络&#xff08;ResNet&#xff09;&#xff0c;Transformer在2016年…

全程Kali linux---CTFshow misc入门(25-37)

第二十五题&#xff1a; 提示&#xff1a;flag在图片下面。 直接检查CRC&#xff0c;检测到错误&#xff0c;就直接暴力破解。 暴力破解CRC的python代码。 import binascii import struct def brute_force_ihdr_crc(filename): # 读取文件二进制数据 with open(filen…

OpenAI深夜反击:o3-mini免费上线,能否撼动DeepSeek的地位?

还在为寻找合适的 AI 模型而烦恼吗&#xff1f;chatTools 平台为您精选 o1、GPT4o、Claude、Gemini 等顶尖 AI 模型&#xff0c;满足您不同的 AI 应用需求。立即体验强大的 AI 能力&#xff01; 深夜反击&#xff0c;OpenAI祭出o3-mini 在DeepSeek异军突起&#xff0c;搅动AI行…

蓝桥杯备考:模拟算法之字符串展开

P1098 [NOIP 2007 提高组] 字符串的展开 - 洛谷 | 计算机科学教育新生态 #include <iostream> #include <cctype> #include <algorithm> using namespace std; int p1,p2,p3; string s,ret; void add(char left,char right) {string tmp;for(char ch left1;…

NLP深度学习 DAY5:Sequence-to-sequence 模型详解

Seq2Seq&#xff08;Sequence-to-Sequence&#xff09;模型是一种用于处理输入和输出均为序列任务的深度学习模型。它最初被设计用于机器翻译&#xff0c;但后来广泛应用于其他任务&#xff0c;如文本摘要、对话系统、语音识别、问答系统等。 核心思想 Seq2Seq 模型的目标是将…

于动态规划的启幕之章,借 C++ 笔触绘就算法新篇

注意&#xff1a;代码由易到难 P1216 [IOI 1994] 数字三角形 Number Triangles 题目链接&#xff1a;[IOI 1994] 数字三角形 Number Triangles - 洛谷 题目描述 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径&#xff0c;使路径经过数字的和最大。每…

Three.js 后期处理(Post-Processing)详解

目录 前言 一、什么是后期处理&#xff1f; 二、Three.js 后期处理的工作流程 2.1 创建 EffectComposer 2.2 添加渲染通道&#xff08;Render Pass&#xff09; 2.3 应用最终渲染 三、后期处理实现示例 3.1 基础代码 四、常见的后期处理效果 4.1 辉光效果&#xf…

低代码系统-产品架构案例介绍、炎黄盈动-易鲸云(十二)

易鲸云作为炎黄盈动新推出的产品&#xff0c;在定位上为低零代码产品。 开发层 表单引擎 表单设计器&#xff0c;包括设计和渲染 流程引擎 流程设计&#xff0c;包括设计和渲染&#xff0c;需要说明的是&#xff1a;采用国际标准BPMN2.0&#xff0c;可以全球通用 视图引擎 视图…

从 HTTP/1.1 到 HTTP/3:如何影响网页加载速度与性能

一、前言 在最近使用Apipost时&#xff0c;突然注意到了http/1.1和http/2&#xff0c;如下图&#xff1a; 在我根深蒂固的记忆中&#xff0c;对于http的理解还停留在TCP协议、三次握手。由于我的好奇心&#xff0c;于是触发了我被动“开卷”&#xff0c;所以有了这篇文章&…

项目练习:重写若依后端报错cannot be cast to com.xxx.model.LoginUser

文章目录 一、情景说明二、解决办法 一、情景说明 在重写若依后端服务的过程中 使用了Redis存放LoginUser对象数据 那么&#xff0c;有存就有取 在取值的时候&#xff0c;报错 二、解决办法 方法1、在TokenService中修改如下 getLoginUser 方法中&#xff1a;LoginUser u…

C语言------二维数组指针从入门到精通

前言: 目标:需要了解及掌握数组指针的行地址、列地址、具体元素地址、具体元素地址的值是怎样定义及实现。 重点:指针的偏移,指针解引用。 难点:指针的升阶与降阶。 1. 基本概念 二维数组&#xff1a;二维数组可以看作是一个数组的数组。例如&#xff0c;int a[3][4] 表示一个 …

AI-ISP论文Learning to See in the Dark解读

论文地址&#xff1a;Learning to See in the Dark 图1. 利用卷积网络进行极微光成像。黑暗的室内环境。相机处的照度小于0.1勒克斯。索尼α7S II传感器曝光时间为1/30秒。(a) 相机在ISO 8000下拍摄的图像。(b) 相机在ISO 409600下拍摄的图像。该图像存在噪点和色彩偏差。©…