1 生成模型

(1) 由sql脚本生成go模型

  1. CREATE TABLE `user` (
  2. `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  3. `name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户姓名',
  4. `gender` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '用户性别',
  5. `mobile` varchar(255) NOT NULL DEFAULT '' COMMENT '用户电话',
  6. `password` varchar(255) NOT NULL DEFAULT '' COMMENT '用户密码',
  7. `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  8. `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  9. PRIMARY KEY (`id`),
  10. UNIQUE KEY `idx_mobile_unique` (`mobile`)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

goctl model mysql ddl -src ./model/user.sql -dir ./model -c

(2) 由数据库生成go模型

goctl model mysql datasource —url “root:password@tcp(127.0.0.1:3306)/database” -dir ./model

2 api生成go文件

(1) 编写api文件

  1. type (
  2. // 用户登录
  3. LoginRequest {
  4. Mobile string `json:"mobile"`
  5. Password string `json:"password"`
  6. }
  7. LoginResponse {
  8. AccessToken string `json:"accessToken"`
  9. AccessExpire int64 `json:"accessExpire"`
  10. }
  11. // 用户登录
  12. // 用户注册
  13. RegisterRequest {
  14. Name string `json:"name"`
  15. Gender int64 `json:"gender"`
  16. Mobile string `json:"mobile"`
  17. Password string `json:"password"`
  18. }
  19. RegisterResponse {
  20. Id int64 `json:"id"`
  21. Name string `json:"name"`
  22. Gender int64 `json:"gender"`
  23. Mobile string `json:"mobile"`
  24. }
  25. // 用户注册
  26. // 用户信息
  27. UserInfoResponse {
  28. Id int64 `json:"id"`
  29. Name string `json:"name"`
  30. Gender int64 `json:"gender"`
  31. Mobile string `json:"mobile"`
  32. }
  33. // 用户信息
  34. )
  35. service User {
  36. @handler Login
  37. post /api/user/login(LoginRequest) returns (LoginResponse)
  38. @handler Register
  39. post /api/user/register(RegisterRequest) returns (RegisterResponse)
  40. }
  41. @server(
  42. jwt: Auth
  43. )
  44. service User {
  45. @handler UserInfo
  46. post /api/user/userinfo returns (UserInfoResponse)
  47. }

(2) 根据api生成go代码

goctl api go -api ./api/user.api -dir ./api

3 proto生成go文件

(1) 编写proto文件

  1. syntax = "proto3";
  2. package userclient;
  3. option go_package = "./user";
  4. // 用户登录
  5. message LoginRequest {
  6. string Mobile = 1;
  7. string Password = 2;
  8. }
  9. message LoginResponse {
  10. int64 Id = 1;
  11. string Name = 2;
  12. int64 Gender = 3;
  13. string Mobile = 4;
  14. }
  15. // 用户登录
  16. // 用户注册
  17. message RegisterRequest {
  18. string Name = 1;
  19. int64 Gender = 2;
  20. string Mobile = 3;
  21. string Password = 4;
  22. }
  23. message RegisterResponse {
  24. int64 Id = 1;
  25. string Name = 2;
  26. int64 Gender = 3;
  27. string Mobile = 4;
  28. }
  29. // 用户注册
  30. // 用户信息
  31. message UserInfoRequest {
  32. int64 Id = 1;
  33. }
  34. message UserInfoResponse {
  35. int64 Id = 1;
  36. string Name = 2;
  37. int64 Gender = 3;
  38. string Mobile = 4;
  39. }
  40. // 用户信息
  41. service User {
  42. rpc Login(LoginRequest) returns(LoginResponse);
  43. rpc Register(RegisterRequest) returns(RegisterResponse);
  44. rpc UserInfo(UserInfoRequest) returns(UserInfoResponse);
  45. }

(2) 根据proto生成go代码

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

4 编写rpc服务

(1) 修改配置文件

rpc/etc/user.yaml

  1. Name: user.rpc
  2. ListenOn: 0.0.0.0:9000
  3. Etcd:
  4. Hosts:
  5. - etcd:2379
  6. Key: user.rpc
  7. Mysql:
  8. DataSource: root:123456@tcp(mysql:3306)/mall?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
  9. CacheRedis:
  10. - Host: redis:6379
  11. Type: node

(2) 添加 model 依赖

vim rpc/internal/config/config.go

  1. package config
  2. import (
  3. "github.com/zeromicro/go-zero/core/stores/cache"
  4. "github.com/zeromicro/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. zrpc.RpcServerConf
  8. Mysql struct {
  9. DataSource string
  10. }
  11. CacheRedis cache.CacheConf
  12. }

vim rpc/internal/svc/servicecontext.go

  1. package svc
  2. import (
  3. "mall/service/user/model"
  4. "mall/service/user/rpc/internal/config"
  5. "github.com/zeromicro/go-zero/core/stores/sqlx"
  6. )
  7. type ServiceContext struct {
  8. Config config.Config
  9. UserModel model.UserModel
  10. }
  11. func NewServiceContext(c config.Config) *ServiceContext {
  12. conn := sqlx.NewMysql(c.Mysql.DataSource)
  13. return &ServiceContext{
  14. Config: c,
  15. UserModel: model.NewUserModel(conn, c.CacheRedis),
  16. }
  17. }

(3) 添加业务逻辑

1) 添加工具库

vim common/cryptx/crypt.go

  1. package cryptx
  2. import (
  3. "fmt"
  4. "golang.org/x/crypto/scrypt"
  5. )
  6. func PasswordEncrypt(salt, password string) string {
  7. dk, _ := scrypt.Key([]byte(password), []byte(salt), 32768, 8, 1, 32)
  8. return fmt.Sprintf("%x", string(dk))
  9. }

