Go-Micro+RabbitMQ微服务 实现简单备忘录 (二)

689 阅读3分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战」。

B站视频讲解地址

www.bilibili.com/video/BV1h4…

Github源码

github.com/CocaineCong…

2. 用户模块

2.1 数据库配置

  • user/conf/conf.ini

文件配置,配置mysql,service服务等等...

[service]
AppMode = debug
HttpPort = :3000

[mysql]
Db = mysql
DbHost = 127.0.0.1
DbPort = 3306
DbUser = root
DbPassWord = root
DbName = todo_list
  • user/model/

加载配置

func Init() {
	file, err := ini.Load("./conf/config.ini")
	if err != nil {
		fmt.Println("配置文件读取错误,请检查文件路径:", err)
	}
	LoadMysqlData(file)
	path := strings.Join([]string{DbUser, ":", DbPassWord, "@tcp(", DbHost, ":", DbPort, ")/", DbName, "?charset=utf8&parseTime=true"}, "")
	model.Database(path)
}
  • user/model/user.go

定义数据库模型

type User struct {
	gorm.Model
	UserName       string `gorm:"unique"`
	PasswordDigest string
}
  • user/model/migration.go

数据库模型迁移

func migration() {
	//自动迁移模式
	DB.Set("gorm:table_options", "charset=utf8mb4").
		AutoMigrate(&User{})
}

2.2 proto文件编写

  • user/services/protos/userModels.proto

定义user的proto模型,注意这里一定要大写!!不然后面网关是绑定不到的!

syntax="proto3";
package services;
option go_package ="./;protos";

message UserModel{
    // @inject_tag: json:"id"
    uint32 ID=1;
    // @inject_tag: json:"user_name"
    string UserName=2;
    // @inject_tag: json:"avatar"
    string Avatar=3;
    // @inject_tag: json:"email"
    string Email=4;
    // @inject_tag: json:"nickname"
    string NickName=5;
    // @inject_tag: json:"status"
    string Status=6;
    // @inject_tag: json:"limit"
    uint32 Limit=7;
    // @inject_tag: json:"created_at"
    int64 CreatedAt=8;
    // @inject_tag: json:"updated_at"
    int64 UpdatedAt=9;
    // @inject_tag: json:"deleted_at"
    int64 DeletedAt=10;
}

在proto目录下执行

protoc --proto_path=. --micro_out=. --go_out=. userModel.proto
  • user/services/protos/userService.proto

这里定义了用户请求的参数UserRequestUserResponse的信息

syntax="proto3";
package services;
import "userModels.proto";
option go_package ="./;protos";

message UserRequest{
  // @inject_tag: json:"user_name" form:"user_name" uri:"user_name"
  string UserName=1;
  // @inject_tag: json:"password" form:"password" uri:"password"
  string Password=2;
  // @inject_tag: json:"password_confirm" form:"password_confirm" uri:"password_confirm"
  string PasswordConfirm=3;
}

message UserDetailResponse{
  UserModel UserDetail=1;
  uint32 Code=2;
}


service UserService{
  rpc UserLogin(UserRequest) returns(UserDetailResponse);
  rpc UserRegister(UserRequest) returns(UserDetailResponse);
}

在proto目录下执行

protoc --proto_path=. --micro_out=. --go_out=. userService.proto

生成这些四个文件即可,然后可以移动到services文件中。 在这里插入图片描述

2.3 实现用户模块业务逻辑

定义用户服务的结构体

//UserService 用户服务
type UserService struct {
}

2.3.1 用户注册方法

这里传入的参数是上下文信息,还有services层的 UserRequestUserDetailResponse

// UserRegister 用户注册
func (*UserService) UserRegister(ctx context.Context, req *services.UserRequest, res *services.UserDetailResponse) error {
	if req.Password != req.PasswordConfirm {
		err := errors.New("两次密码输入不一致")
		return err
	}
	count := 0
	if err := model.DB.Model(&model.User{}).Where("user_name=?", req.UserName).Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		err := errors.New("用户名已存在")
		return err
	}
	user := model.User{
		UserName: req.UserName,
	}
	// 加密密码
	if err := user.SetPassword(req.Password); err != nil {
		return err
	}
	// 创建用户
	if err := model.DB.Create(&user).Error; err != nil {
		return err
	}
	res.UserDetail = BuildUser(user)
	return nil
}

2.3.2 登录服务方法

一样的逻辑方法,这里实现了UserLogin方法,同样地传入上下文,请求参数,响应参数

//UserLogin 实现用户服务接口 用户登录
func (*UserService) UserLogin(ctx context.Context, req *services.UserRequest, res *services.UserDetailResponse) error {
	var user model.User
	res.Code = 200
	if err := model.DB.Where("user_name = ?", req.UserName).First(&user).Error; err != nil {
		//如果查询不到,返回相应错误
		if gorm.IsRecordNotFoundError(err) {
			res.Code = 10003
			return nil
		}
		res.Code = 30001
		return nil
	}
	if user.CheckPassword(req.Password) == false {
		res.Code = 10004
		return nil
	}
	res.UserDetail =  BuildUser(user)
	return nil
}

2.4 接入etcd服务发现

  • 注册etcd
	etcdReg := etcd.NewRegistry(
		registry.Addrs("127.0.0.1:2379"),
	)
  • 得到微服务实例
	// 1. 得到微服务实例
	microService := micro.NewService(
		micro.Name("rpcUserService"), // 设置微服务名字,用来访问的
		micro.Address("127.0.0.1:8082"),
		micro.Registry(etcdReg),
	)
  • 初始化
	microService.Init()
  • 服务注册 将用户服务注册到etcd中
	_ = services.RegisterUserServiceHandler(microService.Server(), new(core.UserService))
  • 启动微服务
	_ = microService.Run()

查看etcd中http://localhost:8080/etcdkeeper/是否有该模块的注册信息 在这里插入图片描述

至此,用户端的微服务已经完成了,我们接入网关,调用服务。