上一篇介绍了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() {varerr 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 Personstruct{
Idint `json:"id" form:"id"`
Namestring `json:"name" form:"name"`
Telephonestring `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)
}returnid
}//查询一条记录
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")forrows.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)
}returnrows
}//删除一条记录
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()
}returnrows
}
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)
}returnrouter
}
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