2) 添加配置信息

vim rpc/etc/user.yaml

  1. Name: user.rpc
  2. ListenOn: 0.0.0.0:9000
  3. ...
  4. Salt: HWVOFkGgPTryzICwd7qnJaZR9KQ2i8xe

vim rpc/internal/config/config.go

  1. package config
  2. import (
  3. "github.com/zeromicro/go-zero/core/stores/cache"
  4. "github.com/zeromicro/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. ...
  8. Salt string
  9. }

3) 添加逻辑

vim rpc/internal/logic/registerlogic.go

  1. package logic
  2. import (
  3. "context"
  4. "mall/common/cryptx"
  5. "mall/service/user/model"
  6. "mall/service/user/rpc/internal/svc"
  7. "mall/service/user/rpc/user"
  8. "github.com/zeromicro/go-zero/core/logx"
  9. "google.golang.org/grpc/status"
  10. )
  11. type RegisterLogic struct {
  12. ctx context.Context
  13. svcCtx *svc.ServiceContext
  14. logx.Logger
  15. }
  16. func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic {
  17. return &RegisterLogic{
  18. ctx: ctx,
  19. svcCtx: svcCtx,
  20. Logger: logx.WithContext(ctx),
  21. }
  22. }
  23. func (l *RegisterLogic) Register(in *user.RegisterRequest) (*user.RegisterResponse, error) {
  24. // 判断手机号是否已经注册
  25. _, err := l.svcCtx.UserModel.FindOneByMobile(in.Mobile)
  26. if err == nil {
  27. return nil, status.Error(100, "该用户已存在")
  28. }
  29. if err == model.ErrNotFound {
  30. newUser := model.User{
  31. Name: in.Name,
  32. Gender: in.Gender,
  33. Mobile: in.Mobile,
  34. Password: cryptx.PasswordEncrypt(l.svcCtx.Config.Salt, in.Password),
  35. }
  36. res, err := l.svcCtx.UserModel.Insert(&newUser)
  37. if err != nil {
  38. return nil, status.Error(500, err.Error())
  39. }
  40. newUser.Id, err = res.LastInsertId()
  41. if err != nil {
  42. return nil, status.Error(500, err.Error())
  43. }
  44. return &user.RegisterResponse{
  45. Id: newUser.Id,
  46. Name: newUser.Name,
  47. Gender: newUser.Gender,
  48. Mobile: newUser.Mobile,
  49. }, nil
  50. }
  51. return nil, status.Error(500, err.Error())
  52. }

6 编写api服务

(1) 修改配置文件

vim api/etc/user.yaml

  1. Name: User
  2. Host: 0.0.0.0
  3. Port: 8000
  4. ...
  5. Auth:
  6. AccessSecret: uOvKLmVfztaXGpNYd4Z0I1SiT7MweJhl
  7. AccessExpire: 86400
  8. UserRpc:
  9. Etcd:
  10. Hosts:
  11. - etcd:2379
  12. Key: user.rpc

(2) 添加 rpc依赖

vim api/internal/config/config.go

  1. package config
  2. import (
  3. "github.com/zeromicro/go-zero/rest"
  4. "github.com/zeromicro/go-zero/zrpc"
  5. )
  6. type Config struct {
  7. rest.RestConf
  8. Auth struct {
  9. AccessSecret string
  10. AccessExpire int64
  11. }
  12. UserRpc zrpc.RpcClientConf
  13. }

vim api/internal/svc/servicecontext.go

  1. package svc
  2. import (
  3. "mall/service/user/api/internal/config"
  4. "mall/service/user/rpc/userclient"
  5. "github.com/zeromicro/go-zero/zrpc"
  6. )
  7. type ServiceContext struct {
  8. Config config.Config
  9. UserRpc userclient.User
  10. }
  11. func NewServiceContext(c config.Config) *ServiceContext {
  12. return &ServiceContext{
  13. Config: c,
  14. UserRpc: userclient.NewUser(zrpc.MustNewClient(c.UserRpc)),
  15. }
  16. }

(3) 添加业务逻辑

vim api/internal/logic/registerlogic.go

  1. package logic
  2. import (
  3. "context"
  4. "mall/service/user/api/internal/svc"
  5. "mall/service/user/api/internal/types"
  6. "mall/service/user/rpc/userclient"
  7. "github.com/zeromicro/go-zero/core/logx"
  8. )
  9. type RegisterLogic struct {
  10. logx.Logger
  11. ctx context.Context
  12. svcCtx *svc.ServiceContext
  13. }
  14. func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) RegisterLogic {
  15. return RegisterLogic{
  16. Logger: logx.WithContext(ctx),
  17. ctx: ctx,
  18. svcCtx: svcCtx,
  19. }
  20. }
  21. func (l *RegisterLogic) Register(req types.RegisterRequest) (resp *types.RegisterResponse, err error) {
  22. res, err := l.svcCtx.UserRpc.Register(l.ctx, &userclient.RegisterRequest{
  23. Name: req.Name,
  24. Gender: req.Gender,
  25. Mobile: req.Mobile,
  26. Password: req.Password,
  27. })
  28. if err != nil {
  29. return nil, err
  30. }
  31. return &types.RegisterResponse{
  32. Id: res.Id,
  33. Name: res.Name,
  34. Gender: res.Gender,
  35. Mobile: res.Mobile,
  36. }, nil
  37. }

7 启动服务

(1) 启动rpc服务

$ cd mall/service/user/rpc $ go run user.go -f etc/user.yaml Starting rpc server at 127.0.0.1:9000…

(2) 启动api服务

$ cd mall/service/user/api $ go run user.go -f etc/user.yaml Starting server at 0.0.0.0:8000…