Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于gin框架的MVC搭建,以及使用流程 #1

Open
panghui23 opened this issue Jan 18, 2023 · 0 comments
Open

关于gin框架的MVC搭建,以及使用流程 #1

panghui23 opened this issue Jan 18, 2023 · 0 comments

Comments

@panghui23
Copy link
Owner

panghui23 commented Jan 18, 2023

因为本教程写于2022年1月,然而后端技术发展太快了。有些库的版本一直在升级,所以你如果碰到奇怪的问题,请先检查下安装的库版本是否和我源码中的一样。

大家阅读的时候,照着目录来阅读哦,有些章节不在文章里面。要点链接的~
具体案例代码gin-framework

##先给大家看一下项目的文件结构


├── conf
│   └── config.yaml //加载配置文件
├── controller
│   ├── code.go //存放常量定义
│   ├── request.go //封装请求的参数提取函数
│   ├── response.go //封装回复的函数
│   └── user.go //定义用户的controller
├── dao
│   ├── mysql
│   │   ├── mysql.go
│   │   └── user.go
├── go.mod
├── go.sum
├── logger
│   └── logger.go //日志组件
├── logic
│   └── user.go 
├── main.go
├── middlewares
│   └── auth.go //用户登录的中间间
├── models
│   ├── params.go //请求参数的结构体
│   └── user.go //定义用户的结构体
├── pkg  //第三方包
│   ├── jwt
│       └── jwt.go

├── router
│   └── route.go //定义gin框架的所有路由
├── setting
│   └── setting.go //加载第三方组件
└── web_app.log //日志记录

目录


model(参考例子user.go)

  1. 结构体的定义

controller(参考例子user.go)

  1. response的定义
  2. request的请求提取
  3. user.go的账户注册例子
  4. user.go的账户登录例子

logic(参考例子user.go)

  1. signup(注册)
  2. Login(登陆)

dao

  1. mysql的用户管理

model(参考例子user.go)


结构体的定义
//paramsignup(账号注册)的结构体
type ParamSignUp struct {
  Username   string `json:"username" binding:"required"`
  Password   string `json:"password" binding:"required"`
  RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}

//user(用户信息)
type User struct {
  UserID   int64  `db:"user_id"`
  Username string `db:"username"`
  Password string `db:"password"`
  Token    string
}

//Login(登陆提交信息)
type Login struct {
  Username string `json:"username" binding:"required"`
  Password string `json:"password" binding:"required"`
}

controller


response的定义
type ResCode int64


const (
  CodeSuccess ResCode = 1000 + iota
  CodeInvalidParam
  CodeUserExist
  CodeUserNotExist
  CodeInvalidPassword
  CodeServerBusy


  CodeNeedLogin
  CodeInvalidToken
)


var codeMsgMap = map[ResCode]string{
  CodeSuccess:         "success",
  CodeInvalidParam:    "请求参数错误",
  CodeUserExist:       "用户名已存在",
  CodeUserNotExist:    "用户名不存在",
  CodeInvalidPassword: "用户名或密码错误",
  CodeServerBusy:      "服务繁忙",


  CodeNeedLogin:    "需要登录",
  CodeInvalidToken: "无效的token",
}


func (c ResCode) Msg() string {
  msg, ok := codeMsgMap[c]
  if !ok {
     msg = codeMsgMap[CodeServerBusy]
  }
  return msg
}


 
type ResponseData struct {
  Code ResCode     `json:"code"`
  Msg  interface{} `json:"msg"`
  Data interface{} `json:"data,omitempty"`
}
 
func ResponseError(c *gin.Context, code ResCode) {
  c.JSON(http.StatusOK, &ResponseData{
     Code: code,
     Msg:  code.Msg(),
     Data: nil,
  })
}
 
func ResponseErrorWithMsg(c *gin.Context, code ResCode, msg interface{}) {
  c.JSON(http.StatusOK, &ResponseData{
     Code: code,
     Msg:  msg,
     Data: nil,
  })
}
 
func ResponseSuccess(c *gin.Context, data interface{}) {
  c.JSON(http.StatusOK, &ResponseData{
     Code: CodeSuccess,
     Msg:  CodeSuccess.Msg(),
     Data: data,
  })
}
 

request的请求提取
package controller


import (
  "errors"
  "strconv"


  "github.com/gin-gonic/gin"
)


const CtxUserIDKey = "userID"


var ErrorUserNotLogin = errors.New("用户未登录")


// getCurrentUserID 获取当前登录的用户ID
func getCurrentUserID(c *gin.Context) (userID int64, err error) {
  uid, ok := c.Get(CtxUserIDKey)
  if !ok {
     err = ErrorUserNotLogin
     return
  }
  userID, ok = uid.(int64)
  if !ok {
     err = ErrorUserNotLogin
     return
  }
  return
}


func getPageInfo(c *gin.Context) (int64, int64) {
  pageStr := c.Query("page")
  sizeStr := c.Query("size")


  var (
     page int64
     size int64
     err  error
  )


  page, err = strconv.ParseInt(pageStr, 10, 64)
  if err != nil {
     page = 1
  }
  size, err = strconv.ParseInt(sizeStr, 10, 64)
  if err != nil {
     size = 10
  }
  return page, size
}
 

