从零开始实现基于go-zero框架的微服务电商项目(二)——User服务的基础搭建
项目地址:liuxianloveqiqi/XianShop: 使用go-zero搭建的电商项目 (github.com)
API
首先在api包下新建user.api文件,我们需要四个接口:
- 根据手机号发送验证码
- 根据手机号和验证码进行注册/登陆,成功后返回token
- 根据手机号/邮箱,密码进行登陆
- 查询用户信息
编写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 ='用户表';
然后cd 到mdel,终端输入:goctl model mysql ddl -src user.sql -dir . -c
这个时候你就会看到你model下多了一些文件,我们接下来的进行mysql的操作将在usermodel.go文件里面,注意:usermodel_gen文件最好不要动,因为你后续加入新的业务修改表的时候,再次goctl,usermodel_gen里面的内容会被初始化,你要是之前在这里面写逻辑你就白写了,所以后续是在usermodel.go文件里面添加,下面有例子:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQ10ehVv-1682646052261)(/Users/liuxian/Pictures/typora图片/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!有问题可以在评论区直接提出来,感谢大家的阅读!🥰🥰🥰🥰🥰🥰