• 包名约定
  • 控制器实现
  • 逻辑封装实现
    • 用户逻辑
    • 工具类包

    包名约定

    根据官方《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. }