入门
1. 环境准备
- go版本:
C:\Users\Huo>go version
go version go1.20.1 windows/amd64
2
goctl安装:
goctl(官方建议读go control)是go-zero微服务框架下的代码生成工具。使用 goctl 可显著提升开发效率,让开发人员将时间重点放在业务开发上,其功能有:
- api服务生成
- rpc服务生成
- model代码生成
- 模板管理
go install github.com/zeromicro/go-zero/tools/goctl@v1.4.4
1这时候会在gopath的bin目录下生成goctl的执行进程(注意要将%GOPATH%\bin设置到path环境变量中)。
C:\Users\Huo>goctl -version goctl version 1.4.4 windows/amd64
1
2protoc & protoc-gen-go安装
go-zero提供了便捷的安装方式:
goctl env check -i -f --verbose
1
IDE工具我这里选择的是Goland,原因是我喜欢用Jetbrains的全家桶。
大家也可以使用广受好评的VS Code,免费的IDE,非常强大。
2.HelloWorld
接下来我们就写一个经典的Hello World程序进行一个简单的入门。
D:\go\project\gozero>mkdir helloworld
D:\go\project\gozero>cd helloworld
D:\go\project\gozero\helloworld>goctl api new hello
D:\go\project\gozero\helloworld>cd hello
D:\go\project\gozero\helloworld\hello>go mod tidy
2
3
4
5
使用goland打开,编写程序。
我们改一下路由,将自动生成的form/:name
改为hello
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodGet,
Path: "/hello",
Handler: HelloHandler(serverCtx),
},
},
)
}
2
3
4
5
6
7
8
9
10
11
type Request struct {
//Name string `path:"name,options=you|me"`
}
2
3
func (l *HelloLogic) Hello(req *types.Request) (resp *types.Response, err error) {
// todo: add your logic here and delete this line
resp = &types.Response{
Message: "Hello go-zero",
}
return
}
2
3
4
5
6
7
8
启动程序,访问http://localhost:8888/hello
// http://localhost:8888/hello
{
"message": "Hello go-zero"
}
2
3
4
5
ok,入门了~
3. 微服务版HelloWorld
场景:
假设有两个服务:
- order service
- user service
用户在查询订单时,同时需要获取用户信息。
D:\go\project\gozero>cd microhelloworld
D:\go\project\gozero\microhelloworld>mkdir mall
D:\go\project\gozero\microhelloworld>cd mall
D:\go\project\gozero\microhelloworld\mall>goctl api new order
D:\go\project\gozero\microhelloworld\mall>goctl api new user
D:\go\project\gozero\microhelloworld\mall>go work init
D:\go\project\gozero\microhelloworld\mall>go work use order
D:\go\project\gozero\microhelloworld\mall>go work use user
2
3
4
5
6
7
8
我们先在user模块提供一个api,用于order调用。
user/rpc/user.proto
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);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
前面我们讲过,服务和服务之间一般使用rpc通信,最常使用的就是grpc,接下来就是使用之前安装的protoc-gen-go将上述的proto文件生成go代码。
这里我们使用的go-zero框架,仍旧是go-zero的方式:
D:\go\project\gozero\microhelloworld\mall\user\rpc> goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
D:\go\project\gozero\microhelloworld\mall\user\rpc> cd ..
D:\go\project\gozero\microhelloworld\mall\user> go mod tidy
2
在logic中填充业务逻辑:
func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
// todo: add your logic here and delete this line
return &user.UserResponse{
Id: "1",
Name: "test",
}, nil
}
2
3
4
5
6
7
8
接下来在order模块,写一个接口,获取订单信息,其中订单信息中需要携带用户信息。
编写order.api
type Request {
Name string `path:"name,options=you|me"`
}
type Response {
Message string `json:"message"`
}
type(
OrderReq {
Id string `path:"id"`
}
OrderReply {
Id string `json:"id"`
Name string `json:"name"`
UserName string `json:"userName"`
}
)
service order-api {
@handler OrderHandler
get /from/:name(Request) returns (Response)
@handler GetOrder
get /api/order/get/:id (OrderReq) returns (OrderReply)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
生成order服务
goctl api go -api order.api -dir ./gen
添加user rpc配置:
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
}
2
3
4
在order-api.yaml
Name: order-api
Host: 0.0.0.0
Port: 8888
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
2
3
4
5
6
7
8
创建对user服务的rpc调用
package svc
import (
"github.com/zeromicro/go-zero/zrpc"
"order/internal/config"
"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)),
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
编写逻辑
package logic
import (
"context"
"errors"
"order/internal/types"
"user/types/user"
"github.com/zeromicro/go-zero/core/logx"
"order/internal/svc"
)
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
userId := l.getOrderById(req.Id)
uResp, err := l.svcCtx.UserRpc.GetUser(context.Background(), &user.IdRequest{
Id: userId,
})
if err != nil {
return nil, err
}
if uResp.Name != "test" {
return nil, errors.New("用户不存在")
}
return &types.OrderReply{
Id: req.Id,
UserName: uResp.Name,
Name: "test order",
}, nil
}
func (l *GetOrderLogic) getOrderById(id string) string {
return "1"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
由于依赖etcd,所以需要启动一个etcd
我们使用docker启动
在mall目录下编写docker-compose.yml
version: '3'
services:
Etcd:
container_name: etcd3
image: bitnami/etcd:${ETCD_VERSION}
deploy:
replicas: 1
restart_policy:
condition: on-failure
environment:
- ALLOW_NONE_AUTHENTICATION=yes
privileged: true
volumes:
- ${ETCD_DIR}/data:/bitnami/etcd/data
ports:
- ${ETCD_PORT}:2379
- 2380:2380
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
同目录下创建.env
COMPOSE_PROJECT_NAME=gozero-demo-mall
ETCD_DIR=D:/go/project/gozero/etcd
ETCD_VERSION=3.5.6
ETCD_PORT=2379
2
3
4
docker-compose up -d
分别启动user服务和order服务。
// http://localhost:8888/api/order/get/1
{
"id": "1",
"name": "test order",
"userName": "test"
}
2
3
4
5
6
7
成功~
恭喜你,入门了~~