go-zero,etcd,gorm完成一次简单的微服务操作

go-zero 是一个集成了各种工程实践的 web 和 rpc 框架,etcd 是一个开源的分布式键值存储系统,用于可靠地存储分布式系统中的关键数据
1.环境准备

#官方脚手架
go install github.com/zeromicro/go-zero/tools/goctl@latest 安装go-zero脚手架,根据配置文件自动生成配置文件
#protobuf 工具
goctl env check --install --verbose --force
#框架
go get -u github.com/zeromicro/go-zero@latest

2.rpc服务端

  • 编写proto配置文件user.proto文件
syntax = "proto3";
package user;

option go_package = "../proto/user";

service UserService {
  rpc GetUser (UserRequest) returns (Response) {}
  rpc AddUserInfo (UserInfo) returns (Response) {}
}

message UserInfo {
  string name = 1;
  string nickname = 2;
  int64  iphone = 3;
  string password = 4;
  int32  status = 5;
  bool   is_admin = 6;
}

message UserRequest {
  int64 id = 1;
}

message Response {
  int64 result = 1;
  bytes data = 2;
}
  • 通过goctl命令生成文件
    goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=../
  • 修改yaml配置文件,并添加mysql等配置信息
Name: user.rpc
ListenOn: 0.0.0.0:8080
Etcd:
  Hosts:
  - 127.0.0.1:2379
  Key: user.rpc


MySQLConf:
  Enable: true
  User: root
  Password: '123456'
  Host: 127.0.0.1
  Port: 3306
  Database: test
  CharSet: utf8
  ParseTime: true
  TimeZOne: Local
  AutoMigrate: true
  Gorm:
    TablePrefix: zero_
    SingularTable: true
    MaxOpenConns: 100
    MaxIdleConns: 5
    ConnMaxLifetime: 600
  • 修改配置config.go文件,添加mysql配置读取结构体
package config

import "github.com/zeromicro/go-zero/zrpc"

type Config struct {
	zrpc.RpcServerConf
	MySQLConf MySQLConf
}

// Mysql config
type MySQLConf struct {
	Host        string   `json:"" yaml:"Host"`
	Port        int64    `json:"" yaml:"Port"`
	User        string   `json:"" yaml:"User"`
	Password    string   `json:"" yaml:"Password"`
	Database    string   `json:"" yaml:"Database"`
	CharSet     string   `json:"" yaml:"CharSet"`
	TimeZone    string   `json:"" yaml:"TimeZone"`
	ParseTime   bool     `json:"" yaml:"ParseTime"`
	Enable      bool     `json:"" yaml:"Enable"` // use mysql or not
	AutoMigrate bool     `json:"" yaml:"AutoMigrate"`
	Gorm        GormConf `json:"" yaml:"Gorm"`
}

// gorm config
type GormConf struct {
	SingularTable   bool   `json:"" yaml:"SingularTable"` // 是否使用单数表名(默认复数),启用后,User结构体表将是user
	TablePrefix     string `json:"" yaml:"TablePrefix"`   // 表前缀
	MaxOpenConns    int    `json:"" yaml:"MaxOpenConns"`
	MaxIdleConns    int    `json:"" yaml:"MaxIdleConns"`
	ConnMaxLifetime int    `json:"" yaml:"ConnMaxLifetime"`
}

  • 修改userserviceserver.go文件
package svc

import (
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
	"study/go-zero-gorm/user-srv/internal/config"
	"study/go-zero-gorm/user-srv/models"
	"time"
)

type ServiceContext struct {
	Config   config.Config
	DBEngine *gorm.DB
}

func NewServiceContext(c config.Config) *ServiceContext {
	mysqlConf := c.MySQLConf
	var db *gorm.DB
	var err error
	if mysqlConf.Enable {
		db, err = creteDbClient(mysqlConf)
		if err != nil {
			db = nil
		}
	}

	return &ServiceContext{
		Config:   c,
		DBEngine: db,
	}
}

