go-zero项目快速搭建流程

go-zero的快速搭建流程

1. goctl的安装

1.1 概述

goctl 是 go-zero 的内置脚手架, 是提升 go-zero 开发的一大利器, 可以一键生成代码、文档、
部署 k8s yaml、dockerfile 等。

1.2 golang直装

1.2.1 如果go版本在1.16以前,则使用以下命令安装:

$ go get -u github.com/zeromicro/go-zero/tools/goctl@latest

1.2.2 如果go版本在1.16以后,则使用如下命令安装

& go install github.com/zeromicro/go-zero/tools/goctl@latest

1.2.3 验证安装

& goctl --version
goctl version 1.5.5 linux/amd64

1.3 手动安装

这里以v1.5.6为例, 大家可 前往Github 自行选择

1.3.1 下载Windows64位

goctl-v1.5.6-windows-amd64.zip (14.7M)

1.3.2 下载windows32位

goctl-v1.5.6-windows-386.zip (14M)

1.3.3 macOS ARM64位

goctl-v1.5.6-darwin-arm64.tar.gz (14.5M)

1.3.4 macOS x86-64位

goctl-v1.5.6-darwin-amd64.tar.gz (14.7M)

1.3.5 Linux 64位

goctl-v1.5.6-linux-amd64.tar.gz (14.8M)

1.3.6 Linux 32为

goctl-v1.5.6-linux-386.tar.gz (13.9M)

1.3.7 安装

解压下载的安装包, 并将其移动到$GOBIN目录, 查看$GOBIN目录

go env GOPATH

$GOBIN为 G O P A T H / b i n , 如果你的 GOPATH/bin, 如果你的 GOPATH/bin,如果你的GOPATH不在系统$PATH中, 将其添加到$PATH中即可

1.3.8 验证

$ goctl --version

1.4 docker安装

1.4.1 pull & run

$ docker pull kevinwan/goctl
$ docker run --rm -it -v pwd:/app kevinwan/goctl goctl --help

1.4.2 验证

$ docker run --rm -it -v pwd:/app kevinwan/goctl:latest goctl --version

2. protoc安装

2.1 一键安装

通过goctl可以一键安装protoc, protoc-gen-go, protoc-gen-go-grpc相关组件, 执行命令如下

$ goctl env check --install --verbose --force

2.2 手动安装

2.2.1 下载

可前往 Github官网 自行选择对应的版本

2.2.2 安装

$ go env GOPATH

$GOBIN为$GOPATH/bin, 如果你的$GOPATH不在系统$PATH中, 将其添加到系统$PATH中

2.2.3 验证

$ goctl env check --verbose
[goctl-env]: preparing to check env
[goctl-env]: looking up “protoc”
[goctl-env]: “protoc” is installed
[goctl-env]: looking up “protoc-gen-go”
[goctl-env]: “protoc-gen-go” is installed
[goctl-env]: looking up “protoc-gen-go-grpc”
[goctl-env]: “protoc-gen-go-grpc” is installed
[goctl-env]: congratulations! your goctl environment is ready!

3. go-zero 安装

3.1 安装

$ mkdir && cd # project name 为具体值
$ go mod init # module
$ go get -u github.com/zeromicro/go-zero@latest

4. DSL介绍

4.1 概述

api 是 go-zero 自研的领域特性语言, 作为生成 http 服务最基本的描述语言. api 领域特性语言包含语法版本, info 块, 结构体声明, 服务描述等几大块语言组成, 其中结
构体和 golang 结构体语法几乎一样, 只是移除了 struct 关键字

4.2 快速入门

示例: 简单的用户服务API文件:

syntax = “v1”

type Base {
	Code int `json:”code”` 
	Message string `json:”message”` 
}

type UserInfo {
	Id int64 `json:”id”` 
	Name string `json:”name”`
	Desc string `json:”desc”` 
}

type (
	// 定义登录接口的请求体
	LoginReq {
		Username string `json:”username”` 
		Password string `json:”password”` 
	}
	// 定义登录接口的响应体
	LoginResp {
		Base
		Id int64 `json:”id”` 
		Name string `json:”name”` 
		Token string `json:”token”` 
		ExpiredAt int64 `json:”expired_at”` 
	}
)

