返回
深度剖析 Go-zero 开箱即用的微服务框架(进阶篇)
前端
2023-11-11 08:50:19
在上一篇文章《Go-zero:开箱即用的微服务框架》中,我们简单介绍了 Go-zero 的基本概念和特性。在这篇文章中,我们将深入探讨如何使用 Go-zero 来开发一个博客的后台系统。我们将重点介绍如何使用 Go-zero 来实现 CRUD 操作、设计 API、使用 gRPC 进行服务间通信、连接 MongoDB 和 MySQL 等内容。
项目结构
我们首先来看一下项目的结构:
├── api
│ ├── blog.pb.go
│ └── blog.pb.gw.go
├── cmd
│ └── blogd
│ ├── main.go
│ └── wire.go
├── internal
│ ├── biz
│ │ ├── blog.go
│ │ └── user.go
│ ├── conf
│ │ ├── config.go
│ │ └── config.yaml
│ ├── handler
│ │ ├── blog.go
│ │ └── user.go
│ ├── model
│ │ ├── blog.go
│ │ └── user.go
│ ├── service
│ │ ├── blog.go
│ │ └── user.go
│ ├── storage
│ │ ├── blog.go
│ │ └── user.go
│ ├── transport
│ │ ├── blog.go
│ │ └── user.go
│ └── wire.go
├── scripts
│ └── gen.sh
└── test
初始化项目
我们可以使用 Go-zero 自带的脚手架工具来初始化一个项目:
go zero init blogd
配置文件
接下来,我们需要在项目根目录下创建配置文件 conf/config.yaml
:
Mode: debug
Service:
Name: blogd
Host: 0.0.0.0
Port: 8848
UseGrpc: true
DB:
DataSource: "mongodb://localhost:27017/blog"
Table: user
业务逻辑
我们首先定义一个用户模型:
type User struct {
Id int64 `db:"id"`
Username string `db:"username"`
Password string `db:"password"`
}
然后,我们定义一个用户服务接口:
type UserService interface {
CreateUser(ctx context.Context, in *userpb.CreateUserReq) (*userpb.CreateUserResp, error)
UpdateUser(ctx context.Context, in *userpb.UpdateUserReq) (*userpb.UpdateUserResp, error)
GetUser(ctx context.Context, in *userpb.GetUserReq) (*userpb.GetUserResp, error)
DeleteUser(ctx context.Context, in *userpb.DeleteUserReq) (*userpb.DeleteUserResp, error)
ListUsers(ctx context.Context, in *userpb.ListUsersReq) (*userpb.ListUsersResp, error)
}
最后,我们实现用户服务接口:
type userServiceImpl struct {
dao userdao.UserDao
}
func NewUserService(dao userdao.UserDao) UserService {
return &userServiceImpl{
dao: dao,
}
}
func (s *userServiceImpl) CreateUser(ctx context.Context, in *userpb.CreateUserReq) (*userpb.CreateUserResp, error) {
user := &User{
Username: in.Username,
Password: in.Password,
}
id, err := s.dao.Insert(ctx, user)
if err != nil {
return nil, err
}
return &userpb.CreateUserResp{
Id: id,
}, nil
}
func (s *userServiceImpl) UpdateUser(ctx context.Context, in *userpb.UpdateUserReq) (*userpb.UpdateUserResp, error) {
user := &User{
Id: in.Id,
Username: in.Username,
Password: in.Password,
}
err := s.dao.Update(ctx, user)
if err != nil {
return nil, err
}
return &userpb.UpdateUserResp{}, nil
}
func (s *userServiceImpl) GetUser(ctx context.Context, in *userpb.GetUserReq) (*userpb.GetUserResp, error) {
user, err := s.dao.FindOne(ctx, in.Id)
if err != nil {
return nil, err
}
return &userpb.GetUserResp{
Id: user.Id,
Username: user.Username,
Password: user.Password,
}, nil
}
func (s *userServiceImpl) DeleteUser(ctx context.Context, in *userpb.DeleteUserReq) (*userpb.DeleteUserResp, error) {
err := s.dao.Delete(ctx, in.Id)
if err != nil {
return nil, err
}
return &userpb.DeleteUserResp{}, nil
}
func (s *userServiceImpl) ListUsers(ctx context.Context, in *userpb.ListUsersReq) (*userpb.ListUsersResp, error) {
users, err := s.dao.FindAll(ctx)
if err != nil {
return nil, err
}
var respUsers []*userpb.User
for _, user := range users {
respUsers = append(respUsers, &userpb.User{
Id: user.Id,
Username: user.Username,
Password: user.Password,
})
}
return &userpb.ListUsersResp{
Users: respUsers,
}, nil
}
数据层
我们使用 MongoDB 作为数据存储,因此我们需要定义一个用户数据访问对象:
type UserDao interface {
Insert(ctx context.Context, user *User) (int64, error)
Update(ctx context.Context, user *User) error
FindOne(ctx context.Context, id int64) (*User, error)
Delete(ctx context.Context, id int64) error
FindAll(ctx context.Context) ([]*User, error)
}
然后,我们实现用户数据访问对象:
type userDaoImpl struct {
client *mongo.Client
}
func NewUserDao(client *mongo.Client) UserDao {
return &userDaoImpl{
client: client,
}
}
func (d *userDaoImpl) Insert(ctx context.Context, user *User) (int64, error) {
result, err := d.client.Database("blog").Collection("user").InsertOne(ctx, user)
if err != nil {
return 0, err
}
return result.InsertedID.(int64), nil
}
func (d *userDaoImpl) Update(ctx context.Context, user *User) error {
_, err := d.client.Database("blog").Collection("user").UpdateOne(ctx, bson.M{"id": user.Id}, bson.M{"$set": user})
return err
}
func (d *userDaoImpl) FindOne(ctx context.Context, id int64) (*User, error) {
var user User
err := d.client.Database("blog").Collection("user").FindOne(ctx, bson.M{"id": id}).Decode(&user)
if err != nil {
return nil, err
}
return &user, nil
}
func (d *userDaoImpl) Delete(ctx context.Context, id int64) error {
_, err := d.client.Database("blog").Collection("user").DeleteOne(ctx, bson.M{"id": id})
return err
}
func (d *userDaoImpl) FindAll(ctx context.Context) ([]*User, error) {
var users []*User
cursor, err := d.client.Database("blog").Collection("user").Find(ctx, bson.M{})
if err != nil {
return nil, err
}
for {
var user User
if err = cursor.Next(ctx); err == mongo.Err