一、go-zero简介及如何学go-zero

1.go-zero官方文档

http://go-zero.dev/

2.go-zero微服务框架入门教程

作者:Mikael

https://www.bilibili.com/medialist/play/389552232?from=space&business=space_series&business_id=2122723

3.go-zero最佳实践

go-zero-looklook

项目地址:

https://github.com/Mikaelemmmm/go-zero-looklook

4.学习资料

  1. 公众号:微服务器实践
  2. go-zero-expmple: https://github.com/zeromicro/zero-examples
  3. zero-contrib: https://github.com/zeromicro/zero-contrib
  4. 微信社区群
  5. go-zero-issue: https://github.com/zeromicro/go-zero/issues

二、go-zero环境搭建

1.GO环境和Gopath的配置

linux配置

export GOROOT="/home/haima/local/go" #go的源码包
export GOPATH=/media/haima/34E401CC64DD0E282/site/go  #工作地址路径
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

更多详细参考以下连接:
https://www.cnblogs.com/haima/p/12057933.html

1.需要安装以下环境和依赖

2.goctl安装

Go 1.16 及以后版本

GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
查看版本
haima@haima-PC:~/Desktop$ goctl -v
goctl version 1.3.5 linux/amd64

3.其它依赖安装

如果goctl安装的版本是>=1.3.3版本的,执行以命令就可以自动安装protoc,protoc-gen-go,protoc-gen-go-grpc三个依赖

haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ goctl -v
goctl version 1.3.3 linux/amd64
haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ goctl env check -i -f
[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!

查看已经安装的环境

haima@haima-PC:~/Desktop$ protoc --version
libprotoc 3.19.4

haima@haima-PC:~/Desktop$ protoc-gen-go --version
protoc-gen-go v1.28.0

haima@haima-PC:~/Desktop$ protoc-gen-go-grpc --version
protoc-gen-go-grpc 1.2.0

文件会安装到gopath目录里

goctl版本小于 1.3.3 参考以下文章安装

https://www.cnblogs.com/haima/p/15859782.html

三、go-zero杀手锏goctl详细使用

1.官方文档:

http://go-zero.dev/cn/goctl.html

goctl -help

2.开发准备工作

  1. ide插件市场里安装goctl插件

  2. 安装protobuf插件

  3. 配置命令别名

vim ~/.bashrc

alias apigen="goctl api go -api *.api -dir ../  --style=goZero"
alias rpcgen="goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../  --zrpc_out=../ --style=goZero"

source ~/.bashrc

3.编写API代码

  1. 新建.api文件
  • 手动创建
    zero-demo/user-api/api/user.api

  • 命令行自动创建
    mkdir zero-demo && cd zero-demo/
    goctl api new user

syntax = "v1"

info(
	author: "user-api"
	date:   "2022-03-26"
	desc:   "api语法示例及语法说明"
)

type UserInfoRequest {
	UserId int64 `json:"userId"`
}

type UserInfoResponse {
	UserId   int64  `json:"userId"`
	Nickname string `json:"nickname"`
}

service user-api{
	@doc "获取用户信息"
	@handler userInfo
	post /user/info (UserInfoRequest) returns (UserInfoResponse)
}
  1. 进入api目标
    cd user-api/api/

  2. 生成api

方法一:

用原始命令:

goctl api go -api *.api -dir ../ --style=goZero

方法二:

用别名:

apigen

命令说明:

-dir 代码输出目录
--api 指定api源文件
--style 指定生成代码文件的文件名称风格,详情见文件名称命名style说明

会在user-api目录里生成代码

  1. 目标结构:
zero-demo/user-api/api$ cd ..
zero-demo/user-api$ cd ..
zero-demo$ tree
.
├── go.mod
└── user-api
    ├── api
    │   └── user.api
    ├── etc
    │   └── user-api.yaml
    ├── internal
    │   ├── config
    │   │   └── config.go
    │   ├── handler
    │   │   ├── routes.go
    │   │   └── userInfoHandler.go
    │   ├── logic
    │   │   └── userInfoLogic.go
    │   ├── svc
    │   │   └── serviceContext.go
    │   └── types
    │       └── types.go
    └── user.go
  1. 下载依赖

zero-demo$ go mod tidy

  1. 生成Dockerfile文件

zero-demo/user-api$ goctl docker --go user.go

会生成Dockerfile文件

zero-demo/user-api/Dockerfile

  1. 生成k8s配置文件
    go-zero/zero-demo/user-api$ goctl kube deploy -name user-api -namespace go-zero-looklook -image user-api:v1.0 -o user-api.yml -port 1001 -nodePort 31001

会生成配置文件

zero-demo/user-api/user-api.yml

4.编写RPC代码

  1. 新建user.proto

zero-demo/user-rpc/pb/user.proto

写入以下内容

syntax = "proto3";

option go_package = "./pb";

package pb;


//model

message GetUserInfoReq {
  int64  id = 1;
}
message GetUserInfoResp {
   int64  id = 1;
   string nickname = 2;
}


//service
service usercenter {
  rpc GetUserInfo(GetUserInfoReq) returns(GetUserInfoResp);
}

  1. 生成代码

进入目录:
cd zero-demo/user-rpc/pb

执行命令:

windows下*号改成具体的文件名,如user.proto

zero-demo/user-rpc/pb$ goctl rpc protoc *.proto --go_out=../ --go-grpc_out=../  --zrpc_out=../ --style=goZero

或者用别名:

zero-demo/user-rpc/pb$ rpcgen

会在user-rpc目录里生成代码

  1. 查看生成目录
haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ tree
.
├── go.mod
├── go.sum
└── user-rpc
    ├── etc
    │   └── user.yaml
    ├── internal
    │   ├── config
    │   │   └── config.go
    │   ├── logic
    │   │   └── getUserInfoLogic.go
    │   ├── server
    │   │   └── usercenterServer.go
    │   └── svc
    │       └── serviceContext.go
    ├── pb
    │   ├── user_grpc.pb.go
    │   ├── user.pb.go
    │   └── user.proto
    ├── usercenter
    │   └── usercenter.go
    └── user.go

  1. 下载依赖
zero-demo$ go mod tidy

5.编写Model代码

  1. 编写脚本文件genModel.sh

go-zero/zero-demo/genModel.sh

#!/usr/bin/env bash

# 使用方法: 第一个参数为数据库名 第二个参数为表名
# ./genModel.sh mall user
# ./genModel.sh usercenter user_auth
# 再将./genModel下的文件剪切到对应服务的model目录里面,记得改package


#生成的表名
tables=$2
#表生成的genmodel目录
modeldir=./genModel

# 数据库配置
host=127.0.0.1
port=3306
#dbname=looklook_$1
dbname=$1
username=root
passwd=123456


echo "开始创建库:$dbname 的表:$2"
# -cache=true 带缓存
#goctl model mysql datasource -url="${username}:${passwd}@tcp(${host}:${port})/${dbname}" -table="${tables}"  -dir="${modeldir}" -cache=true --style=goZero

# 不带缓存
goctl model mysql datasource -url="${username}:${passwd}@tcp(${host}:${port})/${dbname}" -table="${tables}"  -dir="${modeldir}" --style=goZero
  1. 生成代码

./genModel.sh

会生成目录
./genModel

  1. 查看生成代码
haima@haima-PC:/media/haima/34E401CC64DD0E282/site/go/src/haimait/learn/go-zero/zero-demo$ tree
.
├── genModel/
│	├── userModel_gen.go
│	├── userModel.go
│	└── vars.go

重复执行生成代码时,文件 userModel.go 和 vars.go 不会修改,自定义的代码可以写在这两个文件个文件中
如何生成带缓存的model,会根据主键和唯一索引作为key生成生成缓存。

如下面粟子:
goZeroDemoUserIdKey 和 goZeroDemoUserMobileKey即为缓存的key

func (m *defaultUserModel) Insert(ctx context.Context, data *User) (sql.Result, error) {
	goZeroDemoUserIdKey := fmt.Sprintf("%s%v", cacheGoZeroDemoUserIdPrefix, data.Id)
	goZeroDemoUserMobileKey := fmt.Sprintf("%s%v", cacheGoZeroDemoUserMobilePrefix, data.Mobile)
	ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
		query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userRowsExpectAutoSet)
		return conn.ExecCtx(ctx, query, data.Id, data.Name, data.Age, data.Gender, data.Mobile, data.Password, data.CreatedAt, data.UpdatedAt, data.DeletedAt)
	}, goZeroDemoUserIdKey, goZeroDemoUserMobileKey)
	return ret, err
}
  1. 下载依赖
