示例:
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/[email protected]
go install google.golang.org/grpc/cmd/[email protected]
至此使用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: 14
null
参考: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 {
// 用户id
string 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=.
附:官方文档给出的命令:
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 logic
import (
"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.Context
svcCtx *svc.ServiceContext
logx.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 line
userRes :=&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 getOrder
get /api/order/get/:id (OrderReq) returns (OrderReply)
}
order
服务的命令go-zero-micro\api\order>
下执行goctl api go -api order.api -dir .
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:2379
Key: user.rpc
user.yaml
:
# user.yaml
Name: user.rpc
ListenOn: 0.0.0.0:8080
Etcd:
Hosts:
- 192.168.13.3:2379
Key: user.rpc
user服务
的RPC。package config
import (
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
}
user服务
接口加入到 order服务
的ServiceContext
中。package svc
import (
"github.com/zeromicro/go-zero/zrpc"
"go-zero-micro/api/order/internal/config"
"go-zero-micro/rpc/user/userclient"
)
type ServiceContext struct {
Config config.Config
UserRpc userclient.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
}
}
order服务
修改 getorderlogic.go
:
package logic
import (
"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.Logger
ctx context.Context
svcCtx *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 line
Id,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 main
import (
"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.Config
conf.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 main
import (
"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.Config
conf.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
返回结果:用户不存在