示例:
goctl api plugin -plugin goctl-swagger="swagger -filename xxx.json" -api xxx.api -dir .
示例:
goctl api go -api ./doc/admin.api -dir .
示例:
goctl rpc protoc xxx.proto --go_out=./ --go-grpc_out=./ --zrpc_out=.
生成的文件名有下划线分割:
goctl rpc protoc xxx.proto --go_out=./ --go-grpc_out=./ --zrpc_out=. --style=go_zero
logic分组:【不推荐,改动太大】
首先是将proto里的service 进行分组:
service User {rpc getUser(IdRequest) returns(UserResponse);
}
service File {rpc FileUpload(FileList) returns(FileList);
}
然后执行:
goctl rpc protoc xxx.proto --go_out=./ --go-grpc_out=./ --zrpc_out=. --multiple
goctl model mysql ddl -src="./rpc/doc/sql/appsystem/dsms*.sql" -dir="./rpc/model/appsystemodel"
docker run -d -p 9981:8080 --name=swagger-tracksourcetask -v /root/doc:/tmp -e SWAGGER_FILE=/tmp/tracksourcetask-v2.json swaggerapi/swagger-editor
go-zero的是基于go的,所以首先需要安装配置go环境,go的安装配置可参考:Golang安装配置、GoLand安装配置 ,此处不再赘述。
注意:如果是更新组件的版本,建议先备份原来的组件,防止最新版本的组件出现不兼容的问题。
4.3 方式 1
和 4.4 方式 2
均能安装go-zero的环境,如果按照方式1安装某个组件失败,可按方式2来安装缺失的组件。
goctl
go install github.com/zeromicro/go-zero/tools/goctl@latest
查看goctl版本:goctl -v
PS E:\SoftwareData\Aliyun> goctl -v
goctl version 1.4.3 windows/amd64
protoc
、protoc-gen-go
、protoc-gen-go-grpc
goctl env check -i -f --verbose
需要先下载protoc执行器
protoc --version
Protobuf下Go、GRPC插件的安装
protoc-gen-go:Go专用的protoc的编译器插件,安装后会在GOPATH的bin目录下生成一个protoc-gen-go.exe
protoc-gen-go-grp:Go调用grpc的插件,安装后会在GOPATH的bin目录下生成一个protoc-gen-go-grpc.exe
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
至此使用Protobuf的准备工作就做完了。
go install github.com/zeromicro/go-zero/tools/goctl@latest
快速生成api
服务,api
服务就是网关服务,如果不与Service
端【RPC端
】交互,则可以独立成一个单独的服务。
goctl api new greet
cd greet
go mod init
go mod tidy
go run greet.go -f etc/greet-api.yaml
默认侦听在 8888 端口(可以在配置文件里修改):
curl -i http://localhost:8888/from/you
返回如下:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Traceparent: 00-45fa9e7a7c505bad3a53a024e425ace9-eb5787234cf3e308-00
Date: Thu, 22 Oct 2020 14:03:18 GMT
Content-Length: 14null
参考:api配置
参考:rpc配置
参考:单体服务
代码:https://gitee.com/XiMuQi/go-zero-micro/tree/v1.0.0【暂不对外开发】
go-zero微服务的注册中心默认使用的是Etcd。
本小节将以一个订单服务
调用用户服务
来简单演示一下,其实订单服务
是api
下的一个网关,用户服务
是rpc
下的一个后端服务。
这里的创建步骤和官方文档的不一致,做了部分优化,前提是已经了解了go-zero
微服务调用及配置流程。初学者还是推荐按照官方文档操作。
go-zero-micro
文件夹go-zero-micro
文件夹分别创建api
、rpc
文件夹api
下创建order
文件夹rpc
下创建user
文件夹整个服务结构
user
服务下添加user.proto
文件,增加getUser
方法syntax = "proto3";package user;// protoc-gen-go 版本大于1.4.0, proto文件需要加上go_package,否则无法生成
option go_package = "./user";message IdRequest {string id = 1;
}message UserResponse {// 用户idstring id = 1;// 用户名称string name = 2;// 用户性别string gender = 3;
}service User {rpc getUser(IdRequest) returns(UserResponse);
}
go-zero-micro\rpc\user>
下执行goctl rpc protoc user.proto --go_out=./ --go-grpc_out=./ --zrpc_out=.
生成user服务
代码结构:
附:官方文档给出的命令:
goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
生成的代码结构:
两个命令的主要区别是官方文档给出的命令指定了 .pb.go
和 _grpc.pb.go
所在位置,这个不影响代码逻辑。
user服务的代码逻辑主要是在 internal/logic/xxx logic.go
里填写,xxx logic.go
的xxx
指的是在.proto
中定义的方法名的小写。
例如:
user.proto
rpc getUser(IdRequest) returns(UserResponse);
对应 internal/logic/getuserlogic.go
,一个rpc
方法对应一个logic.go
。在logic.go
中可以进一步处理请求,比如操作数据库,Redis等。
package logicimport ("context""go-zero-micro/rpc/user/internal/svc""go-zero-micro/rpc/user/user""github.com/zeromicro/go-zero/core/logx"
)type GetUserLogic struct {ctx context.ContextsvcCtx *svc.ServiceContextlogx.Logger
}func NewGetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLogic {return &GetUserLogic{ctx: ctx,svcCtx: svcCtx,Logger: logx.WithContext(ctx),}
}func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {// todo: add your logic here and delete this lineuserRes :=&user.UserResponse{Id: in.Id,Gender: "男",}if in.Id == "1" {userRes.Name = "admin"}else {userRes.Name = "test"}return userRes, nil
}
order
服务下添加order.api
文件,增加getUser
方法syntax = "v1"info(title: "type title here"desc: "type desc here"author: "type author here"email: "type email here"version: "type version here"
)type(OrderReq {Id string `path:"id"`}OrderReply {Id string `json:"id"`Name string `json:"name"`}
)
service order {@handler getOrderget /api/order/get/:id (OrderReq) returns (OrderReply)
}
order
服务的命令go-zero-micro\api\order>
下执行goctl api go -api order.api -dir .
生成order服务代码结构:
order服务
调用user服务
需要改动3个地方。
1 etc/order.yaml
2 internal/config/config.go
3 internal/svc/servicecontext.go
user服务
的Etcd
服务发现。注意要和user服务
的user.yaml
的Etcd
地址一致。# order.yaml
Name: order
Host: 0.0.0.0
Port: 8888
UserRpc:Etcd:Hosts:- 192.168.13.3:2379Key: user.rpc
user.yaml
:
# user.yaml
Name: user.rpc
ListenOn: 0.0.0.0:8080
Etcd:Hosts:- 192.168.13.3:2379Key: user.rpc
user服务
的RPC。package configimport ("github.com/zeromicro/go-zero/rest""github.com/zeromicro/go-zero/zrpc"
)type Config struct {rest.RestConfUserRpc zrpc.RpcClientConf
}
user服务
接口加入到 order服务
的ServiceContext
中。package svcimport ("github.com/zeromicro/go-zero/zrpc""go-zero-micro/api/order/internal/config""go-zero-micro/rpc/user/userclient"
)type ServiceContext struct {Config config.ConfigUserRpc userclient.User
}func NewServiceContext(c config.Config) *ServiceContext {return &ServiceContext{Config: c,UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),}
}
order服务
修改 getorderlogic.go
:
package logicimport ("context""errors""go-zero-micro/api/order/internal/svc""go-zero-micro/api/order/internal/types""go-zero-micro/rpc/user/user""strconv""github.com/zeromicro/go-zero/core/logx"
)type GetOrderLogic struct {logx.Loggerctx context.ContextsvcCtx *svc.ServiceContext
}func NewGetOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrderLogic {return &GetOrderLogic{Logger: logx.WithContext(ctx),ctx: ctx,svcCtx: svcCtx,}
}func (l *GetOrderLogic) GetOrder(req *types.OrderReq) (resp *types.OrderReply, err error) {// todo: add your logic here and delete this lineId,err := strconv.Atoi(req.Id)if err != nil {return nil, err}if Id < 1{return nil, errors.New("用户不存在")}userRes, err := l.svcCtx.UserRpc.GetUser(l.ctx, &user.IdRequest{Id: req.Id,})if err != nil {return nil, err}return &types.OrderReply{Id: req.Id,Name: userRes.Name,}, nil
}
user服务
再启动order服务
。user服务
启动是执行user服务
下的user.go
如果启动报找不到user.yaml
,则是因为user服务在go-zero-micro
下,更改下user.yaml
的引入路径即可。
error: config file etc/user.yaml, open etc/user.yaml: The system cannot find the path specified.
user.go
:
package mainimport ("flag""fmt""go-zero-micro/rpc/user/internal/config""go-zero-micro/rpc/user/internal/server""go-zero-micro/rpc/user/internal/svc""go-zero-micro/rpc/user/user""github.com/zeromicro/go-zero/core/conf""github.com/zeromicro/go-zero/core/service""github.com/zeromicro/go-zero/zrpc""google.golang.org/grpc""google.golang.org/grpc/reflection"
)var configFile = flag.String("f", "rpc/user/etc/user.yaml", "the config file")func main() {flag.Parse()var c config.Configconf.MustLoad(*configFile, &c)ctx := svc.NewServiceContext(c)s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {user.RegisterUserServer(grpcServer, server.NewUserServer(ctx))if c.Mode == service.DevMode || c.Mode == service.TestMode {reflection.Register(grpcServer)}})defer s.Stop()fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)s.Start()
}
order服务
启动是执行order服务
下的order.go
如果启动报找不到order.yaml
,则是因为order服务在go-zero-micro
下,更改下order.yaml
的引入路径即可。
package mainimport ("flag""fmt""go-zero-micro/api/order/internal/config""go-zero-micro/api/order/internal/handler""go-zero-micro/api/order/internal/svc""github.com/zeromicro/go-zero/core/conf""github.com/zeromicro/go-zero/rest"
)var configFile = flag.String("f", "api/order/etc/order.yaml", "the config file")func main() {flag.Parse()var c config.Configconf.MustLoad(*configFile, &c)server := rest.MustNewServer(c.RestConf)defer server.Stop()ctx := svc.NewServiceContext(c)handler.RegisterHandlers(server, ctx)fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)server.Start()
}
order服务
的端口配置在order.yaml
中,具体的调用地址可在:order/internal/handler/routes.go
中查看。
本示例的完整调用地址为:http://localhost:8888/api/order/get/{参数}
测试1:
请求地址:http://localhost:8888/api/order/get/1
返回结果:{"id":"1","name":"admin"}
测试2:
请求地址:http://localhost:8888/api/order/get/2
返回结果:{"id":"2","name":"test"}
测试3:
请求地址:http://localhost:8888/api/order/get/-1
返回结果:用户不存在