安装:
$ mkdir <project name> && cd <project name> # project name 为具体值
$ go mod init <module name> # module name 为具体值
$ go get -u github.com/zeromicro/go-zero@latest
常见问题
1. 设置了 GOPROXY 后,依赖还是拉不下来?
确认 GO111MODULE 是否开启
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
goctl 安装
概述
goctl 是 go-zero 的内置脚手架,是提升开发效率的一大利器,可以一键生成代码、文档、部署 k8s yaml、dockerfile 等。
文档:goctl 安装 | go-zero Documentation
这里只是安装完了,但是项目还没有正式开始生成
api demo 代码生成
代码生成
# 创建工作空间并进入该目录
$ mkdir -p ~/workspace/api && cd ~/workspace/api
# 执行指令生成 demo 服务
$ goctl api new demo
Done.
执行完指令后,会在当前目录下生成一个 demo 目录,该目录下包含了一个最小化的 HTTP 服务,我们来查看一下该服务的目录结构。
# 进入 demo 服务目录
$ cd ~/workspace/api/demo
# 查看文件列表
$ ls
demo.api demo.go etc go.mod internal
# 查看目录接口
$ tree
.
├── demo.api
├── demo.go
├── etc
│ └── demo-api.yaml
├── go.mod
└── internal
├── config
│ └── config.go
├── handler
│ ├── demohandler.go
│ └── routes.go
├── logic
│ └── demologic.go
├── svc
│ └── servicecontext.go
└── types
└── types.go
其中
启动:go run demo.go 或者 cd进入目录,然后go run .
定义路由
有.api文件,该文件可以自定义位置。
然后编辑器安装goctl。可以通过goctl生成路由信息
逻辑编写
logic/xxx.go
package logic
import (
"context"
"ginGoZeroProject/api/internal/svc"
"ginGoZeroProject/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type ApiLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewApiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ApiLogic {
return &ApiLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ApiLogic) Api(req *types.Request) (resp *types.Response, err error) {
// todo: add your logic here and delete this line 在这里编写具体逻辑
print(req.Name)
resp = &types.Response{Message: req.Name}
return resp, nil
}
RPC生成
# 创建工作空间并进入该目录
$ mkdir -p ~/workspace/rpc && cd ~/workspace/rpc
# 执行指令生成 demo 服务
$ goctl rpc new demo
Done.
文档:gRPC demo 代码生成 | go-zero Documentation
业务逻辑编写流程
1.在api项目/internal/config/config.go。其中。AdminRpcConfig为自定义变量名
2.在api/internal/svc/servicecontext.go
package svc
import (
"admin.go.bi.gamedatayilehudong.com/admin/internal/config"
"admin.go.bi.gamedatayilehudong.com/rpc/admin/adminclient"
"github.com/zeromicro/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
AdminRpc adminclient.Admin
}
func NewServiceContext(c config.Config) *ServiceContext {
adminRpc := zrpc.MustNewClient(c.AdminRpdConfig)
return &ServiceContext{
Config: c,
AdminRpc: adminclient.NewAdmin(adminRpc),
}
}
api调用rpc服务
1.api/etc/api-api.yaml 新增rpc地址
Name: api-api
Host: 0.0.0.0
Port: 8888
# 以下新增
AdminRPCConfig: # 管理RPC配置 文件目录在internal/config/config.go中
Target: dns:///127.0.0.1:8080 # RPC目标地址
2.在api的logic代码里面
通过svcCtx调用【api/internal/svc/servicecontext.go】定义的结构体,再调用rpc里面的方法
all, err := l.svcCtx.AdminRpc.Ping(l.ctx, &admin.Request{Ping: "ping"})
调用model
这里用gorm的操作
- 安装gorm
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
- 在根目录创建common,用来存储自动生成脚本,该目录在哪个项目都可以,主要是取决于哪个项目调用,其中,conn为链接脚本,gen为自动生成脚本。model为gen.go执行了之后自动生成文件
- conn.go代码
package conn
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
type DbConfig struct {
Database string
Username string
Pwd string
Host string
}
func NewDb(config DbConfig) {
dsn := fmt.Sprintf("%s:%s@(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
config.Username,
config.Pwd,
config.Host,
config.Database,
)
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Printf("conn db err:%s", err)
}
}
- gen.go代码
package main
import (
"flag"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gen"
"gorm.io/gorm"
)
var t string
func init() {
flag.StringVar(&t, "t", "", "database")
flag.Parse()
if t == "" {
panic("未選擇表")
}
}
func main() {
g := gen.NewGenerator(gen.Config{
OutPath: "../model",
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
})
database := "yile_xxxs"
dsn := fmt.Sprintf("xxx:xxxx@(xxxx:xxx)/%s?charset=utf8mb4&parseTime=True&loc=Local", database)
gormdb, _ := gorm.Open(mysql.Open(dsn))
g.UseDB(gormdb) // reuse your gorm db
g.GenerateModel(t)
g.Execute()
}
- 配置文件,就是.yaml文件
# 以下为新增配置。类似.env文件
DbConfig:
Database: "yile_xxx"
Username: "roxxx"
Pwd: "sdasxxx"
Host: "gz-xx.xxxcom:5555"
- 进到这个目录执行go run . -t 表名,就会自动生成表的结构体。就是model里面的数据
- config注册服务
- svc里面的context初始化db对象。这样就把db对象放到了全局里面
- 使用的时候需要.WithContext(l.ctx),以下是实例,其中,这里有个注意的点是,go的查找数据是把数据存储到结构体里面。并不是存储到接收的变量。所以要打印数据就是打印结构体的数据
func (l *PingLogic) Ping(in *user.Request) (*user.Response, error) {
var infos []model.BasicsUserInfo // 定义一个存储BasicsUserInfo结构的切片infos
first := conn.DB.WithContext(l.ctx).Find(&infos, []int{2106810, 2106811, 2106812}) // 在数据库中根据给定的id查找BasicsUserInfo记录,并将结果存储在infos中
if first.Error != nil { // 如果查找过程中出现错误
fmt.Printf("ERROR: %v\n", first.Error) // 打印错误信息
return nil, first.Error // 返回错误
}
for _, info := range infos { // 遍历infos切片中的每个记录
fmt.Printf("Retrieved user info: %+v\n", info) // 打印获取到的用户信息
}
return &user.Response{Pong: in.Ping}, nil // 返回带有Pong字段的user.Response结构和nil错误
}