最近被要求學習go語言開發,也就做一個項目實戰鞏固一下,也分享一下關于gin框架的實戰項目
(后續應該還是會繼續學習Java,這一期還是做一個go+vue的)
經過一段時間的開發過后,感覺現在的開發效率要快不少了,爭取一天半做出個大概吧,后續再加一些功能就完工
那么就開始go的后端初始化吧;
先創建一個項目:
注意點1:先創建go.mod(這里如果不創建mod就會報錯
\testProject> go get -u github.com/gin-gonic/gin?
go: go.mod file not found in current directory or any parent directory.
? ? ? ? 'go get' is no longer supported outside a module.
? ? ? ? To build and install a command, use 'go install' with a version,
? ? ? ? like 'go install example.com/cmd@latest'
? ? ? ? For more information, see https://golang.org/doc/go-get-install-deprecation
? ? ? ? or run 'go help get' or 'go help install'.)
創建go.mod文件并加上module 和go
這下再來安裝一下gin框架,終端輸入命令
go get -u github.com/gin-gonic/gin?
吶這樣就安裝成功了
注意點2:這里如果有人會出現壓縮包損壞的情況記得要改變一下GOPROXY
這里雖然安裝成功了,但沒有被識別到,這里需要設置一下
點擊setting
點開goModule,并啟動go模塊集成就可以了
吶,這樣就好了
注意點3:如果安裝了框架卻沒有被識別,點擊setting并啟動模塊集成
前置工作差不多了,現在來初始化一下
初始化的話,先定義一下統一相應結果吧;創建一個response包并在包下創建result.go文件
這里可以定義一個統一返回結果的函數,再定義一個成功返回函數和失敗返回函數
package responseimport ("github.com/gin-gonic/gin""net/http"
)func Result(context *gin.Context, httpStatus int, code int, msg string, data gin.H) {context.JSON(httpStatus, gin.H{"code": code,"msg": msg,"data": data,})
}func Success(context *gin.Context, msg string, data gin.H) {Result(context, http.StatusOK, 0, msg, data)
}func Fail(context *gin.Context, msg string, data gin.H) {Result(context, http.StatusOK, 1, msg, data)
}
這里我是按照寫java的習慣來定義的,也不一定很規范
定義好統一相應結果之后就可以開始定義連接數據庫相關操作,這里專門創建一個go文件來連接
創建common包,并在包下創建database文件
這里用配置文件的方式吧,那就再創建一個config包,并在包下創建application.yml包
在config包下我們規定好開啟端口號和數據庫連接信息
server:port: 8082
datasource:driverName: mysqlhost: localhostport: 3306database: go_ginusername: rootpassword: 1234charset: utf8
注意點4:使用config組件來將配置文件統一管理,這需要我們下載viper
下載命令go get github.com/spf13/viper?
然后,這里使用grom來進行數據庫相關操作
注意點5:安裝gorm: go get -u github.com/jinzhu/gorm?
那么現在來編輯一下database.go文件吧
package commonimport ("fmt""github.com/jinzhu/gorm""github.com/spf13/viper""log"
)// 初始化數據庫
func InitDB() *gorm.DB {driverName := viper.GetString("datasource.driverName")host := viper.GetString("datasource.host")port := viper.GetString("datasource.port")database := viper.GetString("datasource.database")username := viper.GetString("datasource.username")password := viper.GetString("datasource.password")charset := viper.GetString("datasource.charset")args := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true",username, password, host, port, database, charset)db, err := gorm.Open(driverName, args)if err != nil {panic("數據庫連接失敗,err:" + err.Error())}log.Println("數據庫連接成功")return db
}// 定義方法來和獲取數據庫實例
func GetDB() *gorm.DB {return InitDB()
}
這里我們定義了兩個函數,一個用來初始化數據庫,一個用來獲取數據庫實例。
然后就可以來定義main.go文件了,在最外層創建main.go文件作為啟動文件
注意點6:剛才使用了viper庫來處理配置文件,這里需要初始化一下,需要定義一個函數
func InitConfig() {workDir, _ := os.Getwd()viper.SetConfigName("application")viper.SetConfigType("yml")viper.AddConfigPath(workDir + "/config")err := viper.ReadInConfig()if err != nil {panic(err)}
}
這里來解釋一下吧,
1.workDir, _ := os.Getwd():獲取當前工作目錄,os.Getwd()返回當前進程的工作目錄路徑,下劃線_忽略可能的錯誤。
2.viper.SetConfigName("application"):設置配置文件的名稱為application,不包括文件擴展名。
3.viper.SetConfigType("yml"):設置配置文件的類型為yaml,意味著Viper將解析.yml或.yaml格式的配置文件。
4.viper.AddConfigPath(workDir + "/config"):添加配置文件的搜索路徑,這里是當前工作目錄下的config子目錄。
5.err := viper.ReadInConfig():嘗試讀取配置文件。如果找到并成功讀取,err將為nil;否則,err將包含錯誤信息。
這個函數確保了在當前工作目錄的config子目錄下查找名為application.yml或application.yaml的配置文件,并在遇到錯誤時停止程序執行。
這樣就初始化了,
再調用一下common包下初始化數據庫的方法即可完成連接
package mainimport ("github.com/jinzhu/gorm""github.com/spf13/viper""main/common""os"
)func main() {InitConfig()db := common.GetDB()defer func(db *gorm.DB) {err := db.Close()if err != nil {panic(err)}}(db)
}
func InitConfig() {workDir, _ := os.Getwd()viper.SetConfigName("application")viper.SetConfigType("yml")viper.AddConfigPath(workDir + "/config")err := viper.ReadInConfig()if err != nil {panic(err)}
}
啊忒,缺少導入數據庫驅動
注意點7:速速安裝一個go get -u github.com/go-sql-driver/mysql
ok,安裝之后放在main.go文件下吧
_ "github.com/go-sql-driver/mysql"
注意這里的下劃線_,它表示導入包僅用于注冊驅動,而不需要直接使用包內的任何函數或類型
這樣就行了,右擊啟動!
啟動成功!
那么,麻煩的一步也就解決了,
下面就可以開始麻煩的部分了,
先定義模塊所需結構體:
創建model包,其下三包,entity,dto,vo
然后在entity包下創建user.go
package entityimport "github.com/jinzhu/gorm"type User struct {gorm.ModelName string `gorm:"size:20;not null;unique"`Password string `gorm:"size:255;not null"`Mobile string `gorm:"size:11;not null;unique"`Email string `gorm:"size:50;not null;unique"`
}
代碼如上
在main方法處添加方法AutoMigrate(檢查模型結構(這里是entity.User),并根據結構體字段創建或更新相應的數據庫表結構)
那么數據庫和表結構都已經完成了,就可以開始編寫接口了
編寫路由包router
并創建routes.go文件,在文件中定義函數
package routerimport "github.com/gin-gonic/gin"func CollectionRoute(r *gin.Engine) *gin.Engine {r.POST("/user/register",)r.POST("/user/login",)r.GET("/user/info",)return r
}
先不寫具體方法,定義下來
然后回到main.go函數
通過 gin.Default() 初始化了一個默認的 Gin 路由器實例。然后,調用了 router.CollectionRoute(r) 函數,集中定義一組相關的路由規則
然后獲取config文件下的服務斷開接著run開啟即可。
那么main.go文件中要寫的也就是這些了,
接下來開始定義接口
創建controller包,并創建UserController.go文件,就在其中編寫一個注冊功能吧
package controllerimport ("github.com/gin-gonic/gin""github.com/jinzhu/gorm""golang.org/x/crypto/bcrypt""log""main/common""main/model/entity""main/response""net/http""net/mail"
)func Register(context *gin.Context) {db := common.GetDB()//獲取參數username := context.PostForm("username")password := context.PostForm("password")mobile := context.PostForm("mobile")email := context.PostForm("email")if len(username) < 5 || len(username) > 16 {response.Fail(context, "用戶名長度在5-16之間", nil)return}if len(password) < 5 || len(password) > 16 {response.Fail(context, "密碼長度在5-16之間", nil)return}if len(mobile) != 11 {response.Fail(context, "手機號長度為11位", nil)return}_, err := mail.ParseAddress(email)if err != nil {response.Fail(context, "郵箱格式不正確", nil)return}//判斷手機號是否存在if isMobileExist(db, mobile) {response.Fail(context, "手機號已存在", nil)return}if isEmailExist(db, email) {response.Fail(context, "郵箱已存在", nil)return}if isUserNameExist(db, username) {response.Fail(context, "用戶名已存在", nil)return}//都不存在則創建用戶//密碼加密hashPwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)if err != nil {response.Result(context, http.StatusInternalServerError, 500, "密碼加密失敗", nil)return}//創建用戶user := entity.User{Name: username,Password: string(hashPwd),Mobile: mobile,Email: email,}db.Create(&user)//返回結果if user.ID != 0 {response.Success(context, "注冊成功", nil)return} else {response.Fail(context, "注冊失敗", nil)return}}func isMobileExist(db *gorm.DB, mobile string) bool {var user entity.Userdb.Where("mobile = ?", mobile).First(&user)if user.ID != 0 {log.Println("手機號已存在")return true}return false
}func isEmailExist(db *gorm.DB, email string) bool {var user entity.Userdb.Where("email = ?", email).First(&user)if user.ID != 0 {log.Println("郵箱已存在")return true}return false
}func isUserNameExist(db *gorm.DB, username string) bool {var user entity.Userdb.Where("name = ?", username).First(&user)if user.ID != 0 {log.Println("用戶名已存在")return true}return false
}
這里的代碼不太難就不細說了,主要也就是從上下文獲取到前端傳來的表單信息
先對表單的格式進行校驗,然后查詢數據庫看關鍵字段是否已經被注冊,若沒有則執行注冊
寫好之后將其添加到routes中即可
那么來測試一下吧,在main.go處打開程序,并打開postman進行檢驗
這樣就注冊成功了
后端這塊差不多都是這個流程
這里我就先不往后crud了,
題外話:
講個前后端混合的,這里以我之前做的基于前端2048小游戲為例子吧
我們先在項目目錄下創建包templates和static,
這里static包下創建js包,css包,images包分別用來存放前端的資源,然后將現有的index.html文件,css文件,js文件和images文件放入對應的包中
就像這樣:
這樣就OK了,然后在main.go文件中加載一下
func main() {InitConfig()db := common.GetDB()defer func(db *gorm.DB) {err := db.Close()if err != nil {panic(err)}}(db)db.AutoMigrate(&entity.User{})r := gin.Default()r.Static("/static", "./static")r.LoadHTMLGlob("templates/*")r = router.CollectionRoute(r)port := viper.GetString("server.port")panic(r.Run(":" + port))
}
func InitConfig() {workDir, _ := os.Getwd()viper.SetConfigName("application")viper.SetConfigType("yml")viper.AddConfigPath(workDir + "/config")err := viper.ReadInConfig()if err != nil {panic(err)}
}
OK,此時回到routes.go文件中添加
r.GET("/user/game", controller.Game)
在UserController文件下添加方法:
func Game(context *gin.Context) {context.HTML(http.StatusOK, "index.html", gin.H{"msg": "這就是CeTide的游戲!",}) }
這樣就可以了,打開main.go!
瀏覽器訪問目標地址
那么基于js制作的2048小游戲就成功呈現在瀏覽器上了,(需要2048小游戲源碼的可以去資源處下載)
emmm,這一章就分享這些吧