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