业务逻辑封装

基本介绍

职责划分

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

数据校验

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

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

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

实现代码

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

  1. package user
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/gogf/gf-demos/app/model/user"
  6. "github.com/gogf/gf/net/ghttp"
  7. "github.com/gogf/gf/os/gtime"
  8. "github.com/gogf/gf/util/gconv"
  9. "github.com/gogf/gf/util/gvalid"
  10. )
  11. const (
  12. USER_SESSION_MARK = "user_info"
  13. )
  14. // 注册输入参数
  15. type SignUpInput struct {
  16. Passport string `v:"required|length:6,16#账号不能为空|账号长度应当在:min到:max之间"`
  17. Password string `v:"required|length:6,16#请输入确认密码|密码长度应当在:min到:max之间"`
  18. Password2 string `v:"required|length:6,16|same:Password#密码不能为空|密码长度应当在:min到:max之间|两次密码输入不相等"`
  19. Nickname string
  20. }
  21. // 用户注册
  22. func SignUp(data *SignUpInput) error {
  23. // 输入参数检查
  24. if e := gvalid.CheckStruct(data, nil); e != nil {
  25. return errors.New(e.String())
  26. }
  27. // 昵称为非必需参数,默认使用账号名称
  28. if data.Nickname == "" {
  29. data.Nickname = data.Passport
  30. }
  31. // 账号唯一性数据检查
  32. if !CheckPassport(data.Passport) {
  33. return errors.New(fmt.Sprintf("账号 %s 已经存在", data.Passport))
  34. }
  35. // 昵称唯一性数据检查
  36. if !CheckNickName(data.Nickname) {
  37. return errors.New(fmt.Sprintf("昵称 %s 已经存在", data.Nickname))
  38. }
  39. // 将输入参数赋值到数据库实体对象上
  40. var entity *user.Entity
  41. if err := gconv.Struct(data, &entity); err != nil {
  42. return err
  43. }
  44. // 记录账号创建/注册时间
  45. entity.CreateTime = gtime.Now()
  46. if _, err := user.Save(entity); err != nil {
  47. return err
  48. }
  49. return nil
  50. }
  51. // 判断用户是否已经登录
  52. func IsSignedIn(session *ghttp.Session) bool {
  53. return session.Contains(USER_SESSION_MARK)
  54. }
  55. // 用户登录,成功返回用户信息,否则返回nil; passport应当会md5值字符串
  56. func SignIn(passport, password string, session *ghttp.Session) error {
  57. one, err := user.FindOne("passport=? and password=?", passport, password)
  58. if err != nil {
  59. return err
  60. }
  61. if one == nil {
  62. return errors.New("账号或密码错误")
  63. }
  64. return session.Set(USER_SESSION_MARK, one)
  65. }
  66. // 用户注销
  67. func SignOut(session *ghttp.Session) error {
  68. return session.Remove(USER_SESSION_MARK)
  69. }
  70. // 检查账号是否符合规范(目前仅检查唯一性),存在返回false,否则true
  71. func CheckPassport(passport string) bool {
  72. if i, err := user.FindCount("passport", passport); err != nil {
  73. return false
  74. } else {
  75. return i == 0
  76. }
  77. }
  78. // 检查昵称是否符合规范(目前仅检查唯一性),存在返回false,否则true
  79. func CheckNickName(nickname string) bool {
  80. if i, err := user.FindCount("nickname", nickname); err != nil {
  81. return false
  82. } else {
  83. return i == 0
  84. }
  85. }
  86. // 获得用户信息详情
  87. func GetProfile(session *ghttp.Session) (u *user.Entity) {
  88. _ = session.GetStruct(USER_SESSION_MARK, &u)
  89. return
  90. }