从零开始实现基于go-zero框架的微服务电商项目(二)——User服务的基础搭建

514 阅读5分钟

从零开始实现基于go-zero框架的微服务电商项目(二)——User服务的基础搭建

项目地址liuxianloveqiqi/XianShop: 使用go-zero搭建的电商项目 (github.com)

API

首先在api包下新建user.api文件,我们需要四个接口:

  1. 根据手机号发送验证码
  2. 根据手机号和验证码进行注册/登陆,成功后返回token
  3. 根据手机号/邮箱,密码进行登陆
  4. 查询用户信息

编写user.api文件;

 syntax = "v1"  // 版本号
 ​
 // 接口信息
 info(
   title: "XianShip/user.api"
   author: "liuxian"
   version: "1.0.0"
 )
 type (
   // 手机号注册/登陆
   RegisterReq {
     UserPhone string `json:"userPhone"`
     VeCode    string `json:"veCode"`
   }
   RegisterByPhoneRep {
     UserPhone string `json:"userPhone"`
   }
   LoginReq {
     PhoneOrEmail string `json:"phoneOrEmail"` // 手机号或者邮箱
     PassWord     string `json:"PassWord"`     // 用户密码,MD5加密
   }
 ​
   userInfoReq {
     UserId int64 `json:"userId"` // 用户id
   }
 ​
   UserInfoResply {
     Code    int64         `json:"Code"`
     Message string        `json:"Message"`
     Data    *UserInfoItem `json:"Data"`
   }
   RegisterByPhoneResply {
     Code    int64  `json:"Code"`
     Message string `json:"Message"`
     VeCode  string `json:"veCode"`
   }
   UserInfoItem {
     UserID    int64  `json:"userId"`    // 用户id
     UserNick  string `json:"UserNick"`  // 用户昵称
     UserFace  string `json:"UserFace"`  // 用户头像地址
     UserSex   int64  `json:"UserSex"`   // 用户性别:0男,1女,2保密
     UserEmail string `json:"UserEmail"` // 用户邮箱
     UserPhone string `json:"UserPhone"` // 用户手机号
   }
   CommonResply {
     Code    int64  `json:"Code"`
     Message string `json:"Message"`
     Data    string `json:"Data"`
   }
   TokenResply {
     Code         int64  `json:"Code"`
     Message      string `json:"Message"`
     AccessToken  string `json:"accessToken"`
     RefreshToken string `json:"refreshToken"`
   }
 )
 ​
 @server(
   prefix: account
 )
 ​
 service user-api {
   @doc(
     summary: "发验证码"
   )
   @handler Sendcode
   post /sendcode (RegisterByPhoneRep) returns (RegisterByPhoneResply)
   @doc(
     summary: "用户验证码形式注册/登陆"
   )
   @handler Register
   post /register (RegisterReq) returns (TokenResply)
   @doc(
     summary: "用户密码形式登录"
   )
   @handler Login
   post /login (LoginReq) returns (TokenResply)
 }
 ​
 @server(
   middleware: JWT // 路由中间件声明
 )
 ​
 service user-api {
   @doc(
     summary: "用户信息"
   )
   @handler userInfo
   post /userinfo (userInfoReq) returns (UserInfoResply)
 }

cd到 user/api文件下:输入$ goctl api go -api user.api -dir .

再修改etc下的user-api.yaml文件:

 # user 模块配置
 Name: user-api
 Host: 0.0.0.0
 Port: 4000
 # mysql配置
 Mysql:
   DataSource: root:root@(127.0.0.1:3306)/xian-shop?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai
 # redis 配置
 CacheRedis:
   - Host: 127.0.0.1:6379
     Pass:
     Type: node
 Rpc:
   Etcd:
     Hosts:
       - 127.0.0.1:2379
     Key: user.rpc

修改config.go文件:

 package config
 ​
 import (
   "github.com/zeromicro/go-zero/core/stores/cache"
   "github.com/zeromicro/go-zero/rest"
   "github.com/zeromicro/go-zero/zrpc"
 )
 ​
 type Config struct {
   rest.RestConf
   Mysql struct {
     DataSource string
   }
   CacheRedis cache.CacheConf
   Rpc        zrpc.RpcClientConf
 }
 ​

config.go文件里面的东西在logic层进行业务处理的时候都可以调用,这里我们就把mysql,redis写进去

修改svc文件夹下的servicecontext.go

 package svc
 ​
 import (
   "XianShop/service/common"
   "XianShop/service/user/api/internal/config"
   "XianShop/service/user/model"
   "XianShop/service/user/rpc/userclient"
   "github.com/zeromicro/go-zero/core/stores/sqlx"
   "github.com/zeromicro/go-zero/zrpc"
   "gorm.io/gorm"
 )
 ​
 type ServiceContext struct {
   Config    config.Config
   DbEngine  *gorm.DB
   UserModel model.UserModel
   Rpc       userclient.User
 }
 ​
 func NewServiceContext(c config.Config) *ServiceContext {
   coon := sqlx.NewMysql(c.Mysql.DataSource)
   db := common.InitGorm(c.Mysql.DataSource)
   db.AutoMigrate(&model.User{})
   return &ServiceContext{
     Config:    c,
     UserModel: model.NewUserModel(coon, c.CacheRedis),
     Rpc:       userclient.NewUser(zrpc.MustNewClient(c.Rpc)),
     DbEngine:  db,
   }
 }
 ​

就是在ServiceContext结构体里面,把上一步Config里面的字段添加进去,这里我加入了gorm,这个我将在下一章讲到gorm的加入和初始化,这里最后我们要返回是ServiceContext 这个结构体。

