Administrator
发布于 2022-08-07 / 917 阅读 / 0 评论 / 0 点赞

gozero 基础使用

微服务相关知识

微服务架构总结
go+protobuf+grpc+consul简单的服务发现模型
GO-zero doc

网关创建

  1. 创建网关目录go-zero-demo\api\user
  2. 创建网关文件user.api
syntax = "v2"

info(
   author: "tutu"
   date:   "2022-08-23"
   desc:   "用户服务"
)

type (
   // 登录
   LoginReq {
      Username string `json:"username"`
      Password string `json:"password"`
      Code     int    `json:"code"`
   }
   LoginRes {
      Uid      int64  `json:"uid"`
      Nickname string `json:"nickname"`
      Sexy     int    `json:"sexy"`
      Address  string `json:"address"`
   }
   // 获取用户信息
   UserInfoReq {
      Uid int64 `form:"uid"`
   }
   UserInfoRes {
      Uid         int64   `json:"uid"`
      Nickname    string  `json:"nickname"`
      Sexy        int     `json:"sexy"`
      Address     string  `json:"address"`
      Email       string  `json:"email"`
      LastRuntime string  `json:"last_runtime"`
      LastRunIp   string  `json:"last_run_ip"`
      Balance     float32 `json:"balance"`
   }
)

service user {
   
   @doc "登录"
   @handler login
   post /user/login (LoginReq) returns (LoginRes)

   @doc "获取用户信息"
   @handler getUserInfo
   get /user/userinfo (UserInfoReq) returns (UserInfoRes)
}
  1. 生成文件
goctl api go -api ./user.api -dir ./ --style=goZero

clipboard

  1. 生成markdown文档
goctl api doc --dir ./

image-1665557144762

rpc创建和使用

  1. 创建rpc文件路径:go-zero-demo\rpc\user\user.proto
  2. 编写proto文件内容
syntax = "proto3";

package user;

option go_package = "./user_rpc";

// 通用消息返回
message Echo {
  int32 code = 1;
}

message LoginReq {
  string username = 1;
  string password = 2;
}

message Userinfo {
  int64 uid = 1;
  string username = 2;
  string password = 3;
  string nickname = 4;
  int32 gender = 5;
  string address = 6;
  string email = 7;
  string last_runtime = 8;
  string last_run_ip = 9;
  float balance = 10;
}

message IdReq {
  int64 uid = 1;
}

message ListReq {
  int32 page = 1;
  int32 page_size = 2;
}

message ListRes {
  repeated int32 Userinfo = 1;
}

service User {
  rpc creatAccount(Userinfo) returns(Echo);
  rpc updateAccount(Userinfo) returns(Echo);
  rpc deleteAccount(IdReq) returns(Echo);
  rpc getAccount(LoginReq) returns(Userinfo);
  rpc listAccount(ListReq) returns(ListRes);
}
  1. 生成文件
goctl rpc protoc .\user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=.

image-1665557253845

  1. 连接使用Rpc,在go-zero-demo\api\user\etc\user.yaml配置中添加服务发现地址和对应的key
RpcCli:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
    Key: user.rpc
  1. api配置中添加rpc服务的客户端go-zero-demo\api\user\internal\config\config.go
RpcCli zrpc.RpcClientConf
  1. api service 添加Rpc调用
package svc

import (
   "github.com/zeromicro/go-zero/zrpc"
   "go-zero-demo/api/user/internal/config"
   // 使用proto
   userRpc "go-zero-demo/rpc/user/user"
)

type ServiceContext struct {
   Config config.Config
   // 对应rpc 包连接
   UserRpc userRpc.User
}

func NewServiceContext(c config.Config) *ServiceContext {
   return &ServiceContext{
      Config: c,
      // 获取客户端
      UserRpc: userRpc.NewUser(zrpc.MustNewClient(c.RpcCli)),
   }
}
  1. api 中Rpc调用方法示例
func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginRes, err error) {

   if req.Code < 0{
      err = errors.New("验证码错误")
      return
   }

   userinfo, err := l.svcCtx.UserRpc.GetAccount(l.ctx,&user.LoginReq{
      Username: req.Username,
      Password: req.Password,
   })

   return &types.LoginRes{
      Uid:      userinfo.Uid,
      Nickname: userinfo.Nickname,
      Gender:   int(userinfo.Gender),
      Address:  userinfo.Address,
   },err
}

数据库的使用

自动生成代码及使用

  1. 通过datasource连接生成model文件
// 不缓存
goctl model mysql datasource -url="root:123456@tcp(127.0.0.1:3306)/tutu" -table="user" -dir="./user"
// 需要缓存
goctl model mysql datasource -url="root:123456@tcp(127.0.0.1:3306)/tutu" -table="user" -dir="./user" -cache=true