user.go的账户注册例子
func SignUpHandler(c *gin.Context) {
  // 1. 获取参数和参数校验
  p := new(models.ParamSignUp)
  if err := c.ShouldBindJSON(p); err != nil {
     // 请求参数有误,直接返回响应
     zap.L().Error("SignUp with invalid param", zap.Error(err))
     // 判断err是不是validator.ValidationErrors 类型
     errs, ok := err.(validator.ValidationErrors)
     if !ok {
       ResponseError(c, CodeInvalidParam)
       return
     }
     ResponseErrorWithMsg(c, CodeInvalidParam, removeTopStruct(errs.Translate(trans)))
     return
  }
  // 2. 业务处理
  if err := logic.SignUp(p); err != nil {
     zap.L().Error("logic.SignUp failed", zap.Error(err))
     if errors.Is(err, mysql.ErrorUserExist) {
       ResponseError(c, CodeUserExist)
       return
     }
     ResponseError(c, CodeServerBusy)
     return
  }
  // 3. 返回响应
  ResponseSuccess(c, nil)
}

user.go的账户登录例子
// LoginHandler 登录
func LoginHandler(c *gin.Context) {
  // 1.获取请求参数及参数校验
  p := new(models.ParamLogin)
  if err := c.ShouldBindJSON(p); err != nil {
     // 请求参数有误,直接返回响应
     zap.L().Error("Login with invalid param", zap.Error(err))
     // 判断err是不是validator.ValidationErrors 类型
     errs, ok := err.(validator.ValidationErrors)
     if !ok {
       ResponseError(c, CodeInvalidParam)
       return
     }
     ResponseErrorWithMsg(c, CodeInvalidParam, removeTopStruct(errs.Translate(trans)))
     return
  }
  // 2.业务逻辑处理
  user, err := logic.Login(p)
  if err != nil {
     zap.L().Error("logic.Login failed", zap.String("username", p.Username), zap.Error(err))
     if errors.Is(err, mysql.ErrorUserNotExist) {
       ResponseError(c, CodeUserNotExist)
       return
     }
     ResponseError(c, CodeInvalidPassword)
     return
  }

logic(参考例子user.go)


signup(注册)
func SignUp(p *models.ParamSignUp) (err error) {
  // 1.判断用户存不存在
  if err := mysql.CheckUserExist(p.Username); err != nil {
     return err
  }
  // 2.生成UID
  userID := snowflake.GenID()
  // 构造一个User实例
  user := &models.User{
     UserID:   userID,
     Username: p.Username,
     Password: p.Password,
  }
  // 3.保存进数据库
  return mysql.InsertUser(user)
}
Login(登陆)
func Login(p *models.ParamLogin) (user *models.User, err error) {
  user = &models.User{
     Username: p.Username,
     Password: p.Password,
  }
  // 传递的是指针,就能拿到user.UserID
  if err := mysql.Login(user); err != nil {
     return nil, err
  }
  // 生成JWT
  token, err := jwt.GenToken(user.UserID, user.Username)
  if err != nil {
     return
  }
  user.Token = token
  return
}

mysql的用户管理
//error_code.go(新建错误代码)
package mysql


import "errors"


var (
  ErrorUserExist       = errors.New("用户已存在")
  ErrorUserNotExist    = errors.New("用户不存在")
  ErrorInvalidPassword = errors.New("用户名或密码错误")
  ErrorInvalidID       = errors.New("无效的ID")
)

dao


//user.go(用户管理)
package mysql


import (
  "bluebell/models"
  "crypto/md5"
  "database/sql"
  "encoding/hex"
)


// 把每一步数据库操作封装成函数
// 待logic层根据业务需求调用


const secret = "pang"


// CheckUserExist 检查指定用户名的用户是否存在
func CheckUserExist(username string) (err error) {
  sqlStr := `select count(user_id) from user where username = ?`
  var count int64
  if err := db.Get(&count, sqlStr, username); err != nil {
     return err
  }
  if count > 0 {
     return ErrorUserExist
  }
  return
}


// InsertUser 想数据库中插入一条新的用户记录
func InsertUser(user *models.User) (err error) {
  // 对密码进行加密
  user.Password = encryptPassword(user.Password)
  // 执行SQL语句入库
  sqlStr := `insert into user(user_id, username, password) values(?,?,?)`
  _, err = db.Exec(sqlStr, user.UserID, user.Username, user.Password)
  return
}


// encryptPassword 密码加密
func encryptPassword(oPassword string) string {
  h := md5.New()
  h.Write([]byte(secret))
  return hex.EncodeToString(h.Sum([]byte(oPassword)))
}


func Login(user *models.User) (err error) {
  oPassword := user.Password // 用户登录的密码
  sqlStr := `select user_id, username, password from user where username=?`
  err = db.Get(user, sqlStr, user.Username)
  if err == sql.ErrNoRows {
     return ErrorUserNotExist
  }
  if err != nil {
     // 查询数据库失败
     return err
  }
  // 判断密码是否正确
  password := encryptPassword(oPassword)
  if password != user.Password {
     return ErrorInvalidPassword
  }
  return
}


// GetUserById 根据id获取用户信息
func GetUserById(uid int64) (user *models.User, err error) {
  user = new(models.User)
  sqlStr := `select user_id, username from user where user_id = ?`
  err = db.Get(user, sqlStr, uid)
  return
}
 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant