用户注册
获取数据/绑定数据
- 前端传递数据种类:
-
form表单:数据为 form data
-
ajax: 数据为 json 格式。 体现成 —— Request Payload
-
- 默认 postForm() 方法 只能获取 form 表单传递的数据。
- 针对 Request Payload 数据形式,需要 使用 “数据绑定“ 来获取传递的数据。
ctx.Bind()将 数据绑定到对象中。
-- web/main.go 中 添加
r1.POST("/users", controller.PostRet)
-- web/controller/user.go 中添加、实现
// 发送注册信息
func PostRet(ctx *gin.Context) {
/* mobile := ctx.PostForm("mobile")
pwd := ctx.PostForm("password")
sms_code := ctx.PostForm("sms_code")
fmt.Println("m = ", mobile, "pwd = ", pwd, "sms_code = ",sms_code)
*/
// 获取数据
var regData struct {
Mobile string `json:"mobile"`
PassWord string `json:"password"`
SmsCode string `json:"sms_code"`
}
ctx.Bind(®Data)
fmt.Println("获取到的数据为:", regData)
}
微服务端
-
修改密码本 —— proto 文件
syntax = "proto3"; package go.micro.srv.user; service User { rpc SendSms(Request) returns (Response) {}; rpc Register(RegRequest) returns (Response) {}; } message Request { string phone = 1; string imgCode = 2; string uuid = 3; } message RegRequest { string mobile = 1; string password = 2; string smsCode = 3; } message Response { string errno = 1; string errmsg = 2; } -
make 编译生成 xxx.micro.go 文件
-
修改 handler/user.go
// 添加 方法 func (e *User) Register(ctx context.Context, req *user.RegRequest, rsp *user.Response) error { return nil } -
需要操作MySQL数据库,拷贝 web/model/model.go 到微服务项目中。
-
在 service/user/model/modelFunc.go 中添加校验短信验证码函数实现
// CheckSmsCode 校验短信验证码 func CheckSmsCode(mobile, smsCode string) bool { // 连接redis conn := RedisPool.Get() defer conn.Close() // 查询数据 code, err := redis.String(conn.Do("get", mobile+"_code")) if err != nil { fmt.Println("redis查询错误:", err) return false } return smsCode == code } -
service/user/model/modelFunc.go 中, 添加函数 SaveUserInfo,实现用户注册信息,写入MySQL数据库
// SaveUserInfo 存储用户信息到user表 func SaveUserInfo(mobile, password string) error { var newUser User // 如果手机号不存在,则注册新用户 if GlobalConn.Where("mobile = ?", mobile).Find(&newUser).RecordNotFound() { newUser.Name = mobile newUser.Mobile = mobile // 使用md5对password加密 m5 := md5.New() m5.Write([]byte(password)) pwdHash := hex.EncodeToString(m5.Sum(nil)) newUser.Password_hash = pwdHash return GlobalConn.Create(&newUser).Error } // 如果手机号已存在,则注册失败 return errors.New("手机号已存在") } -
完成 Register 函数实现
// Register 用户注册 func (e *User) Register(ctx context.Context, req *user.RegRequest, rsp *user.Response) error { // 校验验证码 -- 从redis中获取验证码,进行比对 result := model.CheckSmsCode(req.Mobile, req.SmsCode) // 由于获取验证码服务有问题,这里指定result为true来测试 result = true if result { // 验证码比对成功 // 存储用户信息到mysql数据库 err := model.SaveUserInfo(req.Mobile, req.Password) if err != nil { fmt.Println("存储用户信息错误:", err) 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 { // 验证码比对失败 fmt.Println("验证码比对错误") rsp.Errno = utils.RECODE_DATAERR rsp.Errmsg = utils.RecodeText(utils.RECODE_DATAERR) } return nil }
Web端
-
拷贝密码本 ——proto
-
创建 web/utils/utils.go 文件,封装函数实现初始 consul 客户端代码
// 初始化micro func InitMicro() micro.Service { // 初始化客户端 consulReg := consul.NewRegistry() return micro.NewService( micro.Registry(consulReg), ) } -
实现 web/controller/user.go 中的 PostRet 函数
// PostRet 发送注册信息 func PostRet(ctx *gin.Context) { // 获取数据 var regData struct { Mobile string `json:"mobile"` Password string `json:"password"` SmsCode string `json:"sms_code"` } ctx.Bind(®Data) // 调用远程函数 microClient := userMicro.NewUserService("go.micro.srv.user", client.DefaultClient) resp, err := microClient.Register(context.TODO(), &userMicro.RegRequest{Mobile: regData.Mobile, Password: regData.Password, SmsCode: regData.SmsCode}) if err != nil { fmt.Println("调用远程函数Register失败:", err) return } // 发送给浏览器 ctx.JSON(http.StatusOK, resp) }
获取地域信息
接口定义
#Request:
method: GET
url:api/v1.0/areas
#data:
no input data
#Response
#返回成功:
{
"errno": "0",
"errmsg":"OK",
"data": [
{"aid": 1, "aname": "东城区"},
{"aid": 2, "aname": "西城区"},
{"aid": 3, "aname": "通州区"},
{"aid": 4, "aname": "顺义区"}]
//...
}
#注册失败:
{
"errno": "400x", //状态码
"errmsg":"状态错误信息"
}
业务流程图
导入sql脚本
- 将 home.sql 保存至 Linux 系统
- 登录MySQL数据库。选择数据库:
use search_house; - 运行脚本文件,向表插入数据。
source /Users/yaxuan/home.sql
Web端
-
在 web/main.go 中,添加路由,设置回调。
r1.GET("/areas", controller.GetArea) -
在 web/controller/use.go 中,添加 GetArea() 函数。
func GetArea(ctx *gin.Context) { } -
从数据库获取数据,提高用户感受的常见方法:先查缓存,缓存没有查MySQL,写入redis缓存。
// 获取地域信息 func GetArea(ctx *gin.Context) { // 先从MySQL中获取数据. var areas []model.Area model.GlobalConn.Find(&areas) // 再把数据写入到 redis 中. conn := model.RedisPool.Get() conn.Do("set", "areaData", areas) //这里直接将areas数组存入redis resp := make(map[string]interface{}) resp["errno"] = "0" resp["errmsg"] = utils.RecodeText(utils.RECODE_OK) resp["data"] = areas ctx.JSON(http.StatusOK, resp) }思考:按如上方法存储数据到 Redis 中
conn.Do("set", "areaData", areas), 将来使用 Do 获取数据时!不好获取!没有对应的回复助手函数来完成“类型断言”。 —— 重新选择存储 redis 的方法: 将数据转换成 josn 字节流存储。// GetArea 获取地域信息 func GetArea(ctx *gin.Context) { // 先从redis获取数据 conn := model.RedisPool.Get() areaData, _ := redis.Bytes(conn.Do("get", "areaData")) var areas []model.Area if len(areaData) == 0 { // redis中没有数据 // 从mysql中获取数据 model.GlobalConn.Find(&areas) // 将数据写入redis -- 存储结构体序列化后的json串 areaBuf, _ := json.Marshal(areas) conn.Do("set", "areaData", areaBuf) } else { // redis中有数据 json.Unmarshal(areaData, &areas) } resp := make(map[string]interface{}) resp["errno"] = utils.RECODE_OK resp["errmsg"] = utils.RecodeText(utils.RECODE_OK) resp["data"] = areas ctx.JSON(http.StatusOK, resp) }