0、索引

go-zero docker-compose 搭建课件服务(一):编写服务api和proto

go-zero docker-compose 搭建课件服务(二):编写courseware rpc服务

go-zero docker-compose 搭建课件服务(三):编写courseware api服务

go-zero docker-compose 搭建课件服务(四):生成Dockerfile并在docker-compose中启动

go-zero docker-compose 搭建课件服务(五):欠缺user服务

go-zero docker-compose 搭建课件服务(六):欠缺jwt鉴权和返回构造

go-zero docker-compose 搭建课件服务(七):prometheus+grafana服务监控

0.1源码地址

https://github.com/liuyuede123/go-zero-courseware

1、生成model

到我的项目根目录下创立model目录,并新建user.sql

mkdir user/rpc/modeltouch user/rpc/model/user.sql
CREATE TABLE `user`(    `id`          bigint unsigned NOT NULL AUTO_INCREMENT,    `login_name`  varchar(255) NOT NULL DEFAULT '' COMMENT '登录名',    `username`        varchar(255) NOT NULL DEFAULT '' COMMENT '用户姓名',    `sex`      tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '用户性别',    `password`    varchar(255) NOT NULL DEFAULT '' COMMENT '用户明码',    `is_delete`   tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否删除 0-未删除 1-已删除',    `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,    `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,    PRIMARY KEY (`id`),    UNIQUE KEY `udx_login_name` (`login_name`)) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4;

到model目录下生成model

cd user/rpc/modelgoctl model mysql ddl -src="./*.sql" -dir="./" -c

2、生成rpc文件

到user/rpc目录下生成rpc文件

goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=.

3、减少mysql配置

user目录下初始化module

go mod initgo mod tidy

user/rpc/etc/user.yaml中减少数据源和缓存配置

Name: user.rpcListenOn: 127.0.0.1:8300Etcd:  Hosts:  - etcd:2379  Key: user.rpc# mysql数据源Mysql:  DataSource: root:liufutian@tcp(192.168.0.110:3306)/go_zero_courseware?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai# redis缓存CacheRedis:  - Host: 192.168.0.110:6379    Pass:

批改user/rpc/internal/config/config.go中配置

package configimport (    "github.com/zeromicro/go-zero/core/stores/cache"    "github.com/zeromicro/go-zero/zrpc")type Config struct {    zrpc.RpcServerConf    Mysql struct {        DataSource string    }    CacheRedis cache.CacheConf}

批改courseware/rpc/internal/svc/servicecontext.go相干配置

package svcimport (    "github.com/zeromicro/go-zero/core/stores/sqlx"    "go-zero-courseware/user/rpc/internal/config"    "go-zero-courseware/user/rpc/model")type ServiceContext struct {    Config config.Config    UserModel model.UserModel}func NewServiceContext(c config.Config) *ServiceContext {    conn := sqlx.NewMysql(c.Mysql.DataSource)    return &ServiceContext{        Config: c,        UserModel: model.NewUserModel(conn, c.CacheRedis),    }}

4、增加用户逻辑

先走通,后续会优化用户逻辑

user/rpc/internal/logic/registerlogic.go减少注册逻辑

package logicimport (    "context"    "go-zero-courseware/user/rpc/internal/svc"    "go-zero-courseware/user/rpc/model"    "go-zero-courseware/user/rpc/user"    "google.golang.org/grpc/status"    "github.com/zeromicro/go-zero/core/logx")type RegisterLogic struct {    ctx    context.Context    svcCtx *svc.ServiceContext    logx.Logger}func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic {    return &RegisterLogic{        ctx:    ctx,        svcCtx: svcCtx,        Logger: logx.WithContext(ctx),    }}func (l *RegisterLogic) Register(in *user.RegisterRequest) (*user.RegisterResponse, error) {    _, err := l.svcCtx.UserModel.FindOneByLoginName(l.ctx, in.LoginName)    if err == nil {        return nil, status.Error(5000, "登录名已存在")    }    if err != model.ErrNotFound {        return nil, status.Error(500, err.Error())    }    newUser := model.User{        LoginName: in.LoginName,        Username:  in.Username,        Sex:       in.Sex,        Password:  in.Password,    }    _, err = l.svcCtx.UserModel.Insert(l.ctx, &newUser)    if err != nil {        return nil, status.Error(500, err.Error())    }    return &user.RegisterResponse{}, nil}

user/rpc/internal/logic/loginlogic.go减少登录逻辑

package logicimport (    "context"    "go-zero-courseware/user/rpc/model"    "google.golang.org/grpc/status"    "go-zero-courseware/user/rpc/internal/svc"    "go-zero-courseware/user/rpc/user"    "github.com/zeromicro/go-zero/core/logx")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.LoginResponse, error) {    userInfo, err := l.svcCtx.UserModel.FindOneByLoginName(l.ctx, in.LoginName)    if err == model.ErrNotFound {        return nil, status.Error(5000, "用户不存在")    }    if err != nil {        return nil, status.Error(500, err.Error())    }    if in.Password != userInfo.Password {        return nil, status.Error(5000, "明码谬误")    }    return &user.LoginResponse{        Id:    userInfo.Id,        Token: "a.b.c",    }, nil}

