一 前言
本来已经用给出的demo实现过一次了,但是觉得还是差点意思,没什么RPC的味道。所以在本地边学边写用gRPC实现了用户注册登录和查看信息。下面会记录整个流程,其中包括了踩的一些坑。
│ go.mod
│ go.sum
│ main.go
│ tiktok.exe
│
├─client
│ client.exe
│ client.go
│
├─common
│ database.go
│ jwt.go
│ table.go
│ userdata.go
│
├─config
│ application.yml
│
├─handler
│ base.go
│ user_info.go
│ user_login.go
│ user_register.go
│
└─pb
user.pb.go
user.proto
user_grpc.pb.go
二 学习proto
和kitex类似,grpc也可利用插件直接生成相关代码,首先新建pb文件夹,编写user.proto文件,文件内容包括结构体及要开放的rpc服务。大致如下:
安装grpc插件及下载protoc(记得把protoc.exe放到对应文件夹中,不然会找不到),在proto文件的目录下执行下面两条命令可以生成user_grpc.pb.go和user.pb.go。
protoc --go-grpc_out=. *.proto
protoc --go_out=. *.proto
user_grpc.pb.go和user.pb.go会根据你给出的proto生成和rpc服务相关的函数和结构体,在编写handler代码上可以做参考,我们后面再说。
三 基本配置
配置分为三个部分,分别是viper读配置文件,启动数据库和服务启动,
viper
自从学会了用viper之后后面就一直在用了,现在根目录新建一个config文件夹,然后在里面新建一个application.yml的配置文件,里面可以包含数据库信息等。然后用以下代码读入,后续在使用配置信息时,可以通过viper.GetString("")来读入。
数据库启动
借助之前配置过的viper读入数据信息,构造dsn,用gorm来启动数据库,可以利用AutoMigrate来自动生成表。
服务启动
gRPC的服务启动需要先通过listen打开端口进行监听,然后通过s:=grpc.NewServer()创建一个服务,然后可以看到pb中有一个函数RegisterUserServiceServer,调用 RegisterUserServiceServer 函数将rpc服务注册进去,然后客户端就可以调用了,这里有一个推荐的写法是构造一个结构体
type Server struct {
pb.UnimplementedUserServiceServer
}
然后将Server传入进RegisterUserServiceServer,这是利用了protoc帮我们生成的代码,如果以后 .proto 协议中的 service 有变更,增加、删除函数或者修改原来的函数,重新生成 .pb.go 文件的时候,protoc 帮我们重新生成了 UnimplementedUserServiceServer,它一定是实现了 UserServiceServer 这个接口的,所以我们的 UserServiceServerImpl 也是实现了 UserServiceServer 这个接口的。
四 handler
handler是我们主要的业务逻辑,以register举例,在pb文件夹可以看到我们需要实现的函数为
func (s *Server) UserRegister(ctx context.Context, in *pb.DouyinUserRegisterRequest) (*pb.DouyinUserRegisterResponse, error)
通过name获取Users表的信息,如果这个用户已经存在,则不能注册,将用户密码加密,将用户信息插入数据库,返回响应。加密可以使用bcrypt.GenerateFromPassword,获取user表可以使用gorm中的db.where。
五 测试
pb中也顶一个client,我们可以使用client来测试。首先先dial服务的地址,然后创建client并调用register注册用户,最后在navicat查看,密码保存的是哈希值。