基於Gin+Gorm框架搭建MVC模式的Go語言企業級後端系統

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第7天。

文/朱季謙

環境準備:安裝Gin與Gorm

本文搭建準備環境:Gin+Gorm+MySql。

Gin是Go語言的一套WEB框架,在學習一種陌生語言的陌生框架,最好的方式,就是用我們熟悉的思維去學。作為一名後端Java開發,在最初入門時,最熟悉的莫過於MVC分層結構,可以簡單歸納成controller層,model層,dao層,而在SpringBoot框架裡,大概也經常看到以下的分層結構——

image

這個結構分為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下:\ image

通過Go命令安裝的依賴包放在這個目錄底下C:\Users\Administrator\go\src下:\ image

現在,我們就參考SpringBoot的分層結構,搭建一套MVC分層結構系統。\

一、搭建根目錄與資源目錄。

先建立一個Go專案,這裡,我取名為go-admin,底下建立一個go目錄,用於存放Go程式碼;一個resources資源目錄,存放配置檔案,結構如下——\ image\ go根目錄底下,建立controller、service、dao、entity包,另外,還需要一個router包,用於存放路由檔案,可能你對路由檔案不是很理解,那麼,你可以簡單理解為,這個路由的作用,就類似SpringMVC的@RequestMapping("/user")和@GetMapping("/list")註解組合起到的作用,通過路由,就可以找到需要呼叫的後端方法。建立完這些包後,若在SpringBoot專案裡,是否還缺少一個xxxxxApplication.java的啟動類,沒錯,在Go裡,同樣需要一個啟動類,該啟動類檔案可以直接命名為main.go。

建立以上包與類後,go根目錄底下結構如下:\ image

接下來,是在resources資源目錄建立一個application.yaml配置檔案,當然,這個配置檔案可以隨便命名,不用像SpringBoot那樣需要考慮其命名背後所代表的優先順序。\ image\ 這個配置檔案裡,就存放需要用到的Mysql資料庫連線資訊:

url: 127.0.0.1 userName: root password: root dbname: example post: 3306

這些基礎工作做好後,就可以填充程式碼了。

二、dao層的搭建。

在dao層下,建立一個mysql.go檔案,這個檔案在dao的包下,最初的效果如下\ image

按照以往jdbc連線資料庫的步驟,首先需要載入jdbc驅動程式,然後再建立資料庫的連線,其實,在Go連線資料庫,同樣需要類似這樣的操作。

首先,需要匯入資料庫驅動程式。

Gorm已經包含了驅動程式,只需要將它匯入進來即可:

import _ "github.com/jinzhu/gorm/dialects/mysql"

進入到這個依賴包的原始碼,根據命名就可以看到出,這是一個go語言的mysql驅動包——\ image

除此之外,還提供了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" )

到這一步,效果如下:\ image

這裡爆紅色是正常的,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形式的值——\ image

最後,就可以根據這些解析到的配置引數,用來驅動連線資料庫了。

建立一個類似舊版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:%[email protected](%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:%[email protected](%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") }

到這一步,就可以啟動專案了,正常情況下,啟動成功會顯示以下日誌資訊——\ image

到這一步,基於Gin+Gorm框架搭建MVC模式的Go後端系統,就初步搭建完成了。

最後,程式碼已經上傳到GitHub:http://github.com/z924931408/go-admin.git