减少用户信息逻辑

package logicimport (    "context"    "go-zero-courseware/user/rpc/model"    "google.golang.org/grpc/status"    "go-zero-courseware/user/rpc/internal/svc"    "go-zero-courseware/user/rpc/user"    "github.com/zeromicro/go-zero/core/logx")type UserInfoLogic struct {    ctx    context.Context    svcCtx *svc.ServiceContext    logx.Logger}func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserInfoLogic {    return &UserInfoLogic{        ctx:    ctx,        svcCtx: svcCtx,        Logger: logx.WithContext(ctx),    }}func (l *UserInfoLogic) UserInfo(in *user.UserInfoRequest) (*user.UserInfoResponse, error) {    userInfo, err := l.svcCtx.UserModel.FindOne(l.ctx, in.Id)    if err == model.ErrNotFound {        return nil, status.Error(5000, "用户不存在")    }    if err != nil {        return nil, status.Error(500, err.Error())    }    return &user.UserInfoResponse{        Id:        userInfo.Id,        Username:  userInfo.Username,        LoginName: userInfo.LoginName,        Sex:       userInfo.Sex,    }, nil}

5、欠缺api代码

到user/api目录下,生成api端代码

goctl api go -api user.api -dir . -style gozero

user/api/etc/user.yaml配置

Name: userHost: 0.0.0.0Port: 8300UserRpc:  Etcd:    Hosts:      - etcd:2379    Key: user.rpc

user/api/internal/config/config.go配置

package configimport (    "github.com/zeromicro/go-zero/rest"    "github.com/zeromicro/go-zero/zrpc")type Config struct {    rest.RestConf    UserRpc zrpc.RpcClientConf}

user/api/internal/svc/servicecontext.go配置