func creteDbClient(mysqlConf config.MySQLConf) (*gorm.DB, error) {
	datasource := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%t&loc=%s",
		mysqlConf.User,
		mysqlConf.Password,
		mysqlConf.Host,
		mysqlConf.Port,
		mysqlConf.Database,
		mysqlConf.CharSet,
		mysqlConf.ParseTime,
		mysqlConf.TimeZone)
	fmt.Printf(datasource)
	db, err := gorm.Open(mysql.Open(datasource), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   mysqlConf.Gorm.TablePrefix,   // such as: prefix_tableName
			SingularTable: mysqlConf.Gorm.SingularTable, // such as zero_user, not zero_users
		},
	})
	if err != nil {
		logx.Errorf("create mysql db failed, err: %v", err)
		return nil, err
	}

	// auto sync table structure, no need to create table
	err = db.AutoMigrate(&models.User{})
	if err != nil {
		logx.Errorf("automigrate table failed, err: %v", err)
	}

	logx.Info("init mysql client instance success.")

	sqlDB, err := db.DB()
	if err != nil {
		logx.Errorf("mysql set connection pool failed, err: %v.", err)
		return nil, err
	}
	sqlDB.SetMaxOpenConns(mysqlConf.Gorm.MaxOpenConns)
	sqlDB.SetMaxIdleConns(mysqlConf.Gorm.MaxIdleConns)
	sqlDB.SetConnMaxLifetime(time.Duration(mysqlConf.Gorm.ConnMaxLifetime) * time.Second)

	return db, nil
}
  • 业务代码的编写操作数据库,函数goctl已经生成了,只需要编写业务代码
func (l *AddUserInfoLogic) AddUserInfo(in *user.UserInfo) (*user.Response, error) {
	// todo: add your logic here and delete this line

	userInfo := models.User{
		Phone:    int(in.Iphone),
		Username: in.Name,
		NickName: in.Nickname,
		Password: in.Password,
		Status:   int8(in.Status),
		IsAdmin:  in.IsAdmin,
		BaseModel: models.BaseModel{
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
			DeletedAt: time.Now(),
		},
	}
	err := l.svcCtx.DBEngine.Table("zero_user").Create(&userInfo).Error
	if err != nil {
		return &user.Response{Result: 500}, err
	}
	return &user.Response{Result: 200}, nil
}

2.网关业务代码编写

  • 编写user.api文件
syntax = "v1"

type Request {
	ID int `path:"id"`
}

type Response {
	Message string `json:"message"`
}

type UserResponse {
	Message string `json:"message"`
	Data    string `json:"data"`
	Code    int    `json:"code"`
}

type UserRequest {
	Username string `json:"username"` // 用户名
	Nickname string `json:"nickname"` // 昵称
	Phone    int64  `json:"phone"` // 手机号
	Password string `json:"password"` // 密码
	Status   int8   `json:"status"` // 状态 1:正常 2:白名单 3:黑名单
	IsAdmin  bool   `json:"is_admin"`
}

service web-api {
	@handler UserInfoHandler
	get /user/:id (Request) returns (UserResponse)

	@handler UserAddHandler
	post /user/add (UserRequest) returns (Response)
}
  • 通过goctl命令将api文件生成代码
    goctl api go -api user.api -dir ../
  • 修改web-api.yaml文件,将rpc服务添加到web-api.yaml文件中
Name: web-api
Host: 0.0.0.0
Port: 8888

UserRpcConf:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
    Key: user.rpc
  • 修改config.go配置文件
package config

import (
	"github.com/zeromicro/go-zero/rest"
	"github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
	rest.RestConf
	UserRpcConf zrpc.RpcClientConf
}
  • 修改servicecontext.go文件
package svc

import (
	"github.com/zeromicro/go-zero/zrpc"
	"study/go-zero-gorm/api-gateway/internal/config"
	"study/go-zero-gorm/user-srv/userservice"
)

type ServiceContext struct {
	Config  config.Config
	UserRpc userservice.UserService
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config:  c,
		UserRpc: userservice.NewUserService(zrpc.MustNewClient(c.UserRpcConf)),
	}
}
  • 编写业务代码,函数goctl已经生成了,只需要编写业务代码
func (l *UserAddLogic) UserAdd(req *types.UserRequest) (resp *types.Response, err error) {
	// todo: add your logic here and delete this line
	userInfo := user.UserInfo{
		Name:     req.Username,
		Iphone:   req.Phone,
		Nickname: req.Nickname,
		Password: req.Password,
		Status:   int32(req.Status),
		IsAdmin:  req.IsAdmin,
	}
	info, err := l.svcCtx.UserRpc.AddUserInfo(context.Background(), &userInfo)
	if err != nil {
		return nil, err

	}
	resp = &types.Response{
		Message: strconv.Itoa(int(info.GetResult())),
	}
	return
}
posted @ 2024-11-04 15:44  9912  阅读(15)  评论(0编辑  收藏  举报