golang微服务之go-zero零基础实战
1. 环境准备
- mysql
提供rpc服务接口后端交互存储 - etcd
提供rpc服务注册与发现
2. 文件结构
rpc服务接口:
1. 用户登录
2. 用户创建
3. 查询用户信息
api服务接口:
1. 用户登录
2. 用户创建
3. 查询用户信息
3. 搭建步骤
1. 搭建rpc服务
- 创建rpc目录
- 在rpc目录下创建proto文件,user.proto
syntax = "proto3";
package user;
option go_package="./user";
message UserInfoRequest{
uint32 id = 1;
}
message UserInfoResponse{
uint32 id = 1;
string username = 2;
bool gender = 3;
}
message UserCreateRequest{
string username = 1;
string password = 2;
bool gender = 3;
}
message UserCreateResponse{
uint32 id = 1;
string err = 2;
}
message UserLoginRequest{
string username = 1;
string password = 2;
}
message UserLoginResponse{
bool success = 1;
uint32 id = 2;
}
service user{
rpc UserInfo(UserInfoRequest)returns(UserInfoResponse);
rpc UserCreate(UserCreateRequest)returns(UserCreateResponse);
rpc UserLogin(UserLoginRequest)returns(UserLoginResponse);
}
// goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
此处,rpc定义 用户登录、用户创建、获取用户信息 ,三个接口以及请求和响应结构体
使用goctl生成代码
goctl rpc protoc user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.
- 修改rpc/etc/user.yaml,配置etcd服务器地址、key、mysql连接地址
Name: user.rpc
ListenOn: 0.0.0.0:8080
Etcd:
Hosts:
- 10.100.11.111:2379
Key: user.rpc
Mysql:
DataSource: root:123456@tcp(10.100.11.111:3306)/db3?parseTime=true
- 修改rpc/internal/config/config.go,添加mysql配置项解析
type Config struct {
zrpc.RpcServerConf
Mysql struct{
DataSource string
}
}
- 修改rpc/internal/svc/servicecontext.go,为svc添加DB服务依赖
type ServiceContext struct {
Config config.Config
DB *gorm.DB
}
func NewServiceContext(c config.Config) *ServiceContext {
db := initgorm.InitGorm(c.Mysql.DataSource)
return &ServiceContext{
Config: c,
DB: db,
}
}
init_gorm:
func InitGorm(MysqlDataSource string) *gorm.DB{
db, err := gorm.Open(mysql.Open(MysqlDataSource), &gorm.Config{})
if err != nil {
panic("connect fail")
}else{
fmt.Println("connect success")
}
db.AutoMigrate(&models.UserModel{})
return db
}
- 创建用户model,供数据库使用,修改rpc/models/user_model.go
type UserModel struct{
gorm.Model
Username string `gorm:"size:32" json:"user"`
Password string `gorm:"size:64" json:"password"`
Gender bool `gorm:"size:64" json:"gender"`
}
- 编写logic,用户登录、创建、获取信息的逻辑部分,数据库交互
用户登录logic:
var userInfo models.UserModel
err := l.svcCtx.DB.Where("username = ? and password = ?", in.Username, in.Password).First(&userInfo).Error
if err != nil {
return &user.UserLoginResponse{
Success: false,
}, err
}
return &user.UserLoginResponse{
Success: true,
Id: uint32(userInfo.ID),
}, nil
添加用户logic:
var model models.UserModel
pd = new(user.UserCreateResponse)
err = l.svcCtx.DB.Take(&model, "username = ?", in.Username).Error
if err == nil {
pd.Err = "user exist"
return
}
model = models.UserModel{
Username: in.Username,
Password: in.Password,
Gender: in.Gender,
}
err = l.svcCtx.DB.Create(&model).Error
if err != nil {
logx.Error(err)
pd.Err = err.Error()
err = nil
return
}
fmt.Println(model.ID)
pd.Id = uint32(model.ID)
return &user.UserCreateResponse{}, nil
查询用户logic
var userInfo models.UserModel
err := l.svcCtx.DB.Take(&userInfo, in.Id).Error
if err != nil {
return nil, errors.New("user not exist")
}
return &user.UserInfoResponse{
Id: uint32(userInfo.ID),
Username: userInfo.Username,
Gender: userInfo.Gender,
}, nil
至此,rpc服务三个接口编写完成,可通过apifox调用rpc接口验证
2. api服务搭建
- 新建api目录、
- 新建user.api,api文件,编辑三个接口的定义、请求及响应结构体
type UserCreateRequest {
Username string `json:"username"`
Password string `json:"password"`
Gender bool `json:"gender"`
}
type UserInfoRequest {
Id uint `path:"id"`
}
type UserInfoResponse {
Id uint `json:"id"`
Username string `json:"username"`
Gender bool `json:"gender"`
}
@server (
prefix: /api/users
jwt: Auth
)
service users {
@handler userCreate
post / (UserCreateRequest) returns (string)
@handler userInfo
get /info/:id (UserInfoRequest) returns (UserInfoResponse)
}
type LoginRequest {
Username string `json:"username"`
Password string `json:"password"`
}
@server (
prefix: /api/users
)
service users {
@handler login
post /login (LoginRequest) returns (string)
}
// goctl api go -api user.api -dir .
-
生成api服务文件
goctl api go -api user.api -dir .
-
修改api/etc/users.yaml,配置jwt auth及rpc服务地址、key相关配置
Name: users
Host: 0.0.0.0
Port: 8888
Auth:
AccessSecret: a123456aaa
AccessExpire: 86400
UserRpc:
Etcd:
Hosts:
- 10.100.13.120:2379
Key: user.rpc
- 修改api/internal/config/config.yaml,添加userRpc及jwtAuth相关配置解析
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
Auth struct{
AccessSecret string
AccessExpire int64
}
}
- 修改api/internal/svc/servicecontext.go,为svc添加rpc服务依赖
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)),
}
}
- 编写logic,调用rpc服务接口
用户登录:
res, err := l.svcCtx.UserRpc.UserLogin(l.ctx, &userclient.UserLoginRequest{
Username: req.Username,
Password: req.Password,
})
if err != nil {
return "", errors.New("login fail")
}
token, err := jwts.GenToken(&jwts.JwtPayLoad{
UserID: uint(res.Id),
Username: req.Username,
Role: 1,
}, l.svcCtx.Config.Auth.AccessSecret, l.svcCtx.Config.Auth.AccessExpire)
if err != nil {
return "", errors.New("login fail")
}
return token, nil
创建用户:
response, err := l.svcCtx.UserRpc.UserCreate(l.ctx, &user.UserCreateRequest{
Username: req.Username,
Password: req.Password,
})
if err != nil {
return "", err
}
if response.Err!= ""{
return "", errors.New(response.Err)
}
return
查询用户:
response, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &user.UserInfoRequest{
Id: uint32(req.Id),
})
if err != nil {
return nil, err
}
return &types.UserInfoResponse{
Id: uint(response.Id),
Username: response.Username,
Gender: response.Gender,
}, nil
至此,api服务接口搭建完成
4. 启动服务
rpc:
go run user.go
api:
go run users.go