Model

在model文件夹下,建一个user.sql文件:

 CREATE TABLE `user`
 (
     `id`           bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',
     `passWord`     varchar(50)     NOT NULL DEFAULT null COMMENT '用户密码,MD5加密',
     `user_Nick`     varchar(100)    NOT NULL DEFAULT NULL COMMENT '用户昵称',
     `user_Face`     varchar(255)    NOT NULL DEFAULT NULL COMMENT '用户头像地址',
     `User_Sex`      tinyint(1)      NOT NULL DEFAULT null COMMENT '用户性别:0男,1女,2保密',
     `user_Email`    varchar(255)    NOT NULL DEFAULT NULL COMMENT '用户邮箱',
     `user_Phone`    varchar(20)     NOT NULL DEFAULT NULL COMMENT '手机号',
     `login_Address` varchar(255)    NOT NULL DEFAULT NULL COMMENT '用户登录IP地址',
     `create_time`  timestamp       NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
     `update_time`  timestamp       NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
     PRIMARY KEY (`id`),
     KEY `userPhone` (`user_Phone`)
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8mb4 COMMENT ='用户表';
 ​

*注意的是!*这里有个坑,如果你使用gorm的话,你的字段名应以下划线的形式,但是go-zero官方的数据库操作是驼峰命名,所以你如果使用gorm就要用下划线的形式命名字段,不然到时候你gorm操作不了。

然后cd 到mdel,终端输入:goctl model mysql ddl -src user.sql -dir . -c

这个时候你就会看到你model下多了一些文件,我们接下来的进行mysql的操作将在usermodel.go文件里面,注意:usermodel_gen文件最好不要动,因为你后续加入新的业务修改表的时候,再次goctl,usermodel_gen里面的内容会被初始化,你要是之前在这里面写逻辑你就白写了,所以后续是在usermodel.go文件里面添加,下面有例子:

image-20230427094743729.png

在UserModel这个空接口里面填逻辑,比如我这里就是FindUserby,也是在usermodel里面实现你的逻辑

RPC

首先新建一个user.proto文件:

 syntax = "proto3";
 ​
 package user;
 ​
 option go_package = "./user";
 ​
 message SendCodeRep{
   string UserPhone = 1;
 ​
 }
 message RegisterReq{
   string UserPhone = 1;
   string VeCode = 2;
 }
 ​
 message LoginReq{
   string PhoneOrEmail = 1;
   string PassWord = 2;
 }
 message SendCodeReply{
   string VeCode = 1;
 ​
 }
 message CommonReply{
   int64 Code = 1;
   string Message = 2;
   string Data = 3;
   int64 UserId = 4;
 }
 ​
 message UserInfoReq{
   string UserIdentity = 1;
 }
 ​
 service user{
   rpc SendCode(SendCodeRep) returns (SendCodeReply);
   rpc Register(RegisterReq) returns(CommonReply);
   rpc Login(LoginReq) returns(CommonReply);
   rpc UserInfo(UserInfoReq) returns (CommonReply);
 ​
 }

这里我写的有点粗糙,我后面改一下,先这样用着,然后cd到rpc下输入:

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

 Name: user.rpc
 ListenOn: 0.0.0.0:8080
 Etcd:
   Hosts:
   - 127.0.0.1:2379
   Key: user.rpc
 # mysql配置
 Mysql:
   DataSource: root:root@(127.0.0.1:3306)/xian-shop?charset=utf8mb4&parseTime=True&loc=Asia%2FShanghai
 # redis 配置
 CacheRedis:
   - Host: 127.0.0.1:6379
     Pass:
     Type: node
 
 # redis配置
 Redis:
   Host: 127.0.0.1:6379
   Pass:
   DB: 0
 
 
 # 腾讯云 SMS 配置
 Credential:
   SecretId: XXXXXXXX #你自己的
   SecretKey: XXXXXXX #你自己的

这里我们外接腾讯呀SMS服务实现短信验证,我也会在后面的章节介绍

同样,按照api的做法,把config,svc文件配好

config:

 package config
 ​
 import (
   "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
   Redis      struct {
     Host string
     Pass string
     DB   int
   }
   Credential struct {
     SecretId  string
     SecretKey string
   }
 }
 ​

Svc:

package svc

import (
	"XianShop/service/common"
	"XianShop/service/user/model"
	"XianShop/service/user/rpc/internal/config"
	"github.com/redis/go-redis/v9"

	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"gorm.io/gorm"
)

type ServiceContext struct {
	Config    config.Config
	UserModel model.UserModel
	Rdb       *redis.Client
	DbEngine  *gorm.DB
}

func NewServiceContext(c config.Config) *ServiceContext {
	coon := sqlx.NewMysql(c.Mysql.DataSource)
	db := common.InitGorm(c.Mysql.DataSource)
	rdb := common.InitRedis(c.Redis.Host, c.Redis.Pass, c.Redis.DB)
	db.AutoMigrate(&model.User{})
	return &ServiceContext{
		Config:    c,
		UserModel: model.NewUserModel(coon, c.CacheRedis),
		Rdb:       rdb,
		DbEngine:  db,
	}
}

这里我配了redis实现验证码的缓存,也会在后面章节介绍

总结

这一章实现了user服务的api, model,rpc的基础配置,下一章将开始实现gorm,redis,腾讯云SMS,validate校验数据格式,md5加密的配置

感谢

如果你觉得我的文章对你有帮忙,欢迎点赞,关注,star!有问题可以在评论区直接提出来,感谢大家的阅读!🥰🥰🥰🥰🥰🥰