gin框架目前应该是go web开发用的最多的一款框架,目前已经有60k星。趁着今天请假,从头搭建个gin项目mvc骨架。
新建项目,按照充血模型新建gin框架开发骨架,按照开发习惯建立些空的文件

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层的独立性