We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
因为本教程写于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 //日志记录
//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"` }
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, }) }
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 }
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) }
// 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 }
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) }
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 }
//error_code.go(新建错误代码) package mysql import "errors" var ( ErrorUserExist = errors.New("用户已存在") ErrorUserNotExist = errors.New("用户不存在") ErrorInvalidPassword = errors.New("用户名或密码错误") ErrorInvalidID = errors.New("无效的ID") )
//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 }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
因为本教程写于2022年1月,然而后端技术发展太快了。有些库的版本一直在升级,所以你如果碰到奇怪的问题,请先检查下安装的库版本是否和我源码中的一样。
大家阅读的时候,照着目录来阅读哦,有些章节不在文章里面。要点链接的~
具体案例代码gin-framework
##先给大家看一下项目的文件结构
目录
model(参考例子user.go)
controller(参考例子user.go)
logic(参考例子user.go)
dao
model(参考例子user.go)
结构体的定义
controller
response的定义
request的请求提取
user.go的账户注册例子
user.go的账户登录例子
logic(参考例子user.go)
signup(注册)
Login(登陆)
mysql的用户管理
dao
The text was updated successfully, but these errors were encountered: