上一篇介紹了Gin+Mysql簡單的Restful風格的API,但代碼放在一個文件中,還不屬於restful風格,接下來將進行進一步的封裝。
目錄結構
☁ gin_restful2 tree
.
├── api
│ └── users.go
├── db
│ └── mysql.go
├── main.go
├── models
│ └── users.go
└── router.go
api文件夾存放我們的handler函數,用於邏輯處理,models文件夾用來存放我們的數據模型。
myql.go的包代碼如下:
package db import ( "database/sql" _ "github.com/go-sql-driver/mysql" "log" ) var SqlDB *sql.DB func init() { var err error SqlDB, err = sql.Open("mysql", "root:password@tcp(127.0.0.1:3306)/test?charset=utf8mb4") if err != nil { log.Fatal(err.Error()) } err = SqlDB.Ping() if err != nil { log.Fatal(err.Error()) } }
因為我們需要在別的地方使用SqlDB這個變量,因此依照golang的習慣,變量名必須大寫開頭。
數據model封裝
修改models文件夾下的users.go,把對應的Person結構及其方法移到這里:
package models import ( "gin_restful2/db" "log" ) type Person struct { Id int `json:"id" form:"id"` Name string `json:"name" form:"name"` Telephone string `json:"telephone" form:"telephone"` } //插入 func (person *Person) Create() int64 { rs, err := db.SqlDB.Exec("INSERT into users (name, telephone) value (?,?)", person.Name, person.Telephone) if err != nil{ log.Fatal(err) } id, err := rs.LastInsertId() if err != nil{ log.Fatal(err) } return id } //查詢一條記錄 func (p *Person) GetRow() (person Person, err error) { person = Person{} err = db.SqlDB.QueryRow("select id,name,telephone from users where id = ?", p.Id).Scan(&person.Id, &person.Name, &person.Telephone) return } //查詢所有記錄 func (person *Person) GetRows() (persons []Person, err error) { rows, err := db.SqlDB.Query("select id,name,telephone from users") for rows.Next(){ person := Person{} err := rows.Scan(&person.Id, &person.Name, &person.Telephone) if err != nil { log.Fatal(err) } persons = append(persons, person) } rows.Close() return } //修改 func (person *Person) Update() int64{ rs, err := db.SqlDB.Exec("update users set telephone = ? where id = ?", person.Telephone, person.Id) if err != nil { log.Fatal(err) } rows, err := rs.RowsAffected() if err != nil { log.Fatal(err) } return rows } //刪除一條記錄 func Delete(id int) int64 { rs, err := db.SqlDB.Exec("delete from users where id = ?", id) if err != nil { log.Fatal() } rows, err := rs.RowsAffected() if err != nil { log.Fatal() } return rows }
handler
然后把具體的handler函數封裝到api包中,因為handler函數要操作數據庫,所以會引用model包,api/users.go代碼如下:
package api import ( "github.com/gin-gonic/gin" "net/http" "fmt" ."gin_restful2/models" "strconv" ) //index func IndexUsers(c *gin.Context) { c.String(http.StatusOK, "It works") } //增加一條記錄 func AddUsers(c *gin.Context) { name := c.Request.FormValue("name") telephone := c.Request.FormValue("telephone") person := Person{ Name:name, Telephone:telephone, } id := person.Create() msg := fmt.Sprintf("insert successful %d", id) c.JSON(http.StatusOK, gin.H{ "msg": msg, }) } //獲得一條記錄 func GetOne(c *gin.Context) { ids := c.Param("id") id, _ := strconv.Atoi(ids) p := Person{ Id:id, } rs, _ := p.GetRow() c.JSON(http.StatusOK, gin.H{ "result": rs, }) } //獲得所有記錄 func GetAll(c *gin.Context) { p := Person{} rs, _ := p.GetRows() c.JSON(http.StatusOK, gin.H{ "list": rs, }) } func UpdateUser(c *gin.Context) { ids := c.Request.FormValue("id") id, _ := strconv.Atoi(ids) telephone := c.Request.FormValue("telephone") person := Person{ Id:id, Telephone:telephone, } row := person.Update() msg := fmt.Sprintf("updated successful %d", row) c.JSON(http.StatusOK, gin.H{ "msg": msg, }) } //刪除一條記錄 func DelUser(c *gin.Context) { ids := c.Request.FormValue("id") id, _ := strconv.Atoi(ids) row := Delete(id) msg := fmt.Sprintf("delete successful %d", row) c.JSON(http.StatusOK, gin.H{ "msg": msg, }) }
路由
最后就是把路由抽離出來,修改router.go,我們在路由文件中封裝路由函數
package main import ( "github.com/gin-gonic/gin" . "gin_restful2/api" ) func initRouter() *gin.Engine { router := gin.Default() router.GET("/", IndexUsers) //http://localhost:8806 //路由群組 users := router.Group("api/v1/users") { users.GET("", GetAll) //http://localhost:8806/api/v1/users users.POST("/add", AddUsers) //http://localhost:8806/api/v1/users/add users.GET("/get/:id", GetOne) //http://localhost:8806/api/v1/users/get/5 users.POST("/update", UpdateUser) users.POST("/del", DelUser) } return router }
app入口
最后就是main函數的app入口,將路由導入,同時我們要在main函數結束的時候,關閉全局的數據庫連接池:
main.go
package main import ( "gin_restful2/db" ) func main() { defer db.SqlDB.Close() router := initRouter() router.Run(":8806") }
至此,我們就把簡單程序進行了更好的組織。當然,golang的程序組織依包為基礎,不拘泥,根據具體的應用場景可以組織。
此時運行項目,不能像之前簡單的使用go run main.go
,因為包main包含main.go和router.go的文件,因此需要運行go run *.go
命令編譯運行。如果是最終編譯二進制項目,則運行go build -o app