type (
	// 定义获取用户信息的请求体
	GetUserInfoReq {
		Id int64 `form:”id”` 
	}
	// 定义获取用户信息的响应体
	GetUserInfoResp {
		Base
		Data UserInfo `json:”data”` 
	}
	// 定义更新用户信息的 json 请求体
	UpdateUserInfoReq {
		Id int64 `json:”id”` 
		Name string `json:”name”` 
		Desc string `json:”desc”` 
	}		
)

// 定义 HTTP 服务
// @server 语法块主要用于控制对 http 服务生成时 mate 信息, 目前支持功能有:
// 1. 路由分组
// 2. 中间件声明
// 3. 路由前缀
// 4. 超时配置
// 5. jwt 鉴权开关
// 所有声明仅对当前 service 中的路由有效
@server (
	// 代表当前 service 代码块下的路由生成代码时都会放到 login 目录下
	group: login
	// 定义路由前缀
	prefix: /v1
)
// 微服务名称位 user, 生成的代码目录和配置文件将和 user 相关
service user {
	// doc 描述信息
	@doc ”登录”
	// 定义 http.HandleFunc 转换的 go 文件名称及方法, 每个接口都会跟一个 handler
	@handler login
	// 定义接口, 请求方式位 post, 路由为/user/login
	// 请求体为 LoginReq, 响应体为 LoginResp, 响应体必须有 returns 关键字修饰
	post /user/login (LoginReq) returns (LoginResp)
}

@server(
	// 代表当前 service 代码块下的所有路由均需要 jwt 鉴权
	// goctl 生成代码时会将当前 service 代码块下的接口信息添加上 jwt 相关的代码, // Authorization 值为 jwt 秘钥, 过期等信息配置的 golang 结构体名称
	jwt: Authorization
	// 代表当前 service 代码块下的路由生成代码时都会被放到 user 目录下
	group: user
	// 定义路由前缀为”/v1” prefix: /v1
	// 定义一个鉴权控制的中间件, 多个中间件以英文逗号分割
	middleware: AuthInterceptor
	// 定义一个超时时间为 3s 的配置
	timeout: 3s
	// 定义一个请求体限制在 1MB 以内
	maxBytes: 1048576
)
// 注意: 定义多个 service 代码块时, 服务名称必须一致, 因此这里的服务名称必须和
// 上文的 service 名称一样, 为 user 服务
service user {
	@handler getUserInfo
	get /user/info (GetUserInfoReq) returns (GetUserInfoResp)
	@handler updateUserInfo
	post /user/info/update (UpdateUserInfoReq)
}

4.3 API语法详情

API语法详情请参考 go-zero 官网 指南中的API定义

5. CLI工具(goctl)

5.1 goctl视图

在这里插入图片描述

5.2 goctl 指令详情

在这里插入图片描述
注: 如需查看所有指令详情请前往 go-zero官网

6. 快速构建微服务

6.1 准备工作

注: 下面以官方示例bookstore demo进行说明

安装 ETCD, mysql, redis, 请自行安装
安装 protoc-gen-go, 请参考本博客protoc的安装章节
安装工具 goctl, 请参考本博客goctl的安装章节
检查goctl环境

$ goctl env
GOCTL_OS=darwin
GOCTL_ARCH=amd64
GOCTL_HOME=/Users/xxx/.goctl
GOCTL_DEBUG=False
GOCTL_CACHE=/Users/xxx/.goctl/cache
GOCTL_VERSION=1.3.3
PROTOC_VERSION=3.17.3
PROTOC_GEN_GO_VERSION=v1.27.1
PROTO_GEN_GO_GRPC_VERSION=1.1.0

创建工作目录bookstore和bookstore/api
在bookstore目录下执行go mod init bookstore, 初始化go.mod

6.2 编写API Gateway代码

6.2.1 在 bookstore/api目录下通过goctl生成api/bookstore.api

