手摸手,带你用Beego撸商城系列二(登录篇)

完整项目地址: go-shop-b2c

系列文章:

前言

一个商城后端系统,登录尤其重要,首先用户下单,需要登录,后台管理系统,需要登录。我们需要做的是,除了登录以及注册,其余的接口需要进行登录校验。

base_controller 封装

由于我们需要进行登录校验和不进行登录校验的 Controller,又由于 base_controller 需要进行登录检验,同时,不需要登录校验的 Controllerbase_controller有共同的函数需要调用

综上所述,我们应该额外增加一个 Controller 分别用于 base_controller 继承 和 不需要登录检验的 Controller 用于继承

下面就简单地介绍一下 json_controller

json_controller

type JsonController struct {
	beego.Controller
}
  • JsonResult 返回给前端JSON数据,公共调用函数
/**
 * Ajax接口返回Json
 */
func (c *JsonController) JsonResult(status int, errCode int, errMsg string, data ...interface{}) {
	jsonData := make(map[string]interface{}, 3)
	jsonData["err_code"] = errCode
	jsonData["message"] = errMsg

	if len(data) > 0 && data[0] != nil {
		jsonData["data"] = data[0]
	}
	c.Ctx.Output.SetStatus(status)
	c.Data["json"] = jsonData
	c.ServeJSON()
}
  • ServerError 服务器通用报错
/**
 * 服务器报错
 */
func (c *JsonController) ServerError(err error) {
	c.Ctx.Output.SetStatus(http.GetHttpStatusByAlias("internalServerError"))
	logs.Error(err)
}
  • SetSessionUser 封装保存session的函数
/**
 * 设置登录登录用户session信息
 */
func (c *JsonController) SetSessionUser(member models.Member) {
	if member.Id <= 0 {
		c.DelSession(common.SessionName)
		c.DelSession("uid")
		c.DestroySession()
	} else {
		c.SetSession(common.SessionName, member)
		c.SetSession("uid", member.Id)
	}
}

登录检验

在 beego 的 Prepare 函数调用

简单说一下Prepare函数的作用,这个函数主要是为了用户扩展用的,这个函数会在下面定义的这些 Method 方法之前执行,用户可以重写这个函数实现类似用户验证之类。点击跳转文档查看方法

主要做三件事

  1. gob 序列化保存用户信息
    ps: 序列化某个对象,必须在 encoding/gob 编码解码前进行注册

  2. session 中获取用户信息

  3. 如果 Cookie 中存在登录信息,从 cookie 中获取用户信息

在其它 Controller 基本写法

主要分类,需要登录检验和不需要登录检验的 Controller,不需要登录校验通常是包含登录和注册的 Controller

需要登录检验的 Controller编写

address_controller 为例

截取部分代码

// 需要登录校验就需要继承 BaseController,这样该 Controller下的函数都在调用执行之前到 执行Prepare函数进行登录检验
type AddressController struct {
	BaseController
}

// URLMapping ...
func (c *AddressController) URLMapping() {
	c.Mapping("AddAddress", c.AddAddress)
	c.Mapping("DeleteAddress", c.DeleteAddress)
	c.Mapping("UpdateAddress", c.UpdateAddress)
	c.Mapping("GetAllAddress", c.GetAllAddress)
}

// @Title 新增地址
// @router /add [post]
func (c *AddressController) AddAddress() {
	var address model_views.Receiver

	if v := c.GetString("address"); v != "" {
		_ = json.Unmarshal([]byte(v), &address)
	}

	var receiver models.Receiver
	receiver.Id = address.Id
	receiver.Consignee = address.Consignee
	receiver.AreaName = address.AreaName
	receiver.AreaId = address.AreaId
	receiver.Address = address.Address
	receiver.IsDefault = address.IsDefault
	receiver.Phone = address.Phone
	receiver.ZipCode = address.ZipCode
	receiver.MemberId = int64(c.Member.Id)
	receiver.LastUpdatedBy = c.Member.Username

	_, err := models.AddReceiver(&receiver)
	if err != nil {
        // 服务通用报错函数调用
		c.ServerError(err)
		return
	}

	c.JsonResult(http.GetHttpStatusByAlias("created"), http.ErrOK, http.Success, nil)
}

就是这么简单,其它 Controller 基本都是如此

不需要登录检验的 Controller 编写

截取部分代码

// 继承 JsonController,不会调用 BaseController 的Prepare函数进行登录校验
type UserController struct {
	JsonController
}

// @Title 登录
// @router /login [post]
func (c *UserController) Login() {
	var mobile string
	var sms string

	// mobile
	if v := c.GetString("mobile"); v != "" {
		mobile = v
	}
	// sms
	if v := c.GetString("sms"); v != "" {
		sms = v
	}

	smsModel, err := models.GetSmsByCodeAndMobile(sms, mobile)
	if err != nil {
		c.JsonResult(http.GetHttpStatusByAlias("ok"), http.ErrError, http.Fail, "手机和验证码不匹配")
		return
	}
	if smsModel.ExpireDate != nil {
		c.JsonResult(http.GetHttpStatusByAlias("ok"), http.ErrError, http.Fail, "验证码已过期")
		return
	}
	if smsModel.IsUsed == 1 {
		c.JsonResult(http.GetHttpStatusByAlias("ok"), http.ErrError, http.Fail, "验证码已使用")
		return
	}

	member, _ := models.GetMemberByUsername(mobile)

	if member == nil {
		member = &models.Member{}
	}

	if member.Id > 0 {
		// 最后登录IP
		member.LoginIp = c.Ctx.Input.IP()
		member.LoginDate = time.Now()

		err = models.UpdateMemberById(member)
		if err != nil {
			c.ServerError(err)
			return
		}
	} else {
		member.Username = mobile
		member.Mobile = mobile
		member.MemberRankId = 1 // 普通会员

		_, err := models.AddMember(member)
		if err != nil {
			c.ServerError(err)
			return
		}
	}
	/**
	 * 更新短信使用
	 */
	now := time.Now()
	smsModel.UsedDate = &now
	smsModel.IsUsed = 1

	err = models.UpdateSmsById(smsModel)
	if err != nil {
		c.ServerError(err)
		return
	}

	/**
	 * 设置Cookie
	 */
	c.SetSessionUser(*member)
	var cookieMember CookieMember
	cookieMember.MemberId = member.Id
	cookieMember.Username = member.Username
	cookieMember.Time = time.Now()
	v, err := helpers.Encode(cookieMember)
	if err == nil {
		c.SetSecureCookie(common.AppKey(), "web_login", v, 24*3600)
	}
	commonController := &CommonController{}
	memberView := commonController.setMemberByMemberModel(*member)
	c.JsonResult(http.GetHttpStatusByAlias("ok"), http.ErrOK, http.Success, memberView)
}

总结

最后,写完这两个基础的 Controller 后,基本就是根据业务判断是否需要登录校验,然后就行CRUD(增删改查)的业务编写就好了,没错就是这么简单

posted @ 2021-06-30 08:19  聪明的竹子_Alfred  阅读(366)  评论(0编辑  收藏  举报