包名约定

根据官方《Effective Go》建议,包名尽量采用言简意赅的名称(short, concise, evocative)。并且推荐通过不同的import路径来区分相同包名的包引入。

控制器实现

控制器主要用于接口的路由注册以及对于用户输入参数的处理。

我们这里使用执行对象注册方式。

/app/api/user/user.go

  1. package user
  2. import (
  3. "github.com/gogf/gf-demos/app/service/user"
  4. "github.com/gogf/gf-demos/library/response"
  5. "github.com/gogf/gf/g/net/ghttp"
  6. "github.com/gogf/gf/g/util/gvalid"
  7. )
  8. // 用户API管理对象
  9. type Controller struct { }
  10. // 用户注册接口
  11. func (c *Controller) SignUp(r *ghttp.Request) {
  12. if err := user.SignUp(r.GetPostMap()); err != nil {
  13. response.Json(r, 1, err.Error())
  14. } else {
  15. response.Json(r, 0, "ok")
  16. }
  17. }
  18. // 用户登录接口
  19. func (c *Controller) SignIn(r *ghttp.Request) {
  20. data := r.GetPostMap()
  21. rules := map[string]string {
  22. "passport" : "required",
  23. "password" : "required",
  24. }
  25. msgs := map[string]interface{} {
  26. "passport" : "账号不能为空",
  27. "password" : "密码不能为空",
  28. }
  29. if e := gvalid.CheckMap(data, rules, msgs); e != nil {
  30. response.Json(r, 1, e.String())
  31. }
  32. if err := user.SignIn(data["passport"], data["password"], r.Session); err != nil {
  33. response.Json(r, 1, err.Error())
  34. } else {
  35. response.Json(r, 0, "ok")
  36. }
  37. }
  38. // 判断用户是否已经登录
  39. func (c *Controller) IsSignedIn(r *ghttp.Request) {
  40. if user.IsSignedIn(r.Session) {
  41. response.Json(r, 0, "ok")
  42. } else {
  43. response.Json(r, 1, "")
  44. }
  45. }
  46. // 用户注销/退出接口
  47. func (c *Controller) SignOut(r *ghttp.Request) {
  48. user.SignOut(r.Session)
  49. response.Json(r, 0, "ok")
  50. }
  51. // 检测用户账号接口(唯一性校验)
  52. func (c *Controller) CheckPassport(r *ghttp.Request) {
  53. passport := r.Get("passport")
  54. if e := gvalid.Check(passport, "required", "请输入账号"); e != nil {
  55. response.Json(r, 1, e.String())
  56. }
  57. if user.CheckPassport(passport) {
  58. response.Json(r, 0, "ok")
  59. }
  60. response.Json(r, 1, "账号已经存在")
  61. }
  62. // 检测用户昵称接口(唯一性校验)
  63. func (c *Controller) CheckNickName(r *ghttp.Request) {
  64. nickname := r.Get("nickname")
  65. if e := gvalid.Check(nickname, "required", "请输入昵称"); e != nil {
  66. response.Json(r, 1, e.String())
  67. }
  68. if user.CheckNickName(r.Get("nickname")) {
  69. response.Json(r, 0, "ok")
  70. }
  71. response.Json(r, 1, "昵称已经存在")
  72. }

逻辑封装实现

我们这里没有使用到数据模型,仅使用了 逻辑封装层+gdb 来操作数据库。

用户逻辑

主要用于用户接口的业务逻辑封装。

/app/service/user/user.go

  1. package user
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/gogf/gf/g"
  6. "github.com/gogf/gf/g/net/ghttp"
  7. "github.com/gogf/gf/g/os/gtime"
  8. "github.com/gogf/gf/g/util/gvalid"
  9. )
  10. const (
  11. USER_SESSION_MARK = "user_info"
  12. )
  13. var (
  14. // 表对象
  15. table = g.DB().Table("user").Safe()
  16. )
  17. // 用户注册
  18. func SignUp(data g.MapStrStr) error {
  19. // 数据校验
  20. rules := []string {
  21. "passport @required|length:6,16#账号不能为空|账号长度应当在:min到:max之间",
  22. "password2@required|length:6,16#请输入确认密码|密码长度应当在:min到:max之间",
  23. "password @required|length:6,16|same:password2#密码不能为空|密码长度应当在:min到:max之间|两次密码输入不相等",
  24. }
  25. if e := gvalid.CheckMap(data, rules); e != nil {
  26. return errors.New(e.String())
  27. }
  28. if _, ok := data["nickname"]; !ok {
  29. data["nickname"] = data["passport"]
  30. }
  31. // 唯一性数据检查
  32. if !CheckPassport(data["passport"]) {
  33. return errors.New(fmt.Sprintf("账号 %s 已经存在", data["passport"]))
  34. }
  35. if !CheckNickName(data["nickname"]) {
  36. return errors.New(fmt.Sprintf("昵称 %s 已经存在", data["nickname"]))
  37. }
  38. // 记录账号创建/注册时间
  39. if _, ok := data["create_time"]; !ok {
  40. data["create_time"] = gtime.Now().String()
  41. }
  42. if _, err := table.Filter().Data(data).Save(); err != nil {
  43. return err
  44. }
  45. return nil
  46. }
  47. // 判断用户是否已经登录
  48. func IsSignedIn(session *ghttp.Session) bool {
  49. return session.Contains(USER_SESSION_MARK)
  50. }
  51. // 用户登录,成功返回用户信息,否则返回nil; passport应当会md5值字符串
  52. func SignIn(passport, password string, session *ghttp.Session) error {
  53. record, err := table.Where("passport=? and password=?", passport, password).One()
  54. if err != nil {
  55. return err
  56. }
  57. if record == nil {
  58. return errors.New("账号或密码错误")
  59. }
  60. session.Set(USER_SESSION_MARK, record)
  61. return nil
  62. }
  63. // 用户注销
  64. func SignOut(session *ghttp.Session) {
  65. session.Remove(USER_SESSION_MARK)
  66. }
  67. // 检查账号是否符合规范(目前仅检查唯一性),存在返回false,否则true
  68. func CheckPassport(passport string) bool {
  69. if i, err := table.Where("passport", passport).Count(); err != nil {
  70. return false
  71. } else {
  72. return i == 0
  73. }
  74. }
  75. // 检查昵称是否符合规范(目前仅检查唯一性),存在返回false,否则true
  76. func CheckNickName(nickname string) bool {
  77. if i, err := table.Where("nickname", nickname).Count(); err != nil {
  78. return false
  79. } else {
  80. return i == 0
  81. }
  82. }

工具类包

主要用于返回JSON数据格式的统一。

/library/response/response.go

  1. package response
  2. import (
  3. "github.com/gogf/gf/g"
  4. "github.com/gogf/gf/g/net/ghttp"
  5. )
  6. // 标准返回结果数据结构封装。
  7. // 返回固定数据结构的JSON:
  8. // err: 错误码(0:成功, 1:失败, >1:错误码);
  9. // msg: 请求结果信息;
  10. // data: 请求结果,根据不同接口返回结果的数据结构不同;
  11. func Json(r *ghttp.Request, err int, msg string, data...interface{}) {
  12. responseData := interface{}(nil)
  13. if len(data) > 0 {
  14. responseData = data[0]
  15. }
  16. r.Response.WriteJson(g.Map{
  17. "err" : err,
  18. "msg" : msg,
  19. "data" : responseData,
  20. })
  21. r.Exit()
  22. }