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

文/朱季谦

环境准备:安装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())}//将读取的字符串转换成结构体conferr = 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配置参数拼接成连接数据库的urldsn := 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 daoimport ("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())}//将读取的字符串转换成结构体conferr = 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配置参数拼接成连接数据库的urldsn := 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{}).Errorreturn
}

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).Errorreturn
}

UserService.go的完整代码如下:

package serviceimport ("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{}).Errorreturn
}/**
根据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).Errorreturn
}

五、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 routesimport (
"go-admin/go/controller"
"github.com/gin-gonic/gin"
)func SetRouter() *gin.Engine  {r :=gin.Default()/**用户User路由组*/userGroup :=r.Group("user"){//增加用户UseruserGroup.POST("/users",controller.CreateUser)//查看所有的UseruserGroup.GET("/users",controller.GetUserList)//修改某个UseruserGroup.PUT("/users/:id",controller.UpdateUser)//删除某个UseruserGroup.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:GitHub - z924931408/go-admin: 这是个人Go语言基于Gin+gorm框架搭建的MVC结构的后端模块。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/196407.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows Oracle Database 19c 卸载教程

目录 打开任务管理器 停止数据库服务 Universal Installer 卸载Oracle数据库程序 使用Oracle Installer卸载 删除注册表项 重新启动系统 打开任务管理器 ctrlShiftEsc可以快速打开任务管理器,找到oracle所有服务然后停止。 停止数据库服务 在开始卸载之前&a…

和鲸科技创始人范向伟受邀出席“凌云出海,来中东吧”2023华为云上海路演活动

11月9日,华为云“凌云出海,来中东吧”系列路演活动第二场在上海正式开启。聚焦“创业全球化”,本次活动由华为云携手阿布扎比投资办公室(ADIO)举办,旨在与渴望出海发展的优秀创业者们共探出海中东新商机。 …

ogrinfo不是内部或者外部命令

这个是GDAL的问题,我是通过OSGeo4w安装的,出来就是这个问题,教程没有仔细看干。 第一次安装,选择express install!!!! 第一次安装,选择express install!&…

M系列 Mac使用Homebrew下载配置git和连接GitHub

一、首先我们需要安装Homebrew M系列 Mac安装配置Homebrewhttps://blog.csdn.net/W_Fe5/article/details/134428377?spm1001.2014.3001.5501 二、下载git 1、终端输入一下命令 brew install git 2、这时下载完成 二、配置git 1、创建用户名和邮箱 这里以我自己的邮箱举例…

Anaconda的安装使用及pycharm设置conda虚拟环境

1.python和包以及anaconda的概念关系 python “工人” 包 “工具” 环境 “工具箱” anaconda “放很多工具箱的大箱子” python等于工人这个好理解,就是编程需要用python来实现对应功能,即工人完成某项工程。 包等于工具,就是工人…

Flask 接口

目录 前言 代码实现 简单接口实现 执行其它程序接口 携带参数访问接口 前言 有时候会想着开个一个接口来访问试试,这里就给出一个基础接口代码示例 代码实现 导入Flask模块,没安装Flask 模块需要进行 安装:pip install flask 使用镜…

【计算机基础】优雅的PPT就应该这样设计

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…

C++模版初阶

泛型编程 如下的交换函数中,它们只有类型的不同,应该怎么实现一个通用的交换函数呢? void Swap(int& left, int& right) {int temp left;left right;right temp; }void Swap(double& left, double& right) {double temp…

带您识别RJ45网口连接器/网口插座口的LED灯的平脚/斜脚,带弹/不带弹细节区分

Hqst华强盛(盈盛电子)导读:网口连接器,网口插座,也叫网口母座,因为产品规格众多,常常因为细小差别,耽误工程设计级或者生产排期延误,今天就带大家一起来认识下平脚RJ45网口连接器/网口插座与斜脚…

小程序申请,商户号申请,微信支付开通操作流程

总目录 文章目录 总目录前言1 申请商户号(如已有商户号跳过)1 申请流程与资料2 详细申请步骤 2 申请开通接入微信支付步骤3 申请微信小程序1 申请小程序步骤2 查看小程序AppID 4 微信支付普通商户与AppID账号关联结语 前言 本文主要讲解如何申请微信商户…

jupyter修改默认打开目录

当我们打开jupyter notebook(不管用什么样的方式打开,使用菜单打开或者是命令行打开是一样的)会在默认的浏览器中看到这样的界面、 但是每一台不同的电脑打开之后的界面是不同的,仔细观察就会发现,这里面现实的一些文件…

Flutter 3.16 中带来的更新

Flutter 3.16 中带来的更新 目 录 1. 概述2. 框架更新2.1 Material 3 成为新默认2.2 支持 Material 3 动画2.3 TextScaler2.4 SelectionArea 更新2.5 MatrixTransition 动画2.6 滚动更新2.7 在编辑菜单中添加附加选项2.8 PaintPattern 添加到 flutter_test 3. 引擎更新&#xf…

基于flask和fomantic-ui的简易p2p文件分享平台的手动实现

背景 开学一个多月了,由于繁重的学业和懒惰,都没怎么更新有意思的博客。 前几天突然想到了一个想法。同学之间平常用网络分享一个文件,大部分都是用的qq。但是qq看起来把文件拖到聊天框点击发送就发给对面同学了。但是实际上是先上传到了腾…

数据库选型与优化:策略与技巧的探讨

大家好,我是一名狂热的数据库程序员,最近鼓起勇气开始吐槽一下数据库,如有雷同,请对号入座。 名不副实的数据库类型 先说说最近的事,我们业务有很多图片要管理,老板说让我选个专业的图数据库,…

【论文精读3】CasMVSNet

模型处理过程: 一. 问题引入 基于学习的MVS算法因为受到显存的限制,输出的深度图的空间分辨率只有输入图像的1/16大小(长宽均为输入图像的1/4大小)。以MVSNet为例,对于16001184大小的输入图像,需要构建hwD…

元数据管理,数字化时代企业的基础建设

随着新一代信息化、数字化技术的应用,众多领域通过科技革命和产业革命实现了深度化的数字改造,进入到以数据为核心驱动力的,全新的数据处理时代,并通过业务系统、商业智能BI等数字化技术和应用实现了数据价值,从数字经…

基于STC12C5A60S2系列1T 8051单片的IIC总线器件数模芯片PCF8591实现数模转换应用

基于STC12C5A60S2系列1T 8051单片的IIC总线器件数模芯片PCF8591实现数模转换应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍IIC总线器件数模芯片PCF8591介绍通过按…

uniapp Android如何打开常用系统设置页面?

uniapp Android 如何打开常用系统设置页面? 在使用App过程时,有时候会对一些权限获取,比如打开蓝牙、打开通知栏通知等设置,我们如何快速跳转到需要的设置页面? 文章目录 uniapp Android 如何打开常用系统设置页面&…

【论文解读】GPT Understands, Too

一.论文 1.1 P-tuning 区别于之前的工作,这篇工作认为promote可以在句子中的任意位置起到作用,可以将它们插入上下文或目标中 上图中,左图是不使用任何操作,右图是选择在居首和目标前插入promote的embedding,插入pro…

java 批量更改

直接上代码 void batchUpdateSpecificationId(Param("infos") List<GoodsInfo> infos);<update id"batchUpdateSpecificationId">update goods_infoset specification_id <foreach collection"infos" item"info" open&…