指令如下:

goctl api -o bookstore.api

编辑bookstore.api, 修改如下:

syntax = "v1"

info(
	title: 
	desc: 
	author: 
	email: 
	version: "v1"
)

type (
	addReq {
		book string `form:"book"`
		price int64 `form:"price"`
	}
	
	addResp {
		ok bool `json:"ok"`
	}
)

type (
	checkReq {
		book string `form:"book"`
	}
	
	checkResp {
		found bool `json:"found"`
		price int64 `json:"price"`
	}
)

service bookstore-api {
	@handler AddHandler
	get /add (addReq) returns (addResp)
	
	@handler CheckHandler
	get /check (checkReq) returns (checkResp)
}

6.2.2 使用goctl生成API Gateway代码

指令如下:

goctl api go -api bookstore.api -dir .

结构如下:

api
├── bookstore.api                  // api定义
├── bookstore.go                   // main入口定义
├── etc
│   └── bookstore-api.yaml         // 配置文件
└── internal
    ├── config
    │   └── config.go              // 定义配置
    ├── handler
    │   ├── addhandler.go          // 实现addHandler
    │   ├── checkhandler.go        // 实现checkHandler
    │   └── routes.go              // 定义路由处理
    ├── logic
    │   ├── addlogic.go            // 实现AddLogic
    │   └── checklogic.go          // 实现CheckLogic
    ├── svc
    │   └── servicecontext.go      // 定义ServiceContext
    └── types
        └── types.go               // 定义请求、返回结构体

注: 如果修改了API文档, 可再次执行上面的指令, 重新生成API代码, 不影响未更新部位的代码

6.2.3 在API目录下启动服务

默认端口是8888, 可在etc/bookstore.yaml中修改
启动服务指令如下:

go run bookstore.go -f etc/bookstore-api.yaml

6.2.4 测试API Gateway服务

执行如下指令:

curl -i “http://localhost:8888/check?book=go-zero”

返回:

HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 03 Sep 2020 06:46:18 GMT
Content-Length: 25

{“found”:false,“price”:0}

6.3 创建 add rpc服务

6.3.1 生成add.proto文件

  1. 在bookstore下创建rpc/add目录
  2. 在rpc/add目录下编写add.proto文件
  3. 可以通过以下命令生成
    $ goctl rpc -o add.proto
  4. 修文文件内容如下
syntax = "proto3";

package add;

option go_package = "./add";

message addReq {
    string book = 1;
    int64 price = 2;
}

message addResp {
    bool ok = 1;
}

service adder {
    rpc add(addReq) returns(addResp);
}

6.3.2 生成rpc代码

在rpc/add目录下执行如下代码:

goctl rpc protoc add.proto --go_out=. --go-grpc_out=. --zrpc_out=.

生成的文件格式如下:

	rpc/add
	├── add                   // pb.go
	│   ├── add.pb.go
	│   └── add_grpc.pb.go
	├── add.go                // main函数入口
	├── add.proto             // proto源文件
	├── adder                 // rpc client call entry
	│   └── adder.go
	├── etc                   // yaml配置文件
	│   └── add.yaml
	└── internal              
	    ├── config            // yaml配置文件对应的结构体定义
	    │   └── config.go
	    ├── logic             // 业务逻辑
	    │   └── addlogic.go
	    ├── server            // rpc server
	    │   └── adderserver.go
	    └── svc               // 资源依赖
	        └── servicecontext.go

6.3.3 启动add rpc 服务

执行如下指令:

$ go run add.go -f etc/add.yaml

注: 如果修改了proto文件, 可重新生成rpc代码, 不会影响到未更新部分的代码

6.4 创建 check rpc 服务

6.4.1 生成 check.proto 文件

  1. 创建 rpc/check目录, 在rpc/check目录中生成check.proto文件
    可通过如下指令来生成:
    $ goctl rpc -o check.proto
  2. 修改check.proto文件
    修改后的check.proto文件如下:
syntax = "proto3";

package check;

option go_package = "./check";

message checkReq {
    string book = 1;
}

