gin框架环境搭建

gin框架目前应该是go web开发用的最多的一款框架,目前已经有60k星。趁着今天请假,从头搭建个gin项目mvc骨架。

新建项目,按照充血模型新建gin框架开发骨架,按照开发习惯建立些空的文件

1

  • bin目录: main函数位置,以及后续可能的可执行文件源代码

  • config目录: 配置文件已经配置加载代码

  • controller: 控制器目录

  • model: 模型目录,包含dao和对应的方法

  • router: 路由配置目录

  • service: 服务层,也可以改为domain

    这里并没有增加middleware层,随用随加.如果可预见的中间件不多则放在router层一起

main.go代码

main主要做路由注册,配置初始化,http监听,数据库初始化等.对应调用router,config,model层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
engine := gin.Default()
// 初始化配置文件
config.InitConfig()
// 注册路由
router.RegisterRouter(engine)
// 初始化模型,数据库连接
model.InitDb()

if err := engine.Run(config.Properties.App.Host + ":" + strconv.Itoa(config.Properties.App.Port)); err != nil {
log.Println(err)
}

}

config层: 主要做配置文件读取, 本身和任何层不发生关联,完全由其他层调用,任意层次结构都可以调用config配置,后续方便各个模块读取配置文件,这里使用viper进行配置文件读取

配置文件采用yaml,示例配置文件如下

1
2
3
4
5
6
7
8
9
10
app:
serviceName: demo_learn
appMode: release
host: 0.0.0.0
port: 8081
db:
driverName: "mysql"
dsn: "root:123456@tcp(172.17.0.2:3306)/gorm?charset=utf8&parseTime=True&loc=Local"
defaultStringSize: 100
dontSupportNullAsDefaultValue: true

config配置代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package config

import (
"github.com/spf13/viper"
"log"
)

type DbConfig struct {
DriverName string
DSN string
DefaultStringSize int
DontSupportNullAsDefaultValue bool
}

type AppConfig struct {
ServiceName string
AppMode string
Host string
Port int
}

type Config struct {
App AppConfig
Db DbConfig
}

var Properties Config

func InitConfig() {
viper.SetTypeByDefaultValue(true)
setDefaultProperties()
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath("config")

if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
panic("配置文件未找到")
} else {
panic(err)
}
}

err := viper.Unmarshal(&Properties)
if err != nil {
panic(err)
}
log.Println(Properties)
}

func setDefaultProperties() {
viper.SetDefault("app", AppConfig{
ServiceName: "demoervicname",
AppMode: "debug",
Host: "127.0.0.1",
Port: 8080,
})
viper.SetDefault("db", DbConfig{
DriverName: "mysql",
DSN: "",
DefaultStringSize: 255,
DontSupportNullAsDefaultValue: true,
})
}

router层比较简单,负责路由注册,中间件加载操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package router

import (
"awesomeProject1/controller"
"github.com/gin-gonic/gin"
)

func RegisterRouter(engine *gin.Engine) *gin.Engine {

engine.Use(func(context *gin.Context) {
// 中间件代码
////////
context.Next()
})
// 路由注册
g := engine.Group("/user")
{
g.GET("/add", controller.UserController{}.Add)
}

return engine
}

router层要调用控制器, 控制器实现HandlerFunc即可

1
2
3
4
5
6
7
8
9
10
11
12
13
package controller

import "github.com/gin-gonic/gin"

type UserController struct {
}

func (receiver UserController) Add(c *gin.Context) {
c.JSON(200, map[string]interface{}{
"say": "hello golang",
})
}

模型层增加model.go做数据初始化等操作,本来想要加到config层做数据库初始化,但是考虑到层级调用以及后续开发可能出现的低级错误问题,则将数据库初始化放在了model层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package model

import (
"awesomeProject1/config"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)

var dbConn *gorm.DB

func InitDb() {
dbConn, err := gorm.Open(mysql.New(mysql.Config{
DriverName: "mysql",
DSN: config.Properties.Db.DSN,
}), &gorm.Config{})
if err != nil {
return
}

// 避免框架骨架阶段报变量没有使用错误,特殊需求注释掉
dbConn.DisableAutomaticPing = false
}

需要注意的是层级调用不要出现循环调用,调用顺序是 controller->service->model, config层可以任意位置被调用.并保持config层的独立性