package svcimport (    "github.com/zeromicro/go-zero/zrpc"    "go-zero-courseware/user/api/internal/config"    "go-zero-courseware/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)),    }}

user/api/internal/logic/userregisterlogic.go减少注册逻辑

package logicimport (    "context"    "go-zero-courseware/user/rpc/userclient"    "google.golang.org/grpc/status"    "go-zero-courseware/user/api/internal/svc"    "go-zero-courseware/user/api/internal/types"    "github.com/zeromicro/go-zero/core/logx")type UserRegisterLogic struct {    logx.Logger    ctx    context.Context    svcCtx *svc.ServiceContext}func NewUserRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserRegisterLogic {    return &UserRegisterLogic{        Logger: logx.WithContext(ctx),        ctx:    ctx,        svcCtx: svcCtx,    }}func (l *UserRegisterLogic) UserRegister(req *types.RegisterRequest) (resp *types.RegisterResponse, err error) {    _, err = l.svcCtx.UserRpc.Register(l.ctx, &userclient.RegisterRequest{        LoginName: req.LoginName,        Username:  req.Username,        Password:  req.Password,        Sex:       req.Sex,    })    if err != nil {        return nil, status.Error(500, err.Error())    }    return &types.RegisterResponse{}, nil}

user/api/internal/logic/userloginlogic.go减少登录逻辑

package logicimport (    "context"    "go-zero-courseware/user/rpc/userclient"    "go-zero-courseware/user/api/internal/svc"    "go-zero-courseware/user/api/internal/types"    "github.com/zeromicro/go-zero/core/logx")type UserLoginLogic struct {    logx.Logger    ctx    context.Context    svcCtx *svc.ServiceContext}func NewUserLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserLoginLogic {    return &UserLoginLogic{        Logger: logx.WithContext(ctx),        ctx:    ctx,        svcCtx: svcCtx,    }}func (l *UserLoginLogic) UserLogin(req *types.LoginRequest) (resp *types.LoginResponse, err error) {    login, err := l.svcCtx.UserRpc.Login(l.ctx, &userclient.LoginRequest{        LoginName: req.LoginName,        Password:  req.Password,    })    if err != nil {        return nil, err    }    return &types.LoginResponse{        Id:    login.Id,        Token: login.Token,    }, nil}

user/api/internal/logic/userinfologic.go减少用户信息逻辑

package logicimport (    "context"    "go-zero-courseware/user/rpc/userclient"    "google.golang.org/grpc/status"    "go-zero-courseware/user/api/internal/svc"    "go-zero-courseware/user/api/internal/types"    "github.com/zeromicro/go-zero/core/logx")type UserInfoLogic struct {    logx.Logger    ctx    context.Context    svcCtx *svc.ServiceContext}func NewUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserInfoLogic {    return &UserInfoLogic{        Logger: logx.WithContext(ctx),        ctx:    ctx,        svcCtx: svcCtx,    }}func (l *UserInfoLogic) UserInfo(req *types.UserInfoRequest) (resp *types.UserInfoResponse, err error) {    info, err := l.svcCtx.UserRpc.UserInfo(l.ctx, &userclient.UserInfoRequest{        Id: req.Id,    })    if err != nil {        return nil, status.Error(500, err.Error())    }    return &types.UserInfoResponse{        Id:        info.Id,        Username:  info.Username,        LoginName: info.LoginName,        Sex:       info.Sex,    }, nil}

6、docker-compose减少配置

user/rpc目录下生成rpc的Dockerfile

goctl docker -go user.go

user/api目录下生成api的Dockerfile

goctl docker -go user.go

根目录下docker-compose.yml减少用户服务api和rpc配置

version: '3.5'# 网络配置networks:  backend:    driver: bridge# 服务容器配置services:  etcd:                                  # 自定义容器名称    build:      context: etcd                    # 指定构建应用的 Dockerfile 文件    environment:      - TZ=Asia/Shanghai      - ALLOW_NONE_AUTHENTICATION=yes      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379    ports:                               # 设置端口映射      - "2379:2379"    networks:      - backend    restart: always  etcd-manage:    build:      context: etcd-manage    environment:      - TZ=Asia/Shanghai    ports:      - "7000:8080"                    # 设置容器8080端口映射指定宿主机端口,用于宿主机拜访可视化web    depends_on:                                       # 依赖容器      - etcd                                          # 在 etcd 服务容器启动后启动    networks:      - backend    restart: always  courseware-rpc: # 自定义容器名称    build:      context: courseware                 # 指定构建应用的 Dockerfile 文件      dockerfile: rpc/Dockerfile    environment: # 设置环境变量      - TZ=Asia/Shanghai    privileged: true    ports: # 设置端口映射      - "9400:9400"  # 课件服务rpc端口    stdin_open: true                     # 关上规范输出,能够承受内部输出    tty: true    networks:      - backend    restart: always                      # 指定容器退出后的重启策略为始终重启  courseware-api: # 自定义容器名称    build:      context: courseware                  # 指定构建应用的 Dockerfile 文件      dockerfile: api/Dockerfile    environment: # 设置环境变量      - TZ=Asia/Shanghai    privileged: true    ports: # 设置端口映射      - "8400:8400"  # 课件服务api端口    stdin_open: true                     # 关上规范输出,能够承受内部输出    tty: true    networks:      - backend    restart: always                      # 指定容器退出后的重启策略为始终重启  user-rpc: # 自定义容器名称    build:      context: user                 # 指定构建应用的 Dockerfile 文件      dockerfile: rpc/Dockerfile    environment: # 设置环境变量      - TZ=Asia/Shanghai    privileged: true    ports: # 设置端口映射      - "9300:9300"  # 课件服务rpc端口    stdin_open: true                     # 关上规范输出,能够承受内部输出    tty: true    networks:      - backend    restart: always                      # 指定容器退出后的重启策略为始终重启  user-api: # 自定义容器名称    build:      context: user                  # 指定构建应用的 Dockerfile 文件      dockerfile: api/Dockerfile    environment: # 设置环境变量      - TZ=Asia/Shanghai    privileged: true    ports: # 设置端口映射      - "8300:8300"  # 课件服务api端口    stdin_open: true                     # 关上规范输出,能够承受内部输出    tty: true    networks:      - backend    restart: always                      # 指定容器退出后的重启策略为始终重启

6、运行user服务

user目录下

go mod tidy

到我的项目根目录

docker-compose up -d

7、测试接口

http://localhost:8300/api/user/register{    "loginName": "liuyuede",    "username": "liuyuede",    "sex": 1,    "password": "123"}http://localhost:8300/api/user/login{    "loginName": "liuyuede",    "password": "123"}http://localhost:8300/api/user/userInfo{    "id": 2