目录
[1. 生成 user api 服务](#1. 生成 user api 服务)
[2. 生成 user rpc 服务](#2. 生成 user rpc 服务)
[3. 生成 user model 模型](#3. 生成 user model 模型)
[4. 编写 user rpc 服务](#4. 编写 user rpc 服务)
[1 修改配置文件 user.yaml](#1 修改配置文件 user.yaml)
[2 添加 user model 依赖](#2 添加 user model 依赖)
[3 添加用户登录逻辑 Login](#3 添加用户登录逻辑 Login)
[5. 编写 user api 服务](#5. 编写 user api 服务)
[1 修改配置文件user.yaml](#1 修改配置文件user.yaml)
[2 添加 user rpc 依赖](#2 添加 user rpc 依赖)
[3 添加用户登录逻辑 Login](#3 添加用户登录逻辑 Login)
[6. 启动服务](#6. 启动服务)
本文章讲解使用go-zero生成一个微服务的过程。其中的一些命令或者名不太熟悉的话,可以参考go-zero官网。
项目名字叫zero。创建zero目录,并在该目录下创建user目录。
1. 生成 user api 服务
在user目录下添加api目录,在api目录添加如下的api文件。
bash
syntax = "v1"
type LoginReq {
UserName string `json:"username"`
Password string `json:"password"`
}
type LoginResponse {
Token string `json:"token"`
}
@server (
prefix: v1
)
service user {
@handler login
post /user/login (LoginReq) returns (LoginResponse)
}
在user/api下执行
bash
goctl go api --api ./user.api --dir .
执行生成后,api目录结构体如下
bash
.
├── etc
│ └── user.yaml
├── internal
│ ├── config
│ │ └── config.go
│ ├── handler
│ │ ├── loginhandler.go
│ │ └── routes.go
│ ├── logic
│ │ └── loginlogic.go
│ ├── svc
│ │ └── servicecontext.go
│ └── types
│ └── types.go
├── user.api
└── user.go
2. 生成 user rpc 服务
在user目录下创建rpc目录。在rpc目录下添加如下的proto文件。
bash
syntax="proto3";
package user;
option go_package="./user";
//用户登录
message LoginRequest{
string username=1;
string Password=2;
}
message LoginResponse{
int64 Id=1;
string Username=2;
}
service User{
rpc Login(LoginRequest)returns(LoginResponse);
}
在user/rpc下执行
bash
goctl rpc protoc ./user.proto --go_out=. --go-grpc_out=. --zrpc_out=.
执行生成后,rpc目录结构如下
bash
.
├── etc
│ └── user.yaml
├── internal
│ ├── code
│ │ └── code.go
│ ├── config
│ │ └── config.go
│ ├── db
│ │ └── mysql.go
│ ├── logic
│ │ └── loginlogic.go
│ ├── server
│ │ └── userserver.go
│ └── svc
│ └── servicecontext.go
├── user
│ ├── user_grpc.pb.go
│ └── user.pb.go
├── userclient
│ └── user.go
├── user.go
└── user.proto
3. 生成 user model 模型
在user目录添加model目录,在model中添加如下的user.sql文件。
bash
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=26;
在model目录中执行
bash
goctl model mysql ddl --src user.sql --dir .
执行生成后,model目录结构体如下
bash
.
├── usermodel_gen.go
├── usermodel.go
├── user.sql
└── vars.go
4. 编写 user rpc 服务
1 修改配置文件 user.yaml
因为需要使用数据库MySql,所以我们需要配置数据库的参数,所以需要在user.yaml中填写数据库相关的参数 。而因为rpc是需要用到Etcd(用于服务注册发现等),所以还需要添加Etcd的配置。
bash
Name: user.rpc
ListenOn: 0.0.0.0:8080
#Etcd部分和Mysql部分是新添加的
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
Mysql:
datasource: "root:wook1847@tcp(127.0.0.1:3306)/zero?charset=utf8mb4&parseTime=True&loc=Local"
2 添加 user model 依赖
- 添加
Mysql
服务配置的实例化
在生成的config目录中有config.go文件,该文件中是用于解析配置文件的结构体。而这里我们添加了MySql配置,所以需要添加相关结构体来进行解析。而rest.RestConf中就带有etcd的(看源码),所以不用写etcd的。
Go
type Config struct {
zrpc.RpcServerConf
MysqlConfig Mysql `json:"mysql"` //添加mysql的配置
}
type Mysql struct {
Datasource string
ConectTimeout int64
}
- 注册服务上下文
user model
的依赖
在生成是svc目录中的 servicecontext.go文件,后续我们就是使用该文件中的ServiceContext。而要想可以使用mysql,那就需要在其添加该依赖。
bash
type ServiceContext struct {
Config config.Config
Conn sqlx.SqlConn //这个就是新添加的依赖
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := sqlx.NewMysql(c.MysqlConfig.Datasource)
return &ServiceContext{
Config: c,
Conn: conn,
}
}
3 添加用户登录逻辑 Login
接着看生成的logic目录中的loginlogic.go文件。这里就是我们要写的业务逻辑地方。logic目录中的文件是我们主要写代码的地方。在Login方法中添加业务逻辑。
Go
type LoginLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
return &LoginLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *LoginLogic) Login(in *user.LoginRequest) (*user.LogResponse, error) {
// todo: add your logic here and delete this line
res, err := model.NewUserModel(l.svcCtx.Conn).FindOneByNameAndPwd(l.ctx, in.Username, in.Password)
if err != nil {
fmt.Println("login rpc err.........................:", err)
if err == model.ErrNotFound {
return nil, err
}
return nil, err
}
return &user.LogResponse{Id: res.Id, Username: res.Username}, nil
}
5. 编写 user api 服务
其过程和编写user rpc服务是类似的。
1 修改配置文件user.yaml
因为我们在api中需要使用rpc,所以我们就需要用到etcd,所以就需要etcd的配置。
bash
Name: user
Host: 0.0.0.0
Port: 8888
#添加user rpc的etcd配置
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
#要是还需要其他服务的rpc,那就需要添加的
# PayRpc:
# Etcd:
# Hosts:
# - 127.0.0.1:2379
# Key: pay.rpc
2 添加 user rpc 依赖
- 添加
user rpc
服务配置的实例化
在user.yaml中添加了user rpc的etcd配置后,那就需要再config.go文件中添加对应的结构体来解析配置。
而前面不是说了,etcd的结构体是rest.RestConf就带有的,不用填写了吗?
这不是这个意思的。这个是对应user rpc的etcd配置的。要是在api中还需要用其他服务,比如支付服务,而支付服务又是一个微服务,那就又要添加pay rpc的etcd配置的。
Go
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
// PayRpc zrpc.RpcClientConf 要是需要该服务的话,就需要添加
}
- 添加
user rpc
服务配置的实例化
bash
type ServiceContext struct {
Config config.Config
UserRpc userclient.User //添加user rpc使用
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
}
}
3 添加用户登录逻辑 Login
在生成的logic目录中的loginlogic.文件。这里就是我们要写的业务逻辑。
Go
type LoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
return &LoginLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
//在该方法中添加我们的业务逻辑
func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResponse, err error) {
// todo: add your logic here and delete this line
_, err = l.svcCtx.UserRpc.Login(l.ctx, &userclient.LoginRequest{
Username: req.UserName,
Password: req.Password,
})
if err != nil {
return nil, err
}
return &types.LoginResponse{Token: "123445"}, nil
}
6. 启动服务
因为api服务是依赖rpc服务,所以先启动rpc服务,再启动api服务。
启动rpc服务
在user/api中执行
bash
go run user.go
启动api服务
在user/rpc中执行
bash
go run user.go