文/朱季謙
環境准備:安裝Gin與Gorm
本文搭建准備環境:Gin+Gorm+MySql。
Gin是Go語言的一套WEB框架,在學習一種陌生語言的陌生框架,最好的方式,就是用我們熟悉的思維去學。作為一名后端Java開發,在最初入門時,最熟悉的莫過於MVC分層結構,可以簡單歸納成controller層,model層,dao層,而在SpringBoot框架里,大概也經常看到以下的分層結構——
這個結構分為java根目錄與resources資源目錄。
在學習Go語言的Gin框架時,是否也可以參照這樣的分層結構來搭建一套簡單的后端系統呢。
答案是,肯定的。
接下來,我們就按照這個MVC分層結構,搭建一套基於Gin+Gorm框架的Go語言后端。
搭建之前,先簡單介紹一下Gin和Gorm分別是什么。
Gin是一個golang的WEB框架,很輕量,依賴到很少,有些類似Java的SpringMVC,通過路由設置,可以將請求轉發到對應的處理器上。
Gorm是Go語言的ORM框架,提供一套對數據庫進行增刪改查的接口,使用它,就可以類似Java使用Hibernate框架一樣,可對數據庫進行相應操作。
若要用到這兩套框架,就需要import依賴進來,依賴進來前,需要Go命令安裝Gin和Gorm。
go get -u github.com/gin-gonic/gin
go get -u github.com/jinzhu/gorm
最好放在GOPATH目錄下。
我的GOPATH目錄在C:\Users\Administrator\go下:
通過Go命令安裝的依賴包放在這個目錄底下C:\Users\Administrator\go\src下:
現在,我們就參考SpringBoot的分層結構,搭建一套MVC分層結構系統。
一、搭建根目錄與資源目錄。
先創建一個Go項目,這里,我取名為go-admin,底下創建一個go目錄,用於存放Go代碼;一個resources資源目錄,存放配置文件,結構如下——
go根目錄底下,創建controller、service、dao、entity包,另外,還需要一個router包,用於存放路由文件,可能你對路由文件不是很理解,那么,你可以簡單理解為,這個路由的作用,就類似SpringMVC的@RequestMapping("/user")和@GetMapping("/list")注解組合起到的作用,通過路由,就可以找到需要調用的后端方法。創建完這些包后,若在SpringBoot項目里,是否還缺少一個xxxxxApplication.java的啟動類,沒錯,在Go里,同樣需要一個啟動類,該啟動類文件可以直接命名為main.go。
創建以上包與類后,go根目錄底下結構如下:
接下來,是在resources資源目錄創建一個application.yaml配置文件,當然,這個配置文件可以隨便命名,不用像SpringBoot那樣需要考慮其命名背后所代表的優先級。
這個配置文件里,就存放需要用到的Mysql數據庫連接信息:
url: 127.0.0.1
userName: root
password: root
dbname: example
post: 3306
這些基礎工作做好后,就可以填充代碼了。
二、dao層的搭建。
在dao層下,建立一個mysql.go文件,這個文件在dao的包下,最初的效果如下
按照以往jdbc連接數據庫的步驟,首先需要加載jdbc驅動程序,然后再創建數據庫的連接,其實,在Go連接數據庫,同樣需要類似這樣的操作。
首先,需要導入數據庫驅動程序。
Gorm已經包含了驅動程序,只需要將它導入進來即可:
import _ "github.com/jinzhu/gorm/dialects/mysql"
進入到這個依賴包的源碼,根據命名就可以看到出,這是一個go語言的mysql驅動包——
除此之外,還提供了mssql、postgres、sqlite的驅動包。
底層使用到的是GORM 框架,自然也要把它依賴進來:
import "github.com/jinzhu/gorm"
另外,還需要依賴以下幾個包,用於讀取yaml配置文件數據與拼接成url字符串:
import "io/ioutil"
import "gopkg.in/yaml.v2"
import "fmt"
當依賴的包過多時,我們可以統一放到一個()號里,例如這樣:
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"io/ioutil"
"gopkg.in/yaml.v2"
"fmt"
)
到這一步,效果如下:
這里爆紅色是正常的,Go語言與Java不同的一個地方是,若依賴進來的包,沒有被用到話,會直接出現紅色異常提示,后面寫到用到它們的代碼時,就正常了。
接下來,定義一個用於接收yaml配置參數的struct結構體,你可以簡單將它理解為Java的類。
type conf struct {
Url string `yaml:"url"`
UserName string `yaml:"userName"`
Password string `yaml:"password"`
DbName string `yaml:"dbname"`
Port string `yaml:"post"`
}
然后提供一個讀取解析該yaml配置的方法,將讀取到的配置參數數據轉換成上邊的結構體conf
func (c *conf) getConf() *conf {
//讀取resources/application.yaml文件
yamlFile, err := ioutil.ReadFile("resources/application.yaml")
//若出現錯誤,打印錯誤提示
if err != nil {
fmt.Println(err.Error())
}
//將讀取的字符串轉換成結構體conf
err = yaml.Unmarshal(yamlFile, c)
if err != nil {
fmt.Println(err.Error())
}
return c
}
后面可以通過debug觀察一下,這個返回的c變量,它就類似Java的對象,里邊是key-value形式的值——
最后,就可以根據這些解析到的配置參數,用來驅動連接數據庫了。
創建一個類似舊版mybatis全局的SqlSession變量,就取名為SqlSession即可,該變量起到作用於mybatis的SqlSession實例類似,在數據庫驅動連接成功后,即可提供select/insert/update/delete方法。
var SqlSession *gorm.DB
然后定義一個初始化連接數據庫的方法,該方法用於在啟動項目時執行——
func InitMySql()(err error) {
var c conf
//獲取yaml配置參數
conf:=c.getConf()
//將yaml配置參數拼接成連接數據庫的url
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
conf.UserName,
conf.Password,
conf.Url,
conf.Port,
conf.DbName,
)
//連接數據庫
SqlSession,err =gorm.Open("mysql",dsn)
if err !=nil{
panic(err)
}
//驗證數據庫連接是否成功,若成功,則無異常
return SqlSession.DB().Ping()
}
最后,還需要提供一個可以關閉數據庫連接的方法——
func Close() {
SqlSession.Close()
}
到這里,我們就完成了Dao層的搭建,該層里的代碼主要負責連接數據庫,創建一個取名為SqlSession全局的*gorm.DB變量,該變量作用類似SqlSession,提供了操作數據庫的方法,最后,整塊dao層的mysql.go代碼就如下:
package dao
import (
"github.com/jinzhu/gorm"
"io/ioutil"
)
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"io/ioutil"
"gopkg.in/yaml.v2"
"fmt"
)
//指定驅動
const DRIVER = "mysql"
var SqlSession *gorm.DB
//配置參數映射結構體
type conf struct {
Url string `yaml:"url"`
UserName string `yaml:"userName"`
Password string `yaml:"password"`
DbName string `yaml:"dbname"`
Port string `yaml:"post"`
}
//獲取配置參數數據
func (c *conf) getConf() *conf {
//讀取resources/application.yaml文件
yamlFile, err := ioutil.ReadFile("resources/application.yaml")
//若出現錯誤,打印錯誤提示
if err != nil {
fmt.Println(err.Error())
}
//將讀取的字符串轉換成結構體conf
err = yaml.Unmarshal(yamlFile, c)
if err != nil {
fmt.Println(err.Error())
}
return c
}
//初始化連接數據庫,生成可操作基本增刪改查結構的變量
func InitMySql()(err error) {
var c conf
//獲取yaml配置參數
conf:=c.getConf()
//將yaml配置參數拼接成連接數據庫的url
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
conf.UserName,
conf.Password,
conf.Url,
conf.Port,
conf.DbName,
)
//連接數據庫
SqlSession,err =gorm.Open(DRIVER,dsn)
if err !=nil{
panic(err)
}
//驗證數據庫連接是否成功,若成功,則無異常
return SqlSession.DB().Ping()
}
//關閉數據庫連接
func Close() {
SqlSession.Close()
}
三、entity層定義模型。
Gorm是全特性的ORM框架,即對象關系映射,這樣,就需要類似Java那樣建立與數據庫映射的類,在Go語言當中,我們稱之為結構體。
首先,先創建一張用於驗證的數據庫表結構——
CREATE TABLE `sys_user` (
`id` int(50) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '用戶名',
`nick_name` varchar(150) DEFAULT NULL COMMENT '昵稱',
`avatar` varchar(150) DEFAULT NULL COMMENT '頭像',
`password` varchar(100) DEFAULT NULL COMMENT '密碼',
`email` varchar(100) DEFAULT NULL COMMENT '郵箱',
`mobile` varchar(100) DEFAULT NULL COMMENT '手機號',
`create_time` bigint(50) DEFAULT NULL COMMENT '更新時間',
`del_status` tinyint(4) DEFAULT '0' COMMENT '是否刪除 -1:已刪除 0:正常',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='用戶表';
然后創建一個User.go文件,里邊定義一個User結構體——
type User struct {
Id int `json:"id"`
Name string `json:"name"`
NickName string `json:"nickName"`
Avatar string `json:"avatar"`
Password string `json:"password"`
Email string `json:"email"`
Mobile string `json:"mobile"`
DelStatus int `json:"delStatus"`
CreateTime int64 `json:"createTime"`
}
注意一點,這里需要明確指出,其struct結構體映射到哪一張表,如果沒有顯示指出,它會默認生成一張命名為users的數據庫表——
// 數據庫表明自定義,默認為model的復數形式,比如這里默認為 users
func (User) TableName() string {
return "sys_user"
}
到這一步,我們就完成了user模型關系建立。
package entity
// 數據庫表明自定義,默認為model的復數形式,比如這里默認為 users
func (User) TableName() string {
return "sys_user"
}
type User struct {
Id int `json:"id"`
Name string `json:"name"`
NickName string `json:"nickName"`
Avatar string `json:"avatar"`
Password string `json:"password"`
Email string `json:"email"`
Mobile string `json:"mobile"`
DelStatus int `json:"delStatus"`
CreateTime int64 `json:"createTime"`
}
四、service層建立增刪改查業務邏輯。
在service層建立一個User的service類,命名為UserService.go。
這里,需要引入兩個依賴,一個是dao層創建的全局SqlSession,用於操作數據庫;一個是User類,用於接收數據庫對應表結構的數據。
import (
"go-admin/go/dao"
"go-admin/go/entity"
)
接下來,就可以基於SqlSession獲取到的API接口,對數據庫進行簡單的增刪改查操作了。
1.添加User信息
/**
新建User信息
*/
func CreateUser(user *entity.User)(err error) {
if err = dao.SqlSession.Create(user).Error;err!=nil{
return err
}
return
}
2.查詢所有的User記錄
/**
獲取user集合
*/
func GetAllUser()(userList []*entity.User,err error) {
if err:=dao.SqlSession.Find(&userList).Error;err!=nil{
return nil,err
}
return
}
3.根據id刪除對應的User信息
/**
根據id刪除user
*/
func DeleteUserById(id string)(err error){
err = dao.SqlSession.Where("id=?",id).Delete(&entity.User{}).Error
return
}
4.根據id查詢用戶User
/**
根據id查詢用戶User
*/
func GetUserById(id string)(user *entity.User,err error) {
if err = dao.SqlSession.Where("id=?",id).First(user).Error;err!=nil{
return nil,err
}
return
}
5.更新用戶信息
/**
更新用戶信息
*/
func UpdateUser(user * entity.User)(err error) {
err = dao.SqlSession.Save(user).Error
return
}
UserService.go的完整代碼如下:
package service
import (
"go-admin/go/dao"
"go-admin/go/entity"
)
/**
新建User信息
*/
func CreateUser(user *entity.User)(err error) {
if err = dao.SqlSession.Create(user).Error;err!=nil{
return err
}
return
}
/**
獲取user集合
*/
func GetAllUser()(userList []*entity.User,err error) {
if err:=dao.SqlSession.Find(&userList).Error;err!=nil{
return nil,err
}
return
}
/**
根據id刪除user
*/
func DeleteUserById(id string)(err error){
err = dao.SqlSession.Where("id=?",id).Delete(&entity.User{}).Error
return
}
/**
根據id查詢用戶User
*/
func GetUserById(id string)(user *entity.User,err error) {
if err = dao.SqlSession.Where("id=?",id).First(user).Error;err!=nil{
return nil,err
}
return
}
/**
更新用戶信息
*/
func UpdateUser(user * entity.User)(err error) {
err = dao.SqlSession.Save(user).Error
return
}
五、controller層建立User的controller類。
在controller層建立一個UserController.go類,類似Java的controller,主要用於根據url跳轉執行到對應路徑的方法。
首先,引入需要用到的依賴包,
import (
//需要用到的結構體
"go-admin/go/entity"
//gin框架的依賴
"github.com/gin-gonic/gin"
//http連接包
"net/http"
//service層方法
"go-admin/go/service"
)
接下來,可以實現增刪改查的controller方法了。
1.實現新增User的方法
func CreateUser(c *gin.Context) {
//定義一個User變量
var user entity.User
//將調用后端的request請求中的body數據根據json格式解析到User結構變量中
c.BindJSON(&user)
//將被轉換的user變量傳給service層的CreateUser方法,進行User的新建
err:=service.CreateUser(&user)
//判斷是否異常,無異常則返回包含200和更新數據的信息
if err!=nil{
c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
}else {
c.JSON(http.StatusOK,gin.H{
"code":200,
"msg":"success",
"data":user,
})
}
}
2.查詢User的方法
func GetUserList(c *gin.Context) {
todoList,err :=service.GetAllUser()
if err!=nil{
c.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
}else {
c.JSON(http.StatusOK,gin.H{
"code":200,
"msg":"success",
"data":todoList,
})
}
}
六、routes層增加路由文件,用於根據請求url進行轉發。
routes層新建一個Routers.go文件。
首先,同樣需要引入需要用到的依賴——
import (
"go-admin/go/controller"
"github.com/gin-gonic/gin"
)
然后搭建一個初始化路由的操作,將路由統一存放到數據user的group組里,這樣可以比較方便區分這些路由數據哪個controller類的。
Routers.go文件完整代碼如下:
package routes
import (
"go-admin/go/controller"
"github.com/gin-gonic/gin"
)
func SetRouter() *gin.Engine {
r :=gin.Default()
/**
用戶User路由組
*/
userGroup :=r.Group("user")
{
//增加用戶User
userGroup.POST("/users",controller.CreateUser)
//查看所有的User
userGroup.GET("/users",controller.GetUserList)
//修改某個User
userGroup.PUT("/users/:id",controller.UpdateUser)
//刪除某個User
userGroup.DELETE("/users/:id",controller.DeleteUserById)
}
return r
}
七、main啟動類。
最后一步,就是建立main的啟動類了,需要注意一點是,go的啟動類,必須命名在package main的包下,否則無法進行啟動。
首先,還是需要先引入依賴,main啟動類需要用到dao、entity、routers以及mysql驅動包。
import (
"go-admin/go/dao"
"go-admin/go/entity"
"go-admin/go/routes"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
啟動方法里的代碼主要如下,即前邊搭建的東西,這里都有用到了——
func main() {
//連接數據庫
err :=dao.InitMySql()
if err !=nil{
panic(err)
}
//程序退出關閉數據庫連接
defer dao.Close()
//綁定模型
dao.SqlSession.AutoMigrate(&entity.User{})
//注冊路由
r :=routes.SetRouter()
//啟動端口為8085的項目
r.Run(":8081")
}
到這一步,就可以啟動項目了,正常情況下,啟動成功會顯示以下日志信息——
到這一步,基於Gin+Gorm框架搭建MVC模式的Go后端系統,就初步搭建完成了。
最后,代碼已經上傳到GitHub:https://github.com/z924931408/go-admin.git
歡迎關注公眾號,關於思考,關於文化,關於成長——