文/朱季谦java
本文搭建准备环境:Gin+Gorm+MySql。mysql
Gin是Go语言的一套WEB框架,在学习一种陌生语言的陌生框架,最好的方式,就是用咱们熟悉的思惟去学。做为一名后端Java开发,在最初入门时,最熟悉的莫过于MVC分层结构,能够简单概括成controller层,model层,dao层,而在SpringBoot框架里,大概也常常看到如下的分层结构——git
这个结构分为java根目录与resources资源目录。github
在学习Go语言的Gin框架时,是否也能够参照这样的分层结构来搭建一套简单的后端系统呢。golang
答案是,确定的。sql
接下来,咱们就按照这个MVC分层结构,搭建一套基于Gin+Gorm框架的Go语言后端。数据库
搭建以前,先简单介绍一下Gin和Gorm分别是什么。json
Gin是一个golang的WEB框架,很轻量,依赖到不多,有些相似Java的SpringMVC,经过路由设置,能够将请求转发到对应的处理器上。后端
Gorm是Go语言的ORM框架,提供一套对数据库进行增删改查的接口,使用它,就能够相似Java使用Hibernate框架同样,可对数据库进行相应操做。mybatis
若要用到这两套框架,就须要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层下,创建一个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() }
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层创建一个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层创建一个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层新建一个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的启动类了,须要注意一点是,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
欢迎关注公众号,关于思考,关于文化,关于成长——