message checkResp {
    bool found = 1;
    int64 price = 2;
}

service checker {
    rpc check(checkReq) returns(checkResp);
}

6.4.2 使用goctl生成check rpc代码

指令如下:

goctl rpc protoc check.proto --go_out=. --go-grpc_out=. --zrpc_out=.

生成的目录结构如下:

rpc/check
├── check                     // pb.go
│   ├── check.pb.go
│   └── check_grpc.pb.go
├── check.go                  // main入口
├── check.proto               // proto源文件
├── checker                   // rpc client call entry
│   └── checker.go
├── etc                       // yaml配置文件
│   └── check.yaml
└── internal
    ├── config                // yaml配置文件对应的结构体定义
    │   └── config.go
    ├── logic                 // 业务逻辑
    │   └── checklogic.go
    ├── server                // rpc server
    │   └── checkerserver.go
    └── svc                   // 资源依赖
        └── servicecontext.go

6.4.3 启动 check rpc 服务

  1. 在etc/check.yaml中修改服务的端口为8081, 因为8080已经被add rpc服务占用
  2. 执行如下指令启动check服务
    $ go run check.go -f etc/check.yaml

6.5 修改API Gateway代码, 以调用 add/check rpc 服务

6.5.1 修改API Gateway的配置文件

在 api/etc/bookstore.yaml中增加如下内容:

Add:
  Etcd:
    Hosts:
      - localhost:2379
    Key: add.rpcCheck:
  Etcd:
    Hosts:
      - localhost:2379
    Key: check.rpc

注: 通过etcd自动去发现可用的add/check服务

6.5.2 修改API Gateway的logic配置文件

修改api/internal/config/config.go, 增加add/check 服务依赖, 修改如下:

type Config struct {
    rest.RestConf
    Add   zrpc.RpcClientConf     // 手动代码
    Check zrpc.RpcClientConf     // 手动代码
}

6.5.3 修改API Gateway的服务入口层

修改api/internal/svc/servicecontext.go文件, 如下:

type ServiceContext struct {
    Config  config.Config
    Adder   adder.Adder          // 手动代码
    Checker checker.Checker      // 手动代码
}

func NewServiceContext(c config.Config) *ServiceContext {
    return &ServiceContext{
        Config:  c,
        Adder:   adder.NewAdder(zrpc.MustNewClient(c.Add)),         // 手动代码
        Checker: checker.NewChecker(zrpc.MustNewClient(c.Check)),   // 手动代码
    }
}

注: 通过ServiceContext在不同业务逻辑之间传递依赖

6.5.4 修改API Gateway的业务逻辑层代码

  1. 修改api/internal/logic/addlogic.go里的Add方法, 如下:

     func (l *AddLogic) Add(req *types.AddReq) (resp *types.AddResp, err error) {
     	r, err := l.svcCtx.Adder.Add(l.ctx, &adder.AddReq{
     		Book:  req.Book,
     		Price: req.Price,
     	})
     	if err != nil {
     		return nil, err
     	}
     
     	return &types.AddResp{
     		Ok: r.Ok,
     	}, nil
     }
    

    注: 通过调用adder的Add方法实现添加图书到bookstore系统

  2. 修改 api/internal/logic/checklogic.go里的Check方法, 修改如下:

     func (l *CheckLogic) Check(req *types.CheckReq) (resp *types.CheckResp,err error) {
     	// 手动代码开始
     	r, err := l.svcCtx.Checker.Check(l.ctx, &checker.CheckReq{
     		Book: req.Book,
     	})
     	if err != nil {
     		logx.Error(err)
     		return &types.CheckResp{}, err
     	}
     
     	return &types.CheckResp{
     		Found: r.Found,
     		Price: r.Price,
     	}, nil
     	// 手动代码结束
     }
    

    注: 通过调用checker的Check方法实现从bookstore系统中查询图书的价格

6.6 定义数据库表schema, 并生成CRUD+cache代码

