本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1 怎么做?
先给出一个目前
我认为
最好
的解决方案, 这么做的原因后面会一个个说,
曾经, 有这么一份真诚的文章放在我面前, 我没有珍惜...
结果浪费了我一整天
看google官方文档
如果你是新手, 希望你别只是看, 跟着做一遍秒懂
(1) 把项目要用的proto文件都放到一个目录下
这个demo项目的代码组织结构如下:
统一把proto文件放到proto文件夹下, 再在里面按各个微服务名称创建文件夹
里面放该微服务的所有proto文件, 以及生成的pb.go和_grpc.pb.go
比如现在项目业务有这样一个需求, group服务需要读取message服务, 获取群消息, 即:
group.proto需要import msg.proto里的一个结构
如何实现呢? 往下看
(2) go.mod
go mod init go_test
会生成下面的go.mod文件
module go_test
go 1.18
复制代码
然后创建远程库, 手动把module go_test
修改为
module github.com/CPALyth/go_test
(替换为你自己的远程库地址)
(3) msg.proto
这个proto文件是被调用的, 记得替换为你自己的远程库地址
syntax = "proto3";
package msg;
option go_package = "github.com/CPALyth/go_test/proto/msg";
message ChatMsg {
int64 id=1; // 消息id
string groupId=2; // 群id
int64 senderId=3; // 发送者uid
int64 type=4; // 消息类型 1文本, 2图片, 3视频, 4音频
string content=5; // 消息内容
string uuid=6; // 作用是去重
int64 createTime=7; // 创建时间
}
复制代码
(4) group.proto
group.proto文件 来调用 msg.proto
syntax = "proto3";
package group;
option go_package = "github.com/CPALyth/go_test/proto/group";
import "proto/msg/msg.proto"; // 注意这里就不要加github...了
// 获取消息页面 群组信息列表
message MessageGroupInfoListRequest {
int64 userId=1;
}
message MessageGroupInfo {
string groupId=1; // 群组id
string aliasName=2; // 备注
string avatarUrl=3; // 头像
msg.ChatMsg lastMsg=4; // 最后一条消息, 注意看这里导入了msg的ChatMsg
}
message MessageGroupInfoListResponse {
repeated MessageGroupInfo list=1;
}
service GroupClient {
rpc MessageGroupInfoList(MessageGroupInfoListRequest) returns(MessageGroupInfoListResponse);
}
复制代码
(5) 生成pb.go和_grpc.pb.go(重点)
生成被调用方(msg.proto)的go stub代码
protoc ./proto/msg/msg.proto --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:.
复制代码
再生成group.proto的go stub代码
protoc ./proto/group/group.proto --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:.
复制代码
go文件一片飘红, 不要紧, 运行 go mod tidy
(6) push, go mod tidy
然后push代码到远程库,
再运行一遍go mod tidy
就好了,
现在完全no problem~~~
2 为什么?
(1) 为什么不能直接两个包都设置ChatMsg这样的结构体?
- ChatMsg类型冲突, 若后面业务中需要同时用GroupRpc和MessageRpc, 将出现runtime panic
- 如果ChatMsg以后改的话, 要两个文件都改, 代码复用性很低
- 细心的你可能会发现, 我这两个包名都是proto, 当然会冲突了, 但我告诉你, 你改了包名照样冲突
(2) 为什么要加上github.com/CPALyth/go_test/
?
如果你在msg.proto里只写option go_package = "app/msg/rpc/proto";
就会有如下事情发生, 它根本不会生成带go module名的路径
手动加? 不太好吧
所以我们加上github.com/CPALyth/go_test/
(要换成你自己的远程库), 然后push到远程, 再go mod tidy
下载到本地$GOPATH
下, 就可以import进来直接用了
(3) go_out=paths=source_relative:. 是什么意思?
一般我们都是写go_out=./
就是把pb.go文件 生成在 当前目录
而paths=source_relative:.
就是把pb.go文件 生成在 proto文件同级目录
--go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative
(4) 为什么不用--go_out=plugins=grpc,paths=source_relative:.?
较新版本的protoc-gen-go已经不再支持plugins=grpc这种写法了, 现在要用--go-grpc_out