重复执行生成代码时,文件 userModel.go 和 vars.go 不会修改,自定义的代码可以写在这两个文件个文件中

  1. 在rpc配置及配置文件中添加相关配置项
################## 文件 go-zero-demo\rpc\user\etc\user.yaml 中添加 #######################
DB:
  DataSource: root:123456@tcp(127.0.0.1:3306)/tutu?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
Cache:
  Host: 127.0.0.1:49153
  Pass: redispw
  ################################################################
  
  ################## 文件 go-zero-demo\rpc\user\internal\config\config.go 中添加 #######################
DB  struct{
   DataSource string
}
Cache  cache.CacheConf
  ################################################################
  1. 在服务依赖里面创建数据库资源句柄 go-zero-demo\rpc\user\internal\svc\servicecontext.go
  2. package svc
import (
   "github.com/zeromicro/go-zero/core/stores/sqlx"
   "go-zero-demo/rpc/user/internal/config"
   // 引入model
   userModel "go-zero-demo/model/user"
)

type ServiceContext struct {
   Config config.Config
   UserModel userModel.UserModel
}

func NewServiceContext(c config.Config) *ServiceContext {
   return &ServiceContext{
      Config: c,
      // 创建资源
      UserModel: userModel.NewUserModel(sqlx.NewMysql(c.DB.DataSource),c.Cache),
   }
}

  1. 调用model示例
func (l *GetAccountLogic) Test(in *user_rpc.LoginReq) (*user_rpc.Userinfo, error) {
   l.svcCtx.UserModel.Insert()
}

自定义model

  1. go-zero-demo\model\user\userModel.go文件修改
package user

import (
   "context"
   "github.com/Masterminds/squirrel"
   "github.com/zeromicro/go-zero/core/stores/cache"
   "github.com/zeromicro/go-zero/core/stores/sqlx"
)

var _ UserModel = (*customUserModel)(nil)

type (
   // UserModel is an interface to be customized, add more methods here,
   // and implement the added methods in customUserModel.
   UserModel interface {
      userModel
      // 定义接口方法
      Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
      RowBuilder() squirrel.SelectBuilder
      CountBuilder(field string) squirrel.SelectBuilder
      SumBuilder(field string) squirrel.SelectBuilder
      FindOneByQuery(ctx context.Context, rowBuilder squirrel.SelectBuilder) (*User, error)
   }

   customUserModel struct {
      *defaultUserModel
   }
)

// NewUserModel returns a model for the database table.
func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf) UserModel {
   return &customUserModel{
      defaultUserModel: newUserModel(conn, c),
   }
}

func (m *defaultUserModel) FindOneByQuery(ctx context.Context, rowBuilder squirrel.SelectBuilder) (*User, error) {

   query, values, err := rowBuilder.ToSql()
   if err != nil {
      return nil, err
   }

   var resp User
   // 不进行数据缓存
   err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
   return &resp,err
}

// export logic
func (m *defaultUserModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {

   return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
      return fn(ctx, session)
   })

}

// export logic
func (m *defaultUserModel) RowBuilder() squirrel.SelectBuilder {
   return squirrel.Select(userRows).From(m.table)
}

// export logic
func (m *defaultUserModel) CountBuilder(field string) squirrel.SelectBuilder {
   return squirrel.Select("COUNT(" + field + ")").From(m.table)
}

// export logic
func (m *defaultUserModel) SumBuilder(field string) squirrel.SelectBuilder {
   return squirrel.Select("IFNULL(SUM(" + field + "),0)").From(m.table)
}

  1. 在go-zero-demo\rpc\user\internal\logic\getaccountlogic.go 中调用model
func (l *GetAccountLogic) Login(in *user_rpc.LoginReq) (*user_rpc.Userinfo, error) {
   // 创建sql
   rowBuilder := l.svcCtx.UserModel.RowBuilder().Where("username =?",in.Username)
   one, err := l.svcCtx.UserModel.FindOneByQuery(l.ctx,rowBuilder)

   if err !=nil{
      return &user_rpc.Userinfo{},err
   }

   if one.Password.String != util.Md5ByString(in.Password) {
      err = errors.New("password fail")
      return &user_rpc.Userinfo{},err
   }

   return &user_rpc.Userinfo{
      Uid:      one.Uid,
      Username: one.Username,
      Nickname: one.Nickname,
      Gender: int32(one.Gender),
      Address:  one.Address.String,
      Email:    one.Email.String,
   }, nil
}

路由分组

@server(
    group: user
    prefix: user_api
)

检查路由go-zero-demo\api\user\internal\handler\routes.go下生成的代码就会增加路由分组

rest.WithPrefix(“/user_api”),