基于Gin+Gorm框架搭建MVC模式的Go语言企业级后端系统

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 基于Gin+Gorm框架搭建MVC模式的Go语言企业级后端系统

文/朱季谦

环境准备:安装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

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
4天前
|
Java Go C++
Go语言中的面向对象编程实践
【2月更文挑战第10天】本文将深入探讨在Go语言中如何进行面向对象编程实践。我们将了解如何在Go中实现封装、继承和多态,以及如何利用结构体、接口和方法来构建健壮和可维护的对象导向程序。通过实际代码示例,我们将更好地理解Go的OOP特性,并学习如何有效地运用它们。
|
4天前
|
SQL 前端开发 Go
编程笔记 GOLANG基础 001 为什么要学习Go语言
编程笔记 GOLANG基础 001 为什么要学习Go语言
|
1天前
|
关系型数据库 MySQL 数据库连接
实战演练:使用Go语言和ORM框架与数据库进行交互
【2月更文挑战第13天】本文将通过一个实战演练,展示如何使用Go语言和ORM(对象关系映射)框架与数据库进行交互。我们将选择一个流行的ORM框架,如GORM,来完成这个任务。通过实际编码,我们将演示如何连接数据库、执行CRUD操作、处理错误和异常,并展示ORM框架如何简化数据库操作过程。
|
1天前
|
SQL 关系型数据库 MySQL
Go语言中的ORM框架介绍
【2月更文挑战第13天】本文将介绍ORM(对象关系映射)框架在Go语言中的应用。ORM框架能够简化数据库操作,将数据库表映射为Go结构体,并提供了一系列方法来执行CRUD(创建、读取、更新、删除)操作。我们将探讨几个流行的Go语言ORM框架,包括GORM、SQLBoiler和Squirrel,并比较它们的特性和用法。
|
1天前
|
SQL 关系型数据库 MySQL
Go语言与数据库基础交互:SQL篇
【2月更文挑战第13天】本文旨在探讨Go语言如何与数据库进行基础交互,特别关注使用SQL语言进行操作。我们将首先简要介绍Go语言与数据库的连接方式,然后详细讲解如何在Go中执行SQL查询、插入、更新和删除操作。此外,还将讨论如何处理查询结果以及处理可能遇到的错误和异常。
|
1天前
|
Go 开发工具 Windows
【GO语言】windows下GO语言环境搭建
【2月更文挑战第1天】windows下GO语言环境搭建
|
1天前
|
JSON Go API
Go语言网络编程:HTTP客户端开发实战
【2月更文挑战第12天】本文将深入探讨使用Go语言开发HTTP客户端的技术细节,包括发送GET和POST请求、处理响应、错误处理、设置请求头、使用Cookie等方面。通过实例演示和代码解析,帮助读者掌握构建高效、可靠的HTTP客户端的关键技术。
|
1天前
|
JSON 缓存 中间件
Go语言网络编程:深入探索HTTP服务器开发
【2月更文挑战第12天】本文将详细探讨使用Go语言开发HTTP服务器的过程,包括HTTP协议的理解、Go标准库中`net/http`包的使用、路由处理、中间件、静态文件服务、JSON处理以及性能优化等方面。通过本文,读者将能够掌握构建高效、可扩展HTTP服务器的关键技术。
|
1天前
|
网络协议 Go 开发者
Go语言网络编程基础:构建高效、可靠的网络应用
【2月更文挑战第12天】本文将深入探讨Go语言在网络编程领域的基础知识,包括其强大的并发模型、网络库的使用、TCP/IP和HTTP协议的理解等。通过本文,读者将能够理解Go语言在网络编程中的优势,并掌握构建高效、可靠网络应用的核心技能。
|
2天前
|
监控 Java 编译器
Go语言内存与并发性能综合优化策略
【2月更文挑战第11天】Go语言以其高效的并发处理能力和简洁的内存管理机制成为了现代软件开发中的热门选择。然而,在实际应用中,如何综合优化Go程序的内存使用和并发性能,仍然是一个值得探讨的话题。本文将深入探讨Go语言内存与并发性能的综合优化策略,包括内存布局优化、并发模式设计、资源池化以及性能监控与分析等方面,旨在帮助开发者全面提升Go程序的整体性能。

相关产品

  • 云迁移中心