go-zero實戰


文檔地址
官方examples
前提:
安裝 protoc, protoc-gen-go, goctl

api

  1. clone 項目或者 生成目錄, init go mod
mkdir zeroService && cd zeroService && go mod init zeroService
  1. 限制grpc版本, 打開go.mod 加入replace google.golang.org/grpc => google.golang.org/grpc v1.29.1
module zeroService

go 1.15

replace google.golang.org/grpc => google.golang.org/grpc v1.29.1
  1. 創建api和rpc目錄
mkdir rpc && mkdir api
  1. 創建api文檔, api語法
cd api
vim user.api

type HttpResponse {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type (
	RegisterReq {
		UserName string `form:"username"`
		Pwd      string `form:"pwd"`
		NickName string `form:"nickname"`
		Age      int    `form:"age"`
	}
	RegisterRsp {
		Rid int `json:"rid"`
	}
)

type (
	InfoReq {
		Rid int `form:"rid"`
	}
	InfoRsp {
		Rid      int    `json:"rid"`
		UserName string `json:"username"`
		Pwd      string `json:"pwd"`
		NickName string `json:"nickname"`
		Age      int    `json:"age"`
	}
)

// 用戶相關api
service user-api{
	@doc "用戶注冊"
	@handler register
	post /register (RegisterReq) returns (HttpResponse)
	
	@doc "獲取用戶信息"
	@handler info
	get /info (InfoReq) returns (HttpResponse)
}


  1. 生成項目
goctl api go -api user.api -dir .


./
├── api
│   ├── etc
│   │   └── user-api.yaml //配置文件
│   ├── internal
│   │   ├── config
│   │   │   └── config.go
│   │   ├── handler
│   │   │   ├── infohandler.go
│   │   │   ├── registerhandler.go
│   │   │   └── routes.go
│   │   ├── logic
│   │   │   ├── infologic.go //業務邏輯
│   │   │   └── registerlogic.go //業務邏輯
│   │   ├── svc
│   │   │   └── servicecontext.go
│   │   └── types
│   │       └── types.go
│   ├── user.api
│   └── user.go
├── go.mod
└── rpc
  1. 修改配置文件
vim etc/user-api.yaml

Name: user-api
Host: 0.0.0.0
Port: 48888
DataSource: zmwb:realize2012@tcp(127.0.0.1:3306)/zero
Cache:
  - Host: 127.0.0.1:6379
Log:
  Model: console
  
vim internal/config/config.go

//加入下面兩個配置聲明
type Config struct {
	rest.RestConf
	DataSource string //新加
	Cache      cache.CacheConf //新加
}
  1. 設計數據庫
CREATE TABLE `userinfo` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(255) not null,
`nickname` varchar(255) not null,
`age` int(10) not null default 0,
`pwd` varchar(255) not null,
`created_at` datetime NOT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
key `n_idx` (`username`),
key `q_idx` (`age`, `nickname`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


//生成model文件, 目錄在api/model里
goctl model mysql datasource -url="zmwb:realize2012@tcp(127.0.0.1:3306)/zero" -table="*"  -dir="./model"

//修改服務上下文, 注入model
vim internal/svc/servicecontext.go


type ServiceContext struct {
	Config config.Config
	Model  model.UserinfoModel //新加
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		Model:  model.NewUserinfoModel(sqlx.NewMysql(c.DataSource)), //新加
	}
}

  1. 實現業務邏輯, 兩個接口, 用這種方式實現info接口, 另一個接口后面用rpc方式實現
vim internal/logic/infologic.go

func (l *InfoLogic) Info(req types.InfoReq) (*types.HttpResponse, error) {
	// 加入實現邏輯
	userinfo, err := l.svcCtx.Model.FindOne(int64(req.Rid))
	rsp := types.HttpResponse{}
	if err != nil {
		rsp.Code = 2
		rsp.Msg = "not found"
		return &rsp, err
	}
	rsp.Data = types.InfoRsp{
		Rid:      int(userinfo.Id),
		UserName: userinfo.Username,
		NickName: userinfo.Nickname,
		Age:      int(userinfo.Age),
	}
	return &rsp, nil
}

  1. 啟動服務
go run user.go

//進行接口測試
curl -v http://127.0.0.1:48888/info\?rid\=1

rpc

  1. 編寫pb文件
cd ../rpc
vim userService.proto


syntax = "proto3";

package userService;


message RegisterRequest {
    string username = 1;
    string nickname = 2;
    string pwd = 3;
    int64  age = 4;
}

message RegisterResponse {
    int64 rid = 1;
}

service UserService {
    //注冊
    rpc Register (RegisterRequest) returns (RegisterResponse);

}

  1. 根據pb文件生成rpc代碼
goctl rpc proto -src userService.proto  -dir .

//執行后項目結構
./
├── api
│   ├── etc
│   │   └── user-api.yaml
│   ├── internal
│   │   ├── config
│   │   │   └── config.go
│   │   ├── handler
│   │   │   ├── infohandler.go
│   │   │   ├── registerhandler.go
│   │   │   └── routes.go
│   │   ├── logic
│   │   │   ├── infologic.go
│   │   │   └── registerlogic.go
│   │   ├── svc
│   │   │   └── servicecontext.go
│   │   ├── table.sql
│   │   └── types
│   │       └── types.go
│   ├── model
│   │   ├── userinfomodel.go
│   │   └── vars.go
│   ├── user.api
│   └── user.go
├── go.mod
├── go.sum
└── rpc
    ├── etc
    │   └── userservice.yaml
    ├── internal
    │   ├── config
    │   │   └── config.go
    │   ├── logic
    │   │   └── registerlogic.go
    │   ├── server
    │   │   └── userserviceserver.go
    │   └── svc
    │       └── servicecontext.go
    ├── userService
    │   └── userService.pb.go
    ├── userService.proto
    ├── userservice.go
    └── userserviceclient
        └── userservice.go
  1. 修改配置文件
vim etc/userservice.yaml

Name: userservice.rpc
ListenOn: 127.0.0.1:48080
Etcd:
  Hosts:
  - 127.0.0.1:2379 //可以指向自己部署的etcd, 用於服務發現
  Key: userservice.rpc
DataSource: zmwb:realize2012@tcp(127.0.0.1:3306)/zero
Cache:
  - Host: 127.0.0.1:6379
Log:
  Model: console

  
vim internal/config/config.go

//加入下面兩個配置聲明
type Config struct {
	zrpc.RpcServerConf
	DataSource string          //新加
	Cache      cache.CacheConf //新加
}
  1. 注入model等
//修改服務上下文, 注入model
vim internal/svc/servicecontext.go


type ServiceContext struct {
	Config config.Config
	Model  model.UserinfoModel //新加
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		Model:  model.NewUserinfoModel(sqlx.NewMysql(c.DataSource)), //新加
	}
}

  1. 實現業務邏輯
