Go Web 开发 Demo【用户登录、注册、验证】(1)https://developer.aliyun.com/article/1534272
3、项目重构
上面我们把连接数据库和响应的代码都放到了一个文件中,显然后期随着业务代码越来越多开发起来越来越难以管理,所以我们这里需要对项目进行重构:
3.1、util 层
存放工具,比如我们上面的随机生成用户名方法
package util import ( "math/rand" "time" ) func RandomString(length int) string { var letters = []byte("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM") result := make([]byte, length) rand.Seed(time.Now().Unix()) for i := range result { result[i] = letters[rand.Intn(len(letters))] } return string(result) }
3.2、model 层
存放结构体
package model import "github.com/jinzhu/gorm" type User struct { gorm.Model Name string `gorm:"type:varchar(20);not null"` Phone string `gorm:"type:varchar(110);not null,unique"` Password string `gorm:"size:255;not null"` }
3.3、common 层
存放一些公共的方法,比如连接数据库工具
package common import ( "com.lyh/goessential/model" "fmt" "github.com/jinzhu/gorm" ) var DB *gorm.DB func InitDB() *gorm.DB { driverName := "mysql" host := "127.0.0.1" port := 3306 database := "go_web" username := "root" password := "Yan1029." charset := "utf8mb4" args := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true", username, password, host, port, database, charset) db, err := gorm.Open(driverName, args) if err != nil { panic("failed to connect database, err : " + err.Error()) } db.AutoMigrate(&model.User{}) // 如果表不存在则自动创建 DB = db return db } func GetDB() *gorm.DB { return DB }
3.4、controller 层
存放控制器,因为我们使用的 Gin 框架的请求方法都是函数式编程,它的第二个参数是一个处理请求的函数,所以控制器层我们存放的是业务模块对应的方法:
package controller import ( "com.lyh/goessential/common" "com.lyh/goessential/model" "com.lyh/goessential/util" "fmt" "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" "net/http" ) func Register(ctx *gin.Context) { DB := common.GetDB() // 获取参数 name := ctx.PostForm("username") phone := ctx.PostForm("phone") password := ctx.PostForm("password") // 数据验证 if len(phone) != 11 { ctx.JSON(http.StatusUnprocessableEntity, gin.H{ "code": 422, "msg": "手机号必须为11位!", }) return } if len(password) < 6 { // gin.H 等同于 map[string]any ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{ "code": 422, "msg": "密码不能少于6位!", }) return } if len(name) == 0 { name = util.RandomString(10) } fmt.Println(name, phone, password) // 判断手机号是否存在 if isPhoneExist(DB, phone) { ctx.JSON(http.StatusUnprocessableEntity, gin.H{ "msg": "用户已存在,不允许重复注册", }) return } // 创建用户 newUser := model.User{ Name: name, Phone: phone, Password: password, } DB.Create(&newUser) // 返回结果 ctx.JSON(200, gin.H{ "msg": "注册成功", }) } func isPhoneExist(db *gorm.DB, phone string) bool { user := model.User{} db.Where("phone = ?", phone).First(&user) // 这里的参数是地址 if user.ID != 0 { return true } return false }
注意:这里判断用户是否存在需要传入一个 user 地址,因为 user 是值类型,如果不传入地址,则进入方法后的操作无效。
3.5、routes.go
所有的请求都将通过这个文件中的方法再传递给 main 方法,其实就是为了简化 main 方法所在go文件的代码量,方便管理和维护。所以它的包名也是 main,相当于它俩在一个文件内。
package main import ( "com.lyh/goessential/controller" "github.com/gin-gonic/gin" ) func CollectRoute(engine *gin.Engine) *gin.Engine { engine.POST("/register", controller.Register) return engine }
3.6、main.go
这是程序的入口,现在我们已经把它彻底解脱出来了:
package main import ( "com.lyh/goessential/common" "github.com/gin-gonic/gin" _ "github.com/go-sql-driver/mysql" ) func main() { db := common.InitDB() defer db.Close() engine := gin.Default() engine = CollectRoute(engine) panic(engine.Run()) // 默认端口 8080 }
测试
因为我们有两个文件都是 main 包,所以我们最好使用命令启动:
Go Web 开发 Demo【用户登录、注册、验证】(3)https://developer.aliyun.com/article/1534274