C++GO语言微服务之用户信息处理
目录
01 01-微服务实现用户注册-微服务端-上
02 02-微服务实现用户注册-微服务端-下
03 03-微服务实现用户注册-web端
04 04-微服务实现用户注册-web端-流程小结
05 05-获取地域信息-读MySQL写Redis入
06 06-获取地域信息-先查redis-没有读MySQL写入
01 07-Cookie简介
02 08-Session简介
03 09-Cookie和Session的对比和生成
04 10-Cookie操作练习
05 11-Session的操作练习-上-初始化容器
06 12-Session的操作练习-下-设置属性获取session
07 13-获取手机号密码登录用户-存入session
08 01-修改GetSession函数,完成用户登录
09 02-用户退出登录
01 01-微服务实现用户注册-微服务端-上
# 微服务实现 注册用户
## 微服务端
1. 修改密码本 —— proto 文件
```go
syntax = "proto3";
package go.micro.srv.user;
service User {
rpc SendSms(Request) returns (Response) {};
rpc Register(RegReq) returns (Response) {}; // 注册用户
}
message RegReq {
string mobile = 1;
string password = 2;
string sms_code = 3;
}
message Request {
string phone = 1;
string imgCode = 2;
string uuid = 3;
}
message Response {
string errno = 1;
string errmsg = 2;
}
```
02 02-微服务实现用户注册-微服务端-下
2. make 编译生成 xxx.micro.go 文件。
3. 修改 service/user/main.go --- 没有需要修改的
4. 修改 handler/user.go
```go
// 添加 方法
func (e *User) Register(ctx context.Context, req *user.RegReq, rsp *user.Response) error {
return nil
}
```
5. 需要操作,MySQL数据库, 拷贝 web/model/model.go 到 微服务项目中。
03 03-微服务实现用户注册-web端
6. 在 service/user/model/modelFunc.go 中 添加 校验短信验证码函数实现
```go
// 校验短信验证码
func CheckSmsCode(phone, code string) error {
// 链接redis
conn := RedisPool.Get()
// 从 redis 中, 根据 key 获取 Value --- 短信验证码 码值
smsCode, err := redis.String(conn.Do("get", phone+"_code"))
if err != nil {
fmt.Println("redis get phone_code err:", err)
return err
}
// 验证码匹配 失败
if smsCode != code {
return errors.New("验证码匹配失败!")
}
// 匹配成功!
return nil
}
04 04-微服务实现用户注册-web端-流程小结
7. service/user/model/modelFunc.go 中, 添加函数RegisterUser, 实现 用户注册信息,写入MySQL数据库
```go
// 注册用户信息,写 MySQL 数据库.
func RegisterUser(mobile, pwd string) error {
var user User
user.Name = mobile // 默认使用手机号作为用户名
// 使用 md5 对 pwd 加密
m5 := md5.New() // 初始md5对象
m5.Write([]byte(pwd)) // 将 pwd 写入缓冲区
pwd_hash := hex.EncodeToString(m5.Sum(nil)) // 不使用额外的秘钥
user.Password_hash = pwd_hash
// 插入数据到MySQL
return GlobalConn.Create(&user).Error
}
```
05 05-获取地域信息-读MySQL写Redis入
8. 完成 Register 函数 实现
```go
func (e *User) Register(ctx context.Context, req *user.RegReq, rsp *user.Response) error {
// 先校验短信验证码,是否正确. redis 中存储短信验证码.
err := model.CheckSmsCode(req.Mobile, req.SmsCode)
if err == nil {
// 如果校验正确. 注册用户. 将数据写入到 MySQL数据库.
err = model.RegisterUser(req.Mobile, req.Password)
if err != nil {
rsp.Errno = utils.RECODE_DBERR
rsp.Errmsg = utils.RecodeText(utils.RECODE_DBERR)
} else {
rsp.Errno = utils.RECODE_OK
rsp.Errmsg = utils.RecodeText(utils.RECODE_OK)
}
} else { // 短信验证码错误
rsp.Errno = utils.RECODE_DATAERR
rsp.Errmsg = utils.RecodeText(utils.RECODE_DATAERR)
}
return nil
}
```
06 06-获取地域信息-先查redis-没有读MySQL写入
## web 端
1. 拷贝密码本 ——proto
2. 创建 web/utils/utils.go 文件, 封装 函数实现 初始 consul 客户端代码
```go
// 初始化micro
func InitMicro() micro.Service {
// 初始化客户端
consulReg := consul.NewRegistry()
return micro.NewService(
micro.Registry(consulReg),
)
}
```
01 07-Cookie简介
3. 实现 web/controller/user.go 中的 PostRet 函数
```go
// 发送注册信息
func PostRet(ctx *gin.Context) {
// 获取数据
var regData struct {
Mobile string `json:"mobile"`
PassWord string `json:"password"`
SmsCode string `json:"sms_code"`
}
ctx.Bind(®Data)
// 初始化consul
microService := utils.InitMicro()
// 初始化客户端
microClient := userMicro.NewUserService("go.micro.srv.user", microService.Client())
// 调用远程函数
resp, err := microClient.Register(context.TODO(), &userMicro.RegReq{
Mobile:regData.Mobile,
SmsCode:regData.SmsCode,
Password:regData.PassWord,
})
if err != nil {
fmt.Println("注册用户, 找不到远程服务!", err)
return
}
// 写给浏览器
ctx.JSON(http.StatusOK, resp)
}
```
02 08-Session简介
4. 测试:
- consul 启动
- getCaptcha 服务启动 --- 12341
- user 服务启动 --- 12342
- web 启动 --- 8080
- 浏览器测试,注册流程。
- 成功:
- 界面跳转。
- 查询 MySQL数据库, 多一条用户信息。
03 09-Cookie和Session的对比和生成
# 获取地域信息
## 导入 SQL脚本
1. 将 home.sql 保存至 Linux 系统。建议放 家目录。
2. 登录 MySQL数据库。选择数据库: use search_house;
3. 执行 source /home/itcast/home.sql —— 运行 脚本文件。向表插入数据。
04 10-Cookie操作练习
## web端实现
1. 在 web/main.go 中,添加路由, 设置回调。
```go
r1.GET("/areas", controller.GetArea)
```
2. 在 web/controller/use.go 中, 添加 GetArea() 函数。
```go
func GetArea(ctx *gin.Context) {
}
```
05 11-Session的操作练习-上-初始化容器
3. 从数据库获取数据,提高用户感受的常见方法:先查缓存, 缓存没有查MySQL, 写入redis缓存。
```go
// 测试实现:
// 获取地域信息
func GetArea(ctx *gin.Context) {
// 先从MySQL中获取数据.
var areas []model.Area
model.GlobalConn.Find(&areas)
// 再把数据写入到 redis 中.
conn := model.RedisPool.Get() // 获取链接
conn.Do("set", "areaData", areas)
resp := make(map[string]interface{})
resp["errno"] = "0"
resp["errmsg"] = utils.RecodeText(utils.RECODE_OK)
resp["data"] = areas
ctx.JSON(http.StatusOK, resp)
}
```
06 12-Session的操作练习-下-设置属性获取session
4. 测试:登录 redis ,指定 --raw 参数,显示中文。
```shell
itcast@ubuntu:~$ redis-cli -h 192.168.6.108 -p 6379 --raw
192.168.6.108:6379> keys *
areaData
hello
itcast
192.168.6.108:6379> get areaData
[{1 东城区 []} {2 西城区 []} {3 朝阳区 []} {4 海淀区 []} {5 昌平区 []} {6 丰台区 []} {7 房山区 []} {8 通州区 []} {9 顺义区 []} {10 大兴区 []} {11 怀柔区 []} {12 平谷区 []} {13 密云区 []} {14 延庆区 []} {15 石景山区 []}]
192.168.6.108:6379>
```
5. 思考:按如上方法存储数据到 Redis 中 `conn.Do("set", "areaData", areas)`, 将来 使用 Do 获取数据时!不好获取!没有对应的 回复助手函数来完成 “类型断言”。 —— 重新选择 存储 redis 的方法: 将 数据转换成 josn 字节流存储。
07 13-获取手机号密码登录用户-存入session

6. 重新实现获取地域信息, 没数据,读MySQL,写redis;有数据,直接读 redis
- 强调:写入 Redis 中的数据 —— 序列化后的字节流数据。
```go
// 获取地域信息
func GetArea(ctx *gin.Context) {
// 先从MySQL中获取数据.
var areas []model.Area
// 从缓存redis 中, 获取数据
conn := model.RedisPool.Get()
// 当初使用 "字节切片" 存入, 现在使用 切片类型接收
areaData, _ := redis.Bytes(conn.Do("get", "areaData"))
// 没有从 Redis 中获取到数据
if len(areaData) == 0 {
fmt.Println("从 MySQL 中 获取数据...")
model.GlobalConn.Find(&areas)
// 把数据写入到 redis 中. , 存储结构体序列化后的 json 串
areaBuf, _ := json.Marshal(areas)
conn.Do("set", "areaData", areaBuf)
} else {
fmt.Println("从 redis 中 获取数据...")
// redis 中有数据
json.Unmarshal(areaData, &areas)
}
resp := make(map[string]interface{})
resp["errno"] = "0"
resp["errmsg"] = utils.RecodeText(utils.RECODE_OK)
resp["data"] = areas
ctx.JSON(http.StatusOK, resp)
}
```
08 01-修改GetSession函数,完成用户登录
7. 测试:
1. GoLand 中 借助输出,看到 展示的数据来源。
# Cookie 和 Session
## Cookie 和 Session简介
- http协议,有 3 个版本:
- http/1.0 版:无状态,短连接。
- http/1.1 版:可以记录状态。—— 默认支持。
- http/2.0 版:可以支持长连接。 协议头:Connection: keep-alive 。
09 02-用户退出登录
### Cookie
- 最早的 http/1.0 版,提供 Cookie 机制, 但是没有 Session。
- Cookie 作用:一定时间内, 存储用户的连接信息。如:用户名、登录时间 ... 不敏感信息。
- Cookie 出身:http自带机制。Session不是!
- Cookie 存储:Cookie 存储在 客户端 (浏览器) 中。—— 浏览器可以存储数据。少
- 存储形式:key - value
- 可以在浏览器中查看。
- Cookie 不安全。直接将数据存储在浏览器上。
### Session
- ”会话“:在一次会话交流中,产生的数据。不是http、浏览器自带。
- Session 作用:一定时间内, 存储用户的连接信息。
- Session 存储:在服务器中。一般为 临时 Session。—— 会话结束 (浏览器关闭) , Session被干掉!
### 对比 Cookie 和 Session
1. Cookie 存储在 浏览器, 在哪生成呢?
2. Session 存储在 服务器,在哪生成呢?
3. 什么时候生成Cookie , 什么时候生成 Session?
