一、开发环境
开发环境:
- Go:go version go1.18.6 darwin/arm64
- goctl:goctl version 1.4.0 darwin/arm64
- IDE:Goland
安装文档直接看 官网文档
二、微服务项目demo实战
用户在查询订单时,同时需要获取用户信息。
创建项目,一个 order
服务,一个 user
服务
$ mkdir mall
$ cd mall
$ goctl api new order
$ goctl api new user
$ cd mall
$ go work init
$ go work use order
$ go work use user
我要实现使用 order
服务调用 user
服务。需要安装一下依赖
$ cd mall/order
$ go mod tidy
$ cd mall/user
$ go mod tidy
所以需要在 user 模块里创建一个 user.proto
$ cd mall/user/rpc
$ vim user.proto
文件内容如下:
// 声明 proto 语法版本,固定值
syntax = "proto3";
// proto 包名
package user;
// 生成 golang 代码后的包名
option go_package = "./user";
// 定义请求体
message IdRequest {
string id = 1;
}
// 定义响应体
message UserResponse {
string id = 1;
string name = 2;
string gender = 3;
}
// 定义 User 服务
service User{
rpc getUser(IdRequest) returns(UserResponse);
}
服务和服务之间一般使用 rpc 通信,最常使用的就是 grpc,接下来就是使用 protoc-gen-go 将上述的 proto 文件生成 go 代码。
$ cd mall/user/rpc
$ goctl rpc protoc ./user.proto --go_out=./types --go-grpc_out=./types --zrpc_out=./ --style=go_zero
填充 logic 逻辑
func (l *GetUserLogic) GetUser(in *user.IdRequest) (*user.UserResponse, error) {
// todo: add your logic here and delete this line
return &user.UserResponse{
Id: in.GetId(),
Name: "hello my good",
Gender: "man",
}, nil
}
接下来在 order
模块,写一个接口,获取订单信息,其中订单信息中需要携带用户信息。
编写 order.api
$ cd mall/order
$ vim order.api
type Request {
Name string `path:"name,options=you|me"`
}
type Response {
Message string `json:"message"`
}
type (
OrderReq {
Id string `path:"id"`
}
OrderResp {
Id string `json:"id"`
Name string `json:"Name"`
Gender string `json:"Gender"`
}
)
service order-api {
@handler OrderHandler
get /from/:name(Request) returns (Response)
@handler GetOrderHandler
get /api/user/get/:id(OrderReq) returns (OrderResp)
}
生成 api 服务
$ cd mall/order
$ goctl api go -api order.api -dir=./
新增 user rpc 配置
$ vim mall/order/internal/config/config.go
type Config struct {
rest.RestConf
UserRpc zrpc.RpcClientConf
}
在 etc/order-api.yaml
Name: order-api
Host: 0.0.0.0
Port: 8888
UserRpc:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: user.rpc
创建对 user 服务的rpc调用,order/internal/svc/servicecontext.go
package svc
import (
"github.com/zeromicro/go-zero/zrpc"
"order/internal/config"
"user/rpc/userclient"
)
type ServiceContext struct {
Config config.Config
UserRpc userclient.User
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
}
}
编写 logic
package logic
import (
"context"
"user/rpc/types/user"
"order/internal/svc"
"order/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetOrderLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrderLogic {
return &GetOrderLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetOrderLogic) GetOrder(req *types.OrderReq) (resp *types.OrderResp, err error) {
userId := l.getOrderById(req.Id)
// 根据用户id调用rpc服务获取用户信息
userResp, err := l.svcCtx.UserRpc.GetUser(context.Background(), &user.IdRequest{
Id: userId,
})
if err != nil {
return nil, err
}
return &types.OrderResp{
Id: userId,
Name: "hello name",
Gender: userResp.Gender,
}, nil
}
func (l *GetOrderLogic) getOrderById(id string) string {
return "1"
}
这样就搞完,可以启动 etcd,再分别启动user服务和order服务
$ cd mall/user/rpc
$ go run user.go -f etc/user.yaml
$ cd mall/order
$ go run order.go -f etc/order-api.yaml
访问 api/order/get/1