手機有軟件做ppt下載網(wǎng)站王通seo教程
目錄
項目介紹
簡介
技術(shù)
項目結(jié)構(gòu)
項目分析
總結(jié)?
項目介紹
簡介
? ? ? ? 項目地址:knoci/list: 基于Gin的待辦清單小項目 (github.com)
? ? ? ? 一個仿照github/Q1mi/bubble 做的一個gin框架練習(xí)
技術(shù)
- gin 框架
- gorm 操作PostgreSQL
- ini 配置文件
項目結(jié)構(gòu)
list
├── README.md
├── config
│ └── config.ini
├── controller
│ └── controller.go
├── dao
│ └── postgresql.go
├── go.mod
├── go.sum
├── main.go
├── models
│ └── todo.go
├── routers
│ └── routers.go
├── static
│ ├── css
│ │ ├── app.8eeeaf31.css
│ │ └── chunk-vendors.57db8905.css
│ ├── fonts
│ │ ├── element-icons.535877f5.woff
│ │ └── element-icons.732389de.ttf
│ └── js
│ ├── app.007f9690.js
│ └── chunk-vendors.ddcb6f91.js
└── templates├── favicon.ico└── index.html
項目分析
? ? ? ? 項目中有config,controllers,dao,models,routers,static,template這7個文件夾。
- config保存ini文件,配置連接數(shù)據(jù)庫的參數(shù)(Port,User,Password...)
- controllers保存控制函數(shù),實現(xiàn)器功能,處理web響應(yīng)
- dao連接數(shù)據(jù)庫
- models是各種數(shù)據(jù)結(jié)構(gòu)模板定義
- routers負(fù)責(zé)路由分組和路由處理
- static存儲靜態(tài)資源
- template是前端模板
? ? ? ? 接下來我們從mian.go開始,逐步分析整個項目的運行。
package mainimport ("list/dao""list/models""list/routers"//_ "gorm.io/driver/mysql"_ "gorm.io/driver/postgres"
)func main() {//連接數(shù)據(jù)庫dao.Connect()//模型綁定dao.DB.AutoMigrate(&models.Todo{})//啟動routerrouters.SetupRouter()
}
? ? ? ? 在main.go中我們導(dǎo)入了同文件夾下的dao,models,routers;隨后運行第一個函數(shù) dao.Connect(),接下來我們進入dao,來看看?dao.Connect() 函數(shù)實現(xiàn)了什么功能。
package daoimport ("fmt""gopkg.in/ini.v1"//"gorm.io/driver/mysql""gorm.io/driver/postgres""gorm.io/gorm"
)var (DB *gorm.DB
)type MysqlConfig struct {User string `ini:"user"`Password string `ini:"password"`Host string `ini:"host"`Port string `ini:"port"`DBname string `ini:"db"`
}func LoadConfig() *MysqlConfig {//development_通過結(jié)構(gòu)體映射參數(shù)c := new(MysqlConfig)ini.MapTo(c, "config/config.ini")fmt.Println(c)return c
}func Connect() {c := LoadConfig()dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s", c.Host, c.User, c.Password, c.DBname, c.Port)/* mysqldsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",c.User, c.Password, c.Host, c.Port, c.DBname)dsn := "root:root1234@tcp(127.0.0.1:13306)/bubble?charset=utf8mb4&parseTime=True&loc=Local"*/var err errorDB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) // connect// mysql DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {panic(err.Error())}fmt.Print("==========連接數(shù)據(jù)庫成功==========\n")
}
? ? ? ? 在postgresql.go中導(dǎo)入了GORM,PG驅(qū)動,ini包,自定義了結(jié)構(gòu)體Mysqlconfig,和一個 導(dǎo)包全局可訪問的 gorm.DB類型的指針DB,封裝了一個函數(shù) LoadConfig()?通過ini.MapTo(c, "config/config.ini")?來接收配置文件。
? ? ? ? 在Connect函數(shù)中調(diào)用LoadConfig()獲得配置,用Sprintf()把配置復(fù)制到dsn,然后通過gorm.Open方法連接到我們的數(shù)據(jù)庫。
????????dao.Connect()完成后,我們繼續(xù)回到main.go,用dao包內(nèi)變量DB的內(nèi)置方法?dao.DB.AutoMigrate(&models.Todo{}) ,實現(xiàn)了模型綁定,實際上就是按照models.Todo結(jié)構(gòu)體在數(shù)據(jù)庫中創(chuàng)建了一張表。
package modelstype Todo struct {ID int `json:"id"`Title string `json:"title"`Status bool `json:"status"`
}
? ? ? ? Todo表中,每個待辦事項有ID,Title,Status,并且有相應(yīng)JOSN的tag。其中ID是用來標(biāo)識事項的自增唯一值,Title是事務(wù)名,Status用0和1表示未完成和完成。
????????回到main.go,最后調(diào)用了routers.SetupRouter(),這是在本地routers包routers.go里的函數(shù)。在SetupRouter中,使用gin.Default()注冊默認(rèn)路由r;然后用r.Static()導(dǎo)入./static目錄下靜態(tài)文件指定為static;接著用r.LoadHTMLGlob()導(dǎo)入當(dāng)前路徑template/*的模板。
? ? ? ? 接著就是路由處理,指定了對"/"的GET請求回應(yīng)controllers.ShowIndex函數(shù),用r.Group()定義了路由組v1Group。
????????路由組中,指定了對"todo"的POST請求回應(yīng)controllers.CreateTodo函數(shù),對"/todo"的GET請求回應(yīng)controllers.RetrieveTodo函數(shù),對"/todo/:id"的PUT請求回應(yīng)controllers.UpdateTodo函數(shù),對"/todo/:id"的DELETE請求回應(yīng)controllers.DeleteTodo函數(shù)。
? ? ? ? 最后用r.Run(:9090),在9090端口上監(jiān)聽并運行。
package routersimport ("github.com/gin-gonic/gin""list/controllers"
)func SetupRouter() {r := gin.Default()r.Static("/static", "static")r.LoadHTMLGlob("template/*")r.GET("/", controllers.ShowIndex)v1Group := r.Group("v1"){//添加v1Group.POST("todo", controllers.CreateTodo)//查看v1Group.GET("/todo", controllers.RetrieveTodo)//修改v1Group.PUT("/todo/:id", controllers.UpdateTodo)//刪除v1Group.DELETE("/todo/:id", controllers.DeleteTodo)}r.Run(":9090")}
? ? ? ? 接下來看看controller中的各個函數(shù)的功能,首先是ShowIndex,負(fù)責(zé)返回狀態(tài)碼200,展示index.html。
func ShowIndex(c *gin.Context) {c.HTML(http.StatusOK, "index.html", nil)
}
? ? ? ? CreateTodo?用來創(chuàng)建一個待辦事項。在接收到傳來的數(shù)據(jù)后,定義一個models.Todo類型的todo結(jié)構(gòu)體,然后用 c.ShouldBind(&todo) 自動的進行響應(yīng)格式(這里是JSON)的參數(shù)綁定到todo,然后通過 dao.DB.Create(&todo) 把todo存入數(shù)據(jù)庫DB,以JSON格式失敗返回報錯,成功返回todo。
func CreateTodo(c *gin.Context) {//get datavar todo models.Todoc.ShouldBind(&todo)//add into databaseerr := dao.DB.Create(&todo).Error//returnif err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return} else {c.JSON(http.StatusOK, todo)}}
? ? ? ? RetrieveTodo 用來獲取所有待辦事項,創(chuàng)建一個結(jié)構(gòu)體數(shù)組todos,用 dao.DB.Find(&todos) 把所有的表數(shù)據(jù)給到todos,以JSON格式失敗返回報錯,成功返回todos。
func RetrieveTodo(c *gin.Context) {var todos []models.Todoif err := dao.DB.Find(&todos).Error; err != nil {c.JSON(http.StatusOK, gin.H{"error": err.Error()})return} else {c.JSON(http.StatusOK, todos)}
}
? ? ? ? ?UpdateTodo 用來更新指定的事項,用 c.Params.GET("id") 獲得要修改事項名為"id"的指定url,定義todo結(jié)構(gòu)體然后用 dao.DB.Where("id=?", id).First(&todo) 來查詢數(shù)據(jù)庫中第一個對應(yīng)id的數(shù)據(jù)到todo,然后 c.BindJSON(&todo) 把方法請求體c以JSON綁定到todo,最后 dao.DB.Save(&todo) 來更新數(shù)據(jù)庫。
func UpdateTodo(c *gin.Context) {id, ok := c.Params.Get("id")if !ok {c.JSON(http.StatusOK, gin.H{"error": "id invalid"})return}var todo models.Todoif err := dao.DB.Where("id=?", id).First(&todo).Error; err != nil {c.JSON(http.StatusOK, gin.H{"error": err.Error()})return}c.BindJSON(&todo) //修改if err := dao.DB.Save(&todo).Error; err != nil {c.JSON(http.StatusOK, gin.H{"error": err.Error()})} else {c.JSON(http.StatusOK, todo)}
}
? ? ? ? DeletTodo 用來刪除一個待辦事項,還是通過 c.Params.GET("id") 獲得要修改事項名為"id"的指定url,用 dao.DB.Where("id=?", id).Delete(models.Todo{}) 來刪除數(shù)據(jù)庫中對應(yīng)id的數(shù)據(jù),因為這里不接收請求體,沒有定義局部變量結(jié)構(gòu)體,所以直接傳入model.Todo{}指定表格式。
總結(jié)?
? ? ? ? 這個項目是Gin和GORM的非常非常簡單的小項目,適合新手入門。