我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下:
期望通过本系列带你在本机利用 Docker 环境利用 go-zero 快速开发一个商城系统,让你快速上手微服务。
完整示例代码:https://github.com/nivin-studio/go-zero-mall
首先,我们来看一下整体的服务拆分图:
进入服务工作区
$ cd mall/service/order
创建 sql 文件
$ vim model/order.sql
编写 sql 文件
CREATE TABLE order
(
id
bigint unsigned NOT NULL AUTO_INCREMENT,
uid
bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
pid
bigint unsigned NOT NULL DEFAULT '0' COMMENT '产品ID',
amount
int(10) unsigned NOT NULL DEFAULT '0' COMMENT '订单金额',
status
tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '订单状态',
create_time
timestamp NULL DEFAULT CURRENT_TIMESTAMP,
update_time
timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id
),
KEY idx_uid
(uid
),
KEY idx_pid
(pid
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
运行模板生成命令
$ goctl model mysql ddl -src ./model/order.sql -dir ./model -c
创建 api 文件
$ vim api/order.api
编写 api 文件
type (
// 订单创建
CreateRequest {
Uid int64 json:"uid"
Pid int64 json:"pid"
Amount int64 json:"amount"
Status int64 json:"status"
}
CreateResponse {
Id int64 json:"id"
}
// 订单创建
// 订单修改
UpdateRequest {
Id int64 `json:"id"`
Uid int64 `json:"uid,optional"`
Pid int64 `json:"pid,optional"`
Amount int64 `json:"amount,optional"`
Status int64 `json:"status,optional"`
}
UpdateResponse {
}
// 订单修改
// 订单删除
RemoveRequest {
Id int64 `json:"id"`
}
RemoveResponse {
}
// 订单删除
// 订单详情
DetailRequest {
Id int64 `json:"id"`
}
DetailResponse {
Id int64 `json:"id"`
Uid int64 `json:"uid"`
Pid int64 `json:"pid"`
Amount int64 `json:"amount"`
Status int64 `json:"status"`
}
// 订单详情
// 订单列表
ListRequest {
Uid int64 `json:"uid"`
}
ListResponse {
Id int64 `json:"id"`
Uid int64 `json:"uid"`
Pid int64 `json:"pid"`
Amount int64 `json:"amount"`
Status int64 `json:"status"`
}
// 订单列表
)
@server(
jwt: Auth
)
service Order {
@handler Create
post /api/order/create(CreateRequest) returns (CreateResponse)
@handler Update
post /api/order/update(UpdateRequest) returns (UpdateResponse)
@handler Remove
post /api/order/remove(RemoveRequest) returns (RemoveResponse)
@handler Detail
post /api/order/detail(DetailRequest) returns (DetailResponse)
@handler List
post /api/order/list(ListRequest) returns (ListResponse)
}
运行模板生成命令
$ goctl api go -api ./api/order.api -dir ./api
创建 proto 文件
$ vim rpc/order.proto
编写 proto 文件
syntax = "proto3";
package orderclient;
option go_package = "order";
// 订单创建
message CreateRequest {
int64 Uid = 1;
int64 Pid = 2;
int64 Amount = 3;
int64 Status = 4;
}
message CreateResponse {
int64 id = 1;
}
// 订单创建
// 订单修改
message UpdateRequest {
int64 id = 1;
int64 Uid = 2;
int64 Pid = 3;
int64 Amount = 4;
int64 Status = 5;
}
message UpdateResponse {
}
// 订单修改
// 订单删除
message RemoveRequest {
int64 id = 1;
}
message RemoveResponse {
}
// 订单删除
// 订单详情
message DetailRequest {
int64 id = 1;
}
message DetailResponse {
int64 id = 1;
int64 Uid = 2;
int64 Pid = 3;
int64 Amount = 4;
int64 Status = 5;
}
// 订单详情
// 订单列表
message ListRequest {
int64 uid = 1;
}
message ListResponse {
repeated DetailResponse data = 1;
}
// 订单列表
// 订单支付
message PaidRequest {
int64 id = 1;
}
message PaidResponse {
}
// 订单支付
service Order {
rpc Create(CreateRequest) returns(CreateResponse);
rpc Update(UpdateRequest) returns(UpdateResponse);
rpc Remove(RemoveRequest) returns(RemoveResponse);
rpc Detail(DetailRequest) returns(DetailResponse);
rpc List(ListRequest) returns(ListResponse);
rpc Paid(PaidRequest) returns(PaidResponse);
}
运行模板生成命令
$ goctl rpc proto -src ./rpc/order.proto -dir ./rpc
修改 order.yaml 配置文件
$ vim rpc/etc/order.yaml
修改服务监听地址,端口号为0.0.0.0:9002,Etcd
服务配置,Mysql
服务配置,CacheRedis
服务配置
Name: order.rpc
ListenOn: 0.0.0.0:9002
Etcd:
Hosts:
Mysql:
DataSource: root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
CacheRedis:
添加 Mysql
服务配置,CacheRedis
服务配置的实例化
$ vim rpc/internal/config/config.go
package config
import (
"github.com/tal-tech/go-zero/core/stores/cache"
"github.com/tal-tech/go-zero/zrpc"
)
type Config struct {
zrpc.RpcServerConf
Mysql struct {
DataSource string
}
CacheRedis cache.CacheConf
}
注册服务上下文 order model
的依赖
$ vim rpc/internal/svc/servicecontext.go
package svc
import (
"mall/service/order/model"
"mall/service/order/rpc/internal/config"
"github.com/tal-tech/go-zero/core/stores/sqlx"
)
type ServiceContext struct {
Config config.Config
OrderModel model.OrderModel
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := sqlx.NewMysql(c.Mysql.DataSource)
return &ServiceContext{
Config: c,
OrderModel: model.NewOrderModel(conn, c.CacheRedis),
}
}
添加 user rpc, product rpc
服务配置
$ vim rpc/etc/order.yaml
Name: order.rpc
ListenOn: 0.0.0.0:9002
Etcd:
Hosts:
……
UserRpc:
Etcd:
Hosts:
- etcd:2379
Key: user.rpc
ProductRpc:
Etcd:
Hosts:
- etcd:2379
Key: product.rpc
添加 user rpc, product rpc
服务配置的实例化
$ vim rpc/internal/config/config.go
package config
import (
"github.com/tal-tech/go-zero/core/stores/cache"
"github.com/tal-tech/go-zero/zrpc"
)
type Config struct {
zrpc.RpcServerConf
Mysql struct {
DataSource string
}
CacheRedis cache.CacheConf
UserRpc zrpc.RpcClientConf
ProductRpc zrpc.RpcClientConf
}
注册服务上下文 user rpc, product rpc
的依赖
$ vim rpc/internal/svc/servicecontext.go
package svc
import (
"mall/service/order/model"
"mall/service/order/rpc/internal/config"
"mall/service/product/rpc/productclient"
"mall/service/user/rpc/userclient"
"github.com/tal-tech/go-zero/core/stores/sqlx"
"github.com/tal-tech/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
OrderModel model.OrderModel
UserRpc userclient.User
ProductRpc productclient.Product
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := sqlx.NewMysql(c.Mysql.DataSource)
return &ServiceContext{
Config: c,
OrderModel: model.NewOrderModel(conn, c.CacheRedis),
UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
ProductRpc: productclient.NewProduct(zrpc.MustNewClient(c.ProductRpc)),
}
}
订单创建流程,通过调用 user rpc
服务查询验证用户是否存在,再通过调用 product rpc
服务查询验证产品是否存在,以及判断产品库存是否充足。验证通过后,创建用户订单,并通过调用 product rpc
服务更新产品库存。
$ vim rpc/internal/logic/createlogic.go
package logic
import (
"context"
"mall/service/order/model"
"mall/service/order/rpc/internal/svc"
"mall/service/order/rpc/order"
"mall/service/product/rpc/product"
"mall/service/user/rpc/user"
"github.com/tal-tech/go-zero/core/logx"
"google.golang.org/grpc/status"
)
type CreateLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLogic {
return &CreateLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *CreateLogic) Create(in *order.CreateRequest) (*order.CreateResponse, error) {
// 查询用户是否存在
_, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &user.UserInfoRequest{
Id: in.Uid,
})
if err != nil {
return nil, err
}
// 查询产品是否存在
productRes, err := l.svcCtx.ProductRpc.Detail(l.ctx, &product.DetailRequest{
Id: in.Pid,
})
if err != nil {
return nil, err
}
// 判断产品库存是否充足
if productRes.Stock <= 0 {
return nil, status.Error(500, "产品库存不足")
}
newOrder := model.Order{
Uid: in.Uid,
Pid: in.Pid,
Amount: in.Amount,
Status: 0,
}
// 创建订单
res, err := l.svcCtx.OrderModel.Insert(&newOrder)
if err != nil {
return nil, status.Error(500, err.Error())
}
newOrder.Id, err = res.LastInsertId()
if err != nil {
return nil, status.Error(500, err.Error())
}
// 更新产品库存
_, err = l.svcCtx.ProductRpc.Update(l.ctx, &product.UpdateRequest{
Id: productRes.Id,
Name: productRes.Name,
Desc: productRes.Desc,
Stock: productRes.Stock - 1,
Amount: productRes.Amount,
Status: productRes.Status,
})
if err != nil {
return nil, err
}
return &order.CreateResponse{
Id: newOrder.Id,
}, nil
}
!注意:这里的产品库存更新存在数据一致性问题,在以往的项目中我们会使用数据库的事务进行这一系列的操作来保证数据的一致性。但是因为我们这边把“订单”和“产品”分成了不同的微服务,在实际的项目中他们可能拥有不同的数据库,所以我们要考虑在跨服务的情况下还能保证数据的一致性,这就涉及到了分布式事务的使用,在后面的章节中我们将介绍使用分布式事务来修改这个下单的逻辑。
$ vim rpc/internal/logic/detaillogic.go
package logic
import (
"context"
"mall/service/order/model"
"mall/service/order/rpc/internal/svc"
"mall/service/order/rpc/order"
"github.com/tal-tech/go-zero/core/logx"
"google.golang.org/grpc/status"
)
type DetailLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DetailLogic {
return &DetailLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *DetailLogic) Detail(in *order.DetailRequest) (*order.DetailResponse, error) {
// 查询订单是否存在
res, err := l.svcCtx.OrderModel.FindOne(in.Id)
if err != nil {
if err == model.ErrNotFound {
return nil, status.Error(100, "订单不存在")
}
return nil, status.Error(500, err.Error())
}
return &order.DetailResponse{
Id: res.Id,
Uid: res.Uid,
Pid: res.Pid,
Amount: res.Amount,
Status: res.Status,
}, nil
}
$ vim rpc/internal/logic/updatelogic.go
package logic
import (
"context"
"mall/service/order/model"
"mall/service/order/rpc/internal/svc"
"mall/service/order/rpc/order"
"github.com/tal-tech/go-zero/core/logx"
"google.golang.org/grpc/status"
)
type UpdateLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateLogic {
return &UpdateLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *UpdateLogic) Update(in *order.UpdateRequest) (*order.UpdateResponse, error) {
// 查询订单是否存在
res, err := l.svcCtx.OrderModel.FindOne(in.Id)
if err != nil {
if err == model.ErrNotFound {
return nil, status.Error(100, "订单不存在")
}
return nil, status.Error(500, err.Error())
}
if in.Uid != 0 {
res.Uid = in.Uid
}
if in.Pid != 0 {
res.Pid = in.Pid
}
if in.Amount != 0 {
res.Amount = in.Amount
}
if in.Status != 0 {
res.Status = in.Status
}
err = l.svcCtx.OrderModel.Update(res)
if err != nil {
return nil, status.Error(500, err.Error())
}
return &order.UpdateResponse{}, nil
}
$ vim rpc/internal/logic/removelogic.go
package logic
import (
"context"
"mall/service/order/model"
"mall/service/order/rpc/internal/svc"
"mall/service/order/rpc/order"
"github.com/tal-tech/go-zero/core/logx"
"google.golang.org/grpc/status"
)
type RemoveLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewRemoveLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RemoveLogic {
return &RemoveLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *RemoveLogic) Remove(in *order.RemoveRequest) (*order.RemoveResponse, error) {
// 查询订单是否存在
res, err := l.svcCtx.OrderModel.FindOne(in.Id)
if err != nil {
if err == model.ErrNotFound {
return nil, status.Error(100, "订单不存在")
}
return nil, status.Error(500, err.Error())
}
err = l.svcCtx.OrderModel.Delete(res.Id)
if err != nil {
return nil, status.Error(500, err.Error())
}
return &order.RemoveResponse{}, nil
}
添加根据 uid
查询用户所有订单的 OrderModel
方法 FindAllByUid
$ vim model/ordermodel.go
package model
……
type (
OrderModel interface {
Insert(data Order) (sql.Result, error)
FindOne(id int64) (Order, error)
FindAllByUid(uid int64) ([]*Order, error)
Update(data *Order) error
Delete(id int64) error
}
......
)
……
func (m defaultOrderModel) FindAllByUid(uid int64) ([]Order, error) {
var resp []*Order
query := fmt.Sprintf("select %s from %s where `uid` = ?", orderRows, m.table)
err := m.QueryRowsNoCache(&resp, query, uid)
switch err {
case nil:
return resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
……
添加订单列表逻辑
$ vim rpc/internal/logic/listlogic.go
package logic
import (
"context"
"mall/service/order/model"
"mall/service/order/rpc/internal/svc"
"mall/service/order/rpc/order"
"mall/service/user/rpc/user"
"github.com/tal-tech/go-zero/core/logx"
"google.golang.org/grpc/status"
)
type ListLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListLogic {
return &ListLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *ListLogic) List(in *order.ListRequest) (*order.ListResponse, error) {
// 查询用户是否存在
_, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &user.UserInfoRequest{
Id: in.Uid,
})
if err != nil {
return nil, err
}
// 查询订单是否存在
list, err := l.svcCtx.OrderModel.FindAllByUid(in.Uid)
if err != nil {
if err == model.ErrNotFound {
return nil, status.Error(100, "订单不存在")
}
return nil, status.Error(500, err.Error())
}
orderList := make([]*order.DetailResponse, 0)
for _, item := range list {
orderList = append(orderList, &order.DetailResponse{
Id: item.Id,
Uid: item.Uid,
Pid: item.Pid,
Amount: item.Amount,
Status: item.Status,
})
}
return &order.ListResponse{
Data: orderList,
}, nil
}
$ vim rpc/internal/logic/paidlogic.go
package logic
import (
"context"
"mall/service/order/model"
"mall/service/order/rpc/internal/svc"
"mall/service/order/rpc/order"
"github.com/tal-tech/go-zero/core/logx"
"google.golang.org/grpc/status"
)
type PaidLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewPaidLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaidLogic {
return &PaidLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *PaidLogic) Paid(in *order.PaidRequest) (*order.PaidResponse, error) {
// 查询订单是否存在
res, err := l.svcCtx.OrderModel.FindOne(in.Id)
if err != nil {
if err == model.ErrNotFound {
return nil, status.Error(100, "订单不存在")
}
return nil, status.Error(500, err.Error())
}
res.Status = 1
err = l.svcCtx.OrderModel.Update(res)
if err != nil {
return nil, status.Error(500, err.Error())
}
return &order.PaidResponse{}, nil
}
修改 order.yaml 配置文件
$ vim api/etc/order.yaml
修改服务地址,端口号为0.0.0.0:8002,Mysql
服务配置,CacheRedis
服务配置,Auth
验证配置
Name: Order
Host: 0.0.0.0
Port: 8002
Mysql:
DataSource: root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
CacheRedis:
Auth:
AccessSecret: uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl
AccessExpire: 86400
添加 order rpc
服务配置
$ vim api/etc/order.yaml
Name: Order
Host: 0.0.0.0
Port: 8002
……
OrderRpc:
Etcd:
Hosts:
- etcd:2379
Key: order.rpc
添加 order rpc
服务配置的实例化
$ vim api/internal/config/config.go
package config
import (
"github.com/tal-tech/go-zero/rest"
"github.com/tal-tech/go-zero/zrpc"
)
type Config struct {
rest.RestConf
Auth struct {
AccessSecret string
AccessExpire int64
}
OrderRpc zrpc.RpcClientConf
}
注册服务上下文 user rpc
的依赖
$ vim api/internal/svc/servicecontext.go
package svc
import (
"mall/service/order/api/internal/config"
"mall/service/order/rpc/orderclient"
"github.com/tal-tech/go-zero/zrpc"
)
type ServiceContext struct {
Config config.Config
OrderRpc orderclient.Order
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
OrderRpc: orderclient.NewOrder(zrpc.MustNewClient(c.OrderRpc)),
}
}
$ vim api/internal/logic/createlogic.go
package logic
import (
"context"
"mall/service/order/api/internal/svc"
"mall/service/order/api/internal/types"
"mall/service/order/rpc/orderclient"
"github.com/tal-tech/go-zero/core/logx"
)
type CreateLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) CreateLogic {
return CreateLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *CreateLogic) Create(req types.CreateRequest) (resp *types.CreateResponse, err error) {
res, err := l.svcCtx.OrderRpc.Create(l.ctx, &orderclient.CreateRequest{
Uid: req.Uid,
Pid: req.Pid,
Amount: req.Amount,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &types.CreateResponse{
Id: res.Id,
}, nil
}
$ vim api/internal/logic/detaillogic.go
package logic
import (
"context"
"mall/service/order/api/internal/svc"
"mall/service/order/api/internal/types"
"mall/service/order/rpc/orderclient"
"github.com/tal-tech/go-zero/core/logx"
)
type DetailLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) DetailLogic {
return DetailLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *DetailLogic) Detail(req types.DetailRequest) (resp *types.DetailResponse, err error) {
res, err := l.svcCtx.OrderRpc.Detail(l.ctx, &orderclient.DetailRequest{
Id: req.Id,
})
if err != nil {
return nil, err
}
return &types.DetailResponse{
Id: res.Id,
Uid: res.Uid,
Pid: res.Pid,
Amount: res.Amount,
Status: res.Status,
}, nil
}
$ vim api/internal/logic/updatelogic.go
package logic
import (
"context"
"mall/service/order/api/internal/svc"
"mall/service/order/api/internal/types"
"mall/service/order/rpc/orderclient"
"github.com/tal-tech/go-zero/core/logx"
)
type UpdateLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) UpdateLogic {
return UpdateLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *UpdateLogic) Update(req types.UpdateRequest) (resp *types.UpdateResponse, err error) {
_, err = l.svcCtx.OrderRpc.Update(l.ctx, &orderclient.UpdateRequest{
Id: req.Id,
Uid: req.Uid,
Pid: req.Pid,
Amount: req.Amount,
Status: req.Status,
})
if err != nil {
return nil, err
}
return &types.UpdateResponse{}, nil
}
$ vim api/internal/logic/removelogic.go
package logic
import (
"context"
"mall/service/order/api/internal/svc"
"mall/service/order/api/internal/types"
"mall/service/order/rpc/orderclient"
"github.com/tal-tech/go-zero/core/logx"
)
type RemoveLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRemoveLogic(ctx context.Context, svcCtx *svc.ServiceContext) RemoveLogic {
return RemoveLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *RemoveLogic) Remove(req types.RemoveRequest) (resp *types.RemoveResponse, err error) {
_, err = l.svcCtx.OrderRpc.Remove(l.ctx, &orderclient.RemoveRequest{
Id: req.Id,
})
if err != nil {
return nil, err
}
return &types.RemoveResponse{}, nil
}
$ vim api/internal/logic/listlogic.go
package logic
import (
"context"
"mall/service/order/api/internal/svc"
"mall/service/order/api/internal/types"
"mall/service/order/rpc/orderclient"
"github.com/tal-tech/go-zero/core/logx"
)
type ListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewListLogic(ctx context.Context, svcCtx *svc.ServiceContext) ListLogic {
return ListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ListLogic) List(req types.ListRequest) (resp []*types.ListResponse, err error) {
res, err := l.svcCtx.OrderRpc.List(l.ctx, &orderclient.ListRequest{
Uid: req.Uid,
})
if err != nil {
return nil, err
}
orderList := make([]*types.ListResponse, 0)
for _, item := range res.Data {
orderList = append(orderList, &types.ListResponse{
Id: item.Id,
Uid: item.Uid,
Pid: item.Pid,
Amount: item.Amount,
Status: item.Status,
})
}
return orderList, nil
}
!提示:启动服务需要在
golang
容器中启动
$ cd mall/service/order/rpc
$ go run order.go -f etc/order.yaml
Starting rpc server at 127.0.0.1:9002...
!提示:启动服务需要在
golang
容器中启动
$ cd mall/service/order/api
$ go run order.go -f etc/order.yaml
Starting server at 0.0.0.0:8002...
https://github.com/zeromicro/go-zero
欢迎使用 go-zero
并 star 支持我们!
关注『微服务实践』公众号并点击 交流群 获取社区群二维码。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章