完整项目地址: [go-shop-b2c](https://github.com/CleverBamboo/go-shop-b2c)
系列文章:
* [手摸手,带你用 Beego撸商城 系列一(基础篇)](https://cleverbamboo.github.io/2021/03/30/GO/手摸手,带你用Beego撸商城系列一(基础篇)/)
* [手摸手,带你用 Beego撸商城 系列二(登录篇)](https://cleverbamboo.github.io/2021/04/01/GO/手摸手,带你用Beego撸商城系列二(登录篇)/)
* [手摸手,带你用 Beego撸商城 系列三(系统配置篇)](https://cleverbamboo.github.io/2021/04/09/GO/手摸手,带你用Beego撸商城系列三(系统配置篇)/)
## 前言
一个商城后端系统,登录尤其重要,首先用户下单,需要登录,后台管理系统,需要登录。我们需要做的是,除了**登录以及注册**,其余的接口需要进行登录校验。
<!--more-->
## base_controller 封装
由于我们需要进行登录校验和不进行登录校验的 **Controller**,又由于 **base_controller** 需要进行登录检验,同时,不需要登录校验的 **Controller** 和 **base_controller**有共同的函数需要调用
综上所述,我们应该额外增加一个 **Controller** 分别用于 **base_controller** 继承 和 不需要登录检验的 **Controller** 用于继承
下面就简单地介绍一下 **json_controller**
### json_controller
```go
type JsonController struct {
beego.Controller
}
```
* JsonResult 返回给前端JSON数据,公共调用函数
```go
/**
* 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 服务器通用报错
```go
/**
* 服务器报错
*/
func (c *JsonController) ServerError(err error) {
c.Ctx.Output.SetStatus(http.GetHttpStatusByAlias("internalServerError"))
logs.Error(err)
}
```
* SetSessionUser 封装保存session的函数
```go
/**
* 设置登录登录用户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 方法之前执行,用户可以重写这个函数实现类似用户验证之类。[点击跳转文档查看方法](https://beego.me/docs/mvc/controller/controller.md)
主要做三件事
1. **gob** 序列化保存用户信息
ps: 序列化某个对象,必须在 **encoding/gob** 编码解码前进行注册
2. 从 **session** 中获取用户信息
3. 如果 **Cookie** 中存在登录信息,从 **cookie** 中获取用户信息
## 在其它 Controller 基本写法
主要分类,需要登录检验和不需要登录检验的 **Controller**,不需要登录校验通常是包含登录和注册的 **Controller**
### 需要登录检验的 Controller编写
以 **address_controller** 为例
截取部分代码
```go
// 需要登录校验就需要继承 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 编写
截取部分代码
```go
// 继承 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(增删改查)的业务编写就好了,没错就是这么简单
有疑问加站长微信联系(非本文作者)