6.6.1 创建book.sql文件

  1. 在bookstore下创建 rpc/model目录

  2. 在rpc/model目录下创建book表的schema, 如下:

     CREATE TABLE `book`
     (
       `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
       `book` varchar(255) NOT NULL COMMENT 'book name',
       `price` int NOT NULL COMMENT 'book price',
       PRIMARY KEY(`id`),
       KEY `index_book` (`book`)
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
  3. 创建DB 和 table
    $ create database gozero;
    $ source book.sql;

6.6.2 使用goctl 生成 CRUD+cache 代码

  1. 使用如下指令来生成model层的代码, -c表示用redis cache:

    $ goctl model mysql ddl -c -src book.sql -dir .

    注: 也可以使用datasource命令代替ddl来指定数据库链接直接从schema生成

  2. 生成的目录结构如下:

     rpc/model
    ├── book.sql
    ├── bookstoremodel.go     // CRUD+cache代码
    └── vars.go               // 定义常量和变量
    

6.6.3 修改rpc代码, 以调用crud+cache

  1. 修改rpc/add/etc/add.yaml 和 rpc/check/etc/check.yaml, 增加如下内容:

     DataSource: root:@tcp(localhost:3306)/gozero 
     \# mysql链接地址,满足 $user:$password@tcp($ip:$port)/$db?$queries 格式即可
     Table: book
     Cache:
       - Host: localhost:6379
    

    可以使用多个redis作为cache, 支持redis 单点或者集群

  2. 修改 etc/add/internal/config/config.go 和 etc/check/internal/config/config.go, 如下:

     type Config struct {
         zrpc.RpcServerConf
         DataSource string             // 手动代码
         Cache      cache.CacheConf    // 手动代码
     }
    

    增加mysql 和 redis的配置

  3. 修改 rpc/add/internal/svc/servicecontext.go 和 rpc/check/internal/svc/servicecontext.go, 如下:

     type ServiceContext struct {
         c     config.Config
         Model model.BookModel   // 手动代码
     }
     func NewServiceContext(c config.Config) *ServiceContext {
         return &ServiceContext{
             c:             c,
             Model: model.NewBookModel(sqlx.NewMysql(c.DataSource), c.Cache), // 手动代码
         }
     }
    
  4. 修改rpc/add/internal/logic/addlogic.go, 如下:

     func (l *AddLogic) Add(in *add.AddReq) (*add.AddResp, error) {
         // 手动代码开始
         _, err := l.svcCtx.Model.Insert(l.ctx,&model.Book{
             Book:  in.Book,
             Price: in.Price,
         })
         if err != nil {
             return nil, err
         }
     
         return &add.AddResp{
             Ok: true,
         }, nil
         // 手动代码结束
     }
    
  5. 修改rpc/check/internal/logic/checklogic.go, 如下:

     func (l *CheckLogic) Check(in *check.CheckReq) (*check.CheckResp, error) {
         // 手动代码开始
         resp, err := l.svcCtx.Model.FindOne(l.ctx,in.Book)
         if err != nil {
             return nil,err
         }
     
         return &check.CheckResp{
             Found: true,
             Price: resp.Price,
         }, nil
         // 手动代码结束
     }
    

6.7 完整示例调用

  1. add api调用

     curl -i “http://localhost:8888/add?book=go-zero&price=10”
     
     返回如下:
     HTTP/1.1 200 OK
     Content-Type: application/json
     Date: Thu, 03 Sep 2020 09:42:13 GMT
     Content-Length: 11
     
     {"ok":true}
    
  2. check api调用

     curl -i “http://localhost:8888/check?book=go-zero”
     
     返回如下:
     HTTP/1.1 200 OK
     Content-Type: application/json
     Date: Thu, 03 Sep 2020 09:47:34 GMT
     Content-Length: 25
     
     {"found":true,"price":10}
    

注: 至此, 快速搭建服务演示结束

7. 以下是一个自己根据bookstore改的项目

项目包含 usercenter 和 bookstore两个完整的微服务, 并对response和error进行了封装, 增加了全局错误拦截器, 想要了解的小伙伴可参考Github go-zero-bookstore 项目

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值