逻辑封装

业务逻辑封装

基本介绍

职责划分

所有的业务逻辑实现均封装于service层中,不推荐实现于控制器api中。service层之间的包存在相互调用,不推荐api在代码层级相互调用。

数据校验

针对于注册逻辑,参数结构体以及校验规则的绑定并没有放置于控制器中,而是由service负责维护。因为该方法的参数复杂且复用性比较强,不仅仅在控制中需要校验,其他service调用时也需要执行该校验逻辑。

// 注册输入参数
type SignUpInput struct {
    Passport  string `v:"required|length:6,16#账号不能为空|账号长度应当在:min到:max之间"`
    Password  string `v:"required|length:6,16#请输入确认密码|密码长度应当在:min到:max之间"`
    Password2 string `v:"required|length:6,16|same:Password#密码不能为空|密码长度应当在:min到:max之间|两次密码输入不相等"`
    Nickname  string
}

针对参数比较复杂且后续可能会变动的参数,推荐定义并使用结构体作为输入参数。

实现代码

https://github.com/gogf/gf-demos/blob/master/app/service/user/user.go

package user

import (
    "errors"
    "fmt"
    "github.com/gogf/gf-demos/app/model/user"
    "github.com/gogf/gf/net/ghttp"
    "github.com/gogf/gf/os/gtime"
    "github.com/gogf/gf/util/gconv"
    "github.com/gogf/gf/util/gvalid"
)

const (
    USER_SESSION_MARK = "user_info"
)

// 注册输入参数
type SignUpInput struct {
    Passport  string `v:"required|length:6,16#账号不能为空|账号长度应当在:min到:max之间"`
    Password  string `v:"required|length:6,16#请输入确认密码|密码长度应当在:min到:max之间"`
    Password2 string `v:"required|length:6,16|same:Password#密码不能为空|密码长度应当在:min到:max之间|两次密码输入不相等"`
    Nickname  string
}

// 用户注册
func SignUp(data *SignUpInput) error {
    // 输入参数检查
    if e := gvalid.CheckStruct(data, nil); e != nil {
        return errors.New(e.String())
    }
    // 昵称为非必需参数,默认使用账号名称
    if data.Nickname == "" {
        data.Nickname = data.Passport
    }
    // 账号唯一性数据检查
    if !CheckPassport(data.Passport) {
        return errors.New(fmt.Sprintf("账号 %s 已经存在", data.Passport))
    }
    // 昵称唯一性数据检查
    if !CheckNickName(data.Nickname) {
        return errors.New(fmt.Sprintf("昵称 %s 已经存在", data.Nickname))
    }
    // 将输入参数赋值到数据库实体对象上
    var entity *user.Entity
    if err := gconv.Struct(data, &entity); err != nil {
        return err
    }
    // 记录账号创建/注册时间
    entity.CreateTime = gtime.Now()
    if _, err := user.Save(entity); err != nil {
        return err
    }
    return nil
}

// 判断用户是否已经登录
func IsSignedIn(session *ghttp.Session) bool {
    return session.Contains(USER_SESSION_MARK)
}

// 用户登录,成功返回用户信息,否则返回nil; passport应当会md5值字符串
func SignIn(passport, password string, session *ghttp.Session) error {
    one, err := user.FindOne("passport=? and password=?", passport, password)
    if err != nil {
        return err
    }
    if one == nil {
        return errors.New("账号或密码错误")
    }
    return session.Set(USER_SESSION_MARK, one)
}

// 用户注销
func SignOut(session *ghttp.Session) error {
    return session.Remove(USER_SESSION_MARK)
}

// 检查账号是否符合规范(目前仅检查唯一性),存在返回false,否则true
func CheckPassport(passport string) bool {
    if i, err := user.FindCount("passport", passport); err != nil {
        return false
    } else {
        return i == 0
    }
}

// 检查昵称是否符合规范(目前仅检查唯一性),存在返回false,否则true
func CheckNickName(nickname string) bool {
    if i, err := user.FindCount("nickname", nickname); err != nil {
        return false
    } else {
        return i == 0
    }
}

// 获得用户信息详情
func GetProfile(session *ghttp.Session) (u *user.Entity) {
    _ = session.GetStruct(USER_SESSION_MARK, &u)
    return
}