功能和背景介绍

用户数据结构体定义

在项目中,使用结构体定义用户数据结构。结构体定义如下所示:

type Member struct {
	Id           int64   `xorm:"pk autoincr" json:"id"`
	UserName     string  `xorm:"varchar(20)" json:"user_name"`
	Mobile       string  `xorm:"varchar(11)" json:"mobile"`
	Password     string  `xorm:"varchar(255)" json:"password"`
	RegisterTime int64   `xorm:"bigint" json:"register_time"`
	Avatar       string  `xorm:"varchar(255)" json:"avatar"`
	Balance      float64 `xorm:"double" json:"balance"`
	IsActive     int8    `xorm:"tinyint" json:"is_active"`
	City         string  `xorm:"varchar(10)" json:"city"`
}

通过定义Member结构体,表示应用的用户信息。通过TAG中的xorm来指定结构体在数据库表中的约束。

ORM映射

通过engine.Sync2方法将Member同步映射成为数据库中的member表:

err = engine.Sync2(new(model.Member),
		new(model.SmsCode))
if err != nil {
    return nil,err
}

插入数据

当用户获取完验证码,并填写验证码以后,用户点击登录,会发起登录请求。因此,我们需要来完成登录相关的逻辑操作和处理。用户手机号码和验证码登录的接口是api/login_sms,因此我们在已经创建的MemberController中解析短信验证码接口。如下所示:

func (mc *MemberController) Router(engine *gin.Engine) {
    ...
    //发送手机验证码
	engine.GET("/api/sendcode", mc.sendSmsCode)
	//手机号和短信登录
	engine.OPTIONS("/api/login_sms", mc.smsLogin)
}

在MemberController中创建smsLogin方法完成用户手机号和密码登录的逻辑,详细实现如下:

//短信登录
func (mc *MemberController) smsLogin(context *gin.Context) {

	var smsParam param.SmsLoginParam
	err := toolbox.Decode(context.Request.Body, &smsParam)

	fmt.Println(err.Error())

	fmt.Println(context.PostForm("phone"))
	fmt.Println(context.Query("code"))
	if err != nil {
		toolbox.Failed(context, "参数解析错误")
		return
	}

	us := service.NewMemberService()
	member := us.SmsLogin(smsParam)
	if member != nil {
		toolbox.Success(context, member)
		return
	}
	toolbox.Failed(context, "登录失败")
}

用户服务层

在MemberService.go文件中,编写SmsLogin方法完成手机号和密码登录。

func (msi *MemberService) SmsLogin(param param.SmsLoginParam) *model.Member {

	dao := dao.NewMemberDao()
	sms := dao.ValidateSmsCode(param.Phone, param.Code)

	if sms == nil || time.Now().Unix()-sms.CreateTime > 300 {
		return nil
	}

	member := dao.QueryByPhone(param.Phone)
	if member != nil {
		return member
	}

	user := model.Member{}
	user.UserName = param.Phone
	user.Mobile = param.Phone
	user.RegisterTime = time.Now().Unix()

	user.Id = dao.InsertMember(user)
	return &user
}

在MemberService中,首先验证手机号和验证码是否正确。如果通过了手机号和验证码的验证,通过手机号查询用户是否已经存在。如果用户记录不存在,则创建新的用户记录并保存到数据库中,如果用户记录已经存在,则表示登录成功,返回用户信息。

数据库操作的MemberDao实现如下

在MemberDao中,实现用户模块的数据库操作。
首先是手机验证码验证功能,如下所示:

func (md *MemberDao) ValidateSmsCode(phone string, code string) *model.SmsCode {
	var sms model.SmsCode

	if err := md.Where(" phone = ? and code = ? ", phone, code).Find(&sms); err != nil {
		toolbox.Error(err.Error())
	}
	return &sms
}

其次是根据手机号查询用户数据库表中是否存在手机号对应的用户,如下所示:

func (md *MemberDao) QueryByPhone(phone string) *model.Member {
	var member model.Member

	if err := md.Where(" phone = ? ", phone).Find(&member); err != nil {
		toolbox.Error(err.Error())
	}
	return &member
}

最后,对于新手机号,新建用户,插入到数据库中:

func (md *MemberDao) InsertMember(member model.Member) int64 {
	result, err := md.InsertOne(&member)
	if err != nil {
		toolbox.Error(err.Error())
	}
	return result
}

跨域

npm run dev

03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)-LMLPHP

跨域访问的问题
/*
	* 1、通信协议:又称protocol,有很多通信协议,比如http,					tcp/ip协议等等。
	* 2、主机:也就是常说的host。
	* 3、端口:即服务所监听的端口号。
	* 4、资源路径:端口号后面的内容即是路径。
*/
OPTIONS请求
服务端设置跨域访问
func Cors() gin.HandlerFunc {
	return func(context *gin.Context) {
		method := context.Request.Method
		origin := context.Request.Header.Get("Origin")
		var headerKeys []string
		for k, _ := range context.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ",")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}

		if origin != "" {
			context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
			context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
			context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
			context.Header("Access-Control-Max-Age", "172800")
			context.Header("Access-Control-Allow-Credentials", "false")
			context.Set("content-type", "application/json") //// 设置返回格式是json
		}

		if method == "OPTIONS" {
			context.JSON(http.StatusOK, "Options Request!")
		}
		//处理请求
		context.Next()
	}
}
服务器设置跨域调用
func main(){
    ...
    app := gin.Default()
    app.Use(Cors())
    ...
}

/*
		调用app.Use方法,设置跨域访问
*/
功能演示

03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)-LMLPHP

11-03 00:47
查看更多