zero-demo$ go mod tidy

原文笔记:
https://www.cnblogs.com/haima/p/16057786.html

五、API服务之API文档

1.生成API文档

根据user.api文件生成.md文档

执行命令:

go-zero-demo\user-api\api> goctl api doc --dir ./

会生成 go-zero-demo\user-api/api/user.md 文件

2.atServer关键key描述说明

修饰service时

路由组(group)和路由前缀(prefix)

参考文档:

http://go-zero.dev/cn/api-grammar.html

语法:

// service block
@server(
	group: user
	prefix: api/v1
)

例子:

syntax = "v1"

info(
	author: "user-api"
	date:   "2022-03-26"
	desc:   "api语法示例及语法说明"
)

type UserInfoRequest {
	UserId int64 `json:"userId"`
}

type UserInfoResponse {
	UserId   int64  `json:"userId"`
	Nickname string `json:"nickname"`
}
type UserUpdateRequest {
	UserId   int64  `json:"userId"`
	Nickname string `json:"nickname"`
}

type UserUpdateResponse {
	Flag bool `json:"flag"`
}

// 看这里 声名 路由组(group)和路由前缀(prefix)
// service block
@server(
	group: user
	prefix: api/v1
)

service user-api{
	@doc "获取用户信息"
	@handler userInfo
	post /user/info (UserInfoRequest) returns (UserInfoResponse)
	
	@doc "修改用户信息"
	@handler upDateUser
	post /user/update (UserUpdateRequest) returns (UserUpdateResponse)
}

执行生成命令:

go-zero-demo\user-api\api> goctl api go -api user.api -dir ../ --style=goZero

生成的路由:

// Code generated by goctl. DO NOT EDIT.
package handler

import (
	"net/http"

	user "go-zero-demo/user-api/internal/handler/user"
	"go-zero-demo/user-api/internal/svc"

	"github.com/zeromicro/go-zero/rest"
)

func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
	server.AddRoutes(
		[]rest.Route{
			{
				Method:  http.MethodPost,
				Path:    "/user/info",
				Handler: user.UserInfoHandler(serverCtx),
			},
			{
				Method:  http.MethodPost,
				Path:    "/user/update",
				Handler: user.UpDateUserHandler(serverCtx),
			},
		},
		rest.WithPrefix("/api/v1"), #生成的路由前缀
	)
}

生成文件

go-zero-demo\user-api\internal\handler\user\upDateUserHandler.go

go-zero-demo\user-api\internal\handler\user\userInfoHandler.go

go-zero-demo\user-api\internal\logic\user\upDateUserLogic.go

go-zero-demo\user-api\internal\logic\user\userInfoLogic.go

├── user-api
│   ├── api
│   │   └── user.api
│   ├── Dockerfile
│   ├── etc
│   │   └── user-api.yaml
│   ├── internal
│   │   ├── config
│   │   │   └── config.go
│   │   ├── handler
│   │   │   ├── user
│   │   │   │   ├── upDateUserHandler.go
│   │   │   │   └── userInfoHandler.go
│   │   │   ├── routes.go
│   │   ├── logic
│   │   │   ├── user
│   │   │   │   ├── upDateUserLogic.go
│   │   │   └── └── userInfoLogic.go
│   │   ├── svc
│   │   │   └── serviceContext.go
│   │   └── types
│   │       └── types.go
│   ├── user-api.yml
│   └── user.go

访问路由:

/api/v1/user/info
/api/v1/user/update