vim internal/logic/registerlogic.go

// 注冊
func (l *RegisterLogic) Register(in *userService.RegisterRequest) (*userService.RegisterResponse, error) {
	user := model.Userinfo{
		Username: in.Username,
		Nickname: in.Nickname,
		Pwd: in.Pwd,
		Age: in.Age,
	}
	res, err := l.svcCtx.Model.Insert(user)
	if err != nil {
		return nil, err
	}
	rid, err := res.LastInsertId()
	if err != nil {
		return nil, err
	}
	return &userService.RegisterResponse{Rid: rid}, nil
}

  1. api 中注冊rpc客戶端
cd ../api

vim etc/user-api.yaml
//加入以下幾行服務發現配置
Rpc:
  Etcd:
    Hosts:
    - 127.0.0.1:2379
    Key: userservice.rpc
	

vim internal/config/config.go 
type Config struct {
	rest.RestConf
	DataSource string
	Cache      cache.CacheConf
	Rpc        zrpc.RpcClientConf //新加
}

vim internal/svc/servicecontext.go

type ServiceContext struct {
	Config         config.Config
	Model          model.UserinfoModel
	UserServiceRpc userserviceclient.UserService //新加
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config:         c,
		Model:          model.NewUserinfoModel(sqlx.NewMysql(c.DataSource)),
		UserServiceRpc: userserviceclient.NewUserService(zrpc.MustNewClient(c.Rpc)), //新加
	}
}

  1. api 中實現register邏輯
vim internal/logic/registerlogic.go 

func (l *RegisterLogic) Register(req types.RegisterReq) (*types.HttpResponse, error) {

	in := &userService.RegisterRequest{
		Username: req.UserName,
		Nickname: req.NickName,
		Pwd:      req.Pwd,
		Age:      int64(req.Age),
	}
	regRsp, err := l.svcCtx.UserServiceRpc.Register(l.ctx, in)
	if err != nil {
		return nil, err
	}
	rsp := types.HttpResponse{}

	rsp.Data = types.RegisterRsp{
		Rid: int(regRsp.Rid),
	}
	return &rsp, nil
}

  1. 啟動api 和 rpc 服務
go run user.go &
go run userservice.go &

//進行接口測試
  1. docker 部署
goctl docker -go rpc/userService.go -port 48080
goctl docker -go api.user.go -port 48888
//會在兩個目錄中生成兩個dockerfile
//build 兩個鏡像
docker build -t user.service:v1 
docker build -t user.api:v1 .
//build 失敗, 看Dockerfile發現很多目錄寫死, 可能是要固定的機器上把目錄生成好, 才能build成功

//啟動兩個容器

總結

  1. goctl功能很好用
  2. 部分細節比較固定, 比如, mysql的time.Time有些情況不行, 大部分是ok, goctl docker功能參數太少了, 如果要使用的話可能需要改一改
  3. 看介紹, goctl model生成如果配置了緩存的話, 會自動緩存很多數據, 減輕數據庫壓力, 這一塊算是個特色


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM