Gingo

Introduce

Gingo是基于 gin 框架为外围的脚手架,可能疾速创立Restful格调的API接口,并且能提供简略的后盾治理性能,应用本我的项目能够疾速实现业务逻辑开发。

Github: https://github.com/songcser/gingo

Feature

  • gin框架,简略,高效,轻量
  • gorm数据库ORM框架,封装mapper,应用简略
  • viper配置管理
  • zap日志框架,输入日志更灵便
  • api接口封装,疾速实现CURD操作,提供Restful格调接口
  • admin后盾治理,实现了简略的后盾治理,不便进行数据管理
  • 应用范型,go版本不能低于1.18

Catalogue

.|——.gitignore|——go.mod|——go.sum|——cmd             └──migrate      └──main.go            // 注册数据库表   └──main.go               // 我的项目入口main|——README.md|——config                   // 配置文件目录|  └──autoload              // 配置文件的构造体定义包|     └──admin.go           // admin配置|     └──db.go|     └──jwt.go             // jwt配置|     └──mysql.go           // mysql配置|     └──zap.go             // zap日志配置|  └──config.yaml           // .yaml配置示例文件|  └──config.go             // 配置初始化文件|——initialize               // 数据初始化目录|  └──admin.go              // admin初始化|  └──constants.go          // 常量数据|  └──gorm.go               // 数据库初始化|  └──mysql.go              // mysql初始化|  └──router.go             // gin初始化|  └──swagger.go            |  └──viper.go              // viper配置初始化|  └──zap.go                // zap日志初始化|——internal                 // 该服务所有不对外裸露的代码,通常的业务逻辑都在这上面,应用internal防止谬误援用|──middleware               // 中间件目录|  └──logger.go             // 日志中间件,打印申请数据|  └──recovery.go           // 自定义recovery, 输入谬误格式化|──pkg                      // 外部服务包    |  └──admin                 // admin实现逻辑|     └──admin.go|     └──init.go|     └──model.go|     └──service.go|  └──api                   // API接口封装|     └──api.go|  └──auth                  // 登陆受权接口封装|     └──model.go           |     └──user.go            |  └──model                 // 底层模型封装|     └──mapper.go           |     └──model.go           |     └──page.go           |     └──wrapper.go           |  └──response              // 响应数据模型封装|     └──page.go         |     └──response.go         |  └──router                // 路由模块封装|     └──router.go          |  └──service               // 服务模块封装|     └──service.go|──templates                // admin模版页面|  └──add.html              // 新建页面|  └──edit.html             // 编辑页面|  └──embed.go          |  └──header.html           // 头部页面|  └──home.html             // 首页|  └──index.html            // 主页面|  └──login.html            // 登陆页面|  └──register.html         // 注册页面页面|  └──sidebar.html          // 右边栏页面|──utils                    // 一些工具办法|  └──cache.go              // 缓存|  └──error.go              // error查看|  └──hash.go               // hash加密解密|  └──http.go               // http客户端申请|  └──json.go               // |  └──jwt.go                // JWT|  └──path.go               // 文件门路|  └──time.go               // time相干办法|  └──translator.go         // 中英文翻译

Usage

internal目录是不对外裸露的代码,在做go get时,此目录不会被下载,所以通常业务逻辑放在这个上面。
咱们将在这个目录上面加一些业务代码,阐明脚手架的应用。

在internal目录下新增 app 包目录

Model

// Package app model.gopackage appimport "github.com/songcser/gingo/pkg/model"type App struct {   model.BaseModel   Name        string `json:"name" gorm:"column:name;type:varchar(255);not null"`   Description string `json:"description" gorm:"column:description;type:varchar(4096);not null"`   Level       string `json:"level" gorm:"column:level;type:varchar(8);not null"`   Type        string `json:"type" gorm:"column:type;type:varchar(16);not null"`}

App模型有4个自定义字段,gorm标签会对应到数据库的字段。

package modeltype Model interface {   Get() int64}type BaseModel struct {   ID        int64          `json:"id" gorm:"primarykey" admin:"disable"`                // 主键ID   CreatedAt utils.JsonTime `json:"createdAt" gorm:"index;comment:创立工夫" admin:"disable"` // 创立工夫   UpdatedAt utils.JsonTime `json:"updatedAt" gorm:"index;comment:更新工夫" admin:"disable"` // 更新工夫}func (m BaseModel) Get() int64 {   return m.ID}

BaseModel 是根底模型,有一些公共字段, 并且实现了 Model interface, 所有援用 BaseModel 的模型都实现了 Model interface。

创立数据库表

# Package initialize gorm.gopackage initialize// RegisterTables 注册数据库表专用func RegisterTables(db *gorm.DB) {   err := db.Set("gorm:table_options", "CHARSET=utf8mb4").AutoMigrate(      // 零碎模块表      auth.BaseUser{},      app.App{}, // app表注册   )   if err != nil {      os.Exit(0)   }}

执行 migrate 的 main 办法会在数据库创立对应的表。

Api

// Package app api.gopackage appimport (   "github.com/songcser/gingo/pkg/api"   "github.com/songcser/gingo/pkg/service")type Api struct {   api.Api}func NewApi() Api {   var app App   baseApi := api.NewApi[App](service.NewBaseService(app))   return Api{baseApi}}

api.Api接口

// Package api api.gopackage apiimport "github.com/gin-gonic/gin"type Api interface {   Query(c *gin.Context)   Get(c *gin.Context)   Create(c *gin.Context)   Update(c *gin.Context)   Delete(c *gin.Context)}

api.Api接口定义了CURD办法,并且办法都是gin.HandlerFunc类型,能够间接绑定到gin Router上。
BaseApi实现了CURD的根本办法,app.Api类型组合了BaseApi的办法。

Router

// Package app router.gopackage appimport (   "github.com/gin-gonic/gin"   "github.com/songcser/gingo/pkg/router")func InitRouter(g *gin.RouterGroup) {   r := router.NewRouter(g.Group("app"))   a := NewApi()   r.BindApi("", a)}

router 是对gin.RouterGroup做了简略封装,不便和Api类型做绑定。
BindApi办法将Api的 CURD 办法和router进行了绑定。

启动服务之后,执行脚本或者应用 postman 申请服务

创立数据
curl --location 'http://localhost:8080/api/v1/app' \--header 'Content-Type: application/json' \--data '{    "name": "测试利用",    "description": "测试应用服务",    "level": "S3",    "type": "container"}'

返回内容

{    "code": 0,    "data": true,    "message": "success"}

胜利创立数据

查问数据
curl --location 'http://localhost:8080/api/v1/app'

返回内容

{    "code": 0,    "data": {        "total": 1,        "size": 10,        "current": 1,        "results": [            {                "id": 1,                "createdAt": "2023-04-13 16:35:59",                "updatedAt": "2023-04-13 16:35:59",                "name": "测试利用",                "description": "测试应用服务",                "level": "S3",                "type": "container"            }        ]    },    "message": "success"}
查问单个数据
curl --location 'http://localhost:8080/api/v1/app/1'

返回内容

{    "code": 0,    "data": {        "id": 1,        "createdAt": "2023-04-13 16:56:09",        "updatedAt": "2023-04-13 16:58:29",        "name": "测试利用",        "description": "测试应用服务",        "level": "S3",        "type": "container"    },    "message": "success"}
更新数据
curl --location --request PUT 'http://localhost:8080/api/v1/app/1' \--header 'Content-Type: application/json' \--data '{    "name": "测试利用",    "description": "测试应用服务",    "level": "S1",    "type": "container"}'

返回内容

{    "code": 0,    "data": true,    "message": "success"}
删除数据
curl --location --request DELETE 'http://localhost:8080/api/v1/app/1'

返回内容

{    "code": 0,    "data": true,    "message": "success"}

自定义办法

api增加新的办法

// Package app api.gopackage appfunc (a Api) Hello(c *gin.Context) {   response.OkWithData("Hello World", c)}

router进行绑定

    r.BindGet("hello", a.Hello)

接口申请

curl --location 'http://localhost:8080/api/v1/app/hello'

返回内容

{    "code": 0,    "data": "Hello World",    "message": "success"}

Service

在 NewApi 时应用的是BaseService,能够实现自定义的Service,重写一些办法。

package appimport (   "github.com/gin-gonic/gin"   "github.com/songcser/gingo/pkg/model"   "github.com/songcser/gingo/pkg/service"   "github.com/songcser/gingo/utils")type Service struct {   service.Service[App]}func NewService(a App) Service {   return Service{service.NewBaseService[App](a)}}func (s Service) MakeMapper(c *gin.Context) model.Mapper[App] {   var r Request   err := c.ShouldBindQuery(&r)   utils.CheckError(err)   w := model.NewWrapper()   w.Like("name", r.Name)   w.Eq("level", r.Level)   m := model.NewMapper[App](App{}, w)   return m}func (s Service) MakeResponse(val model.Model) any {   a := val.(App)   res := Response{      Name:        a.Name,      Description: fmt.Sprintf("名称:%s, 等级: %s, 类型: %s", a.Name, a.Level, a.Type),      Level:       a.Level,      Type:        a.Type,   }   return res}
  • MakeMapper办法重写新的Mapper,能够自定义一些查问条件。
  • MakeResponse办法能够重写返回的内容

在Api中替换新的Service

// Package app api.gofunc NewApi() Api {   var app App   s := NewService(app)  //应用新的Service   baseApi := api.NewApi[App](s)   return Api{Api: baseApi}}
查问数据
curl --location 'http://localhost:8080/api/v1/app?name=测试&level=S3'

返回内容

{    "code": 0,    "data": {        "total": 1,        "size": 10,        "current": 1,        "results": [            {                "name": "测试利用",                "description": "名称:测试利用, 等级: S3, 类型: container",                "level": "S3",                "type": "container"            }        ]    },    "message": "success"}

如果要在Service减少新的办法,须要在Api模型中重写Service

// Package app service.gofunc (s Service) Hello() string {   return "Hello World"}

Api实现

// Package app api.gopackage apptype Api struct {   api.Api   Service Service  // 重写Service}func NewApi() Api {   var app App   s := NewService(app)   baseApi := api.NewApi[App](s)   return Api{Api: baseApi, Service: s}}func (a Api) Hello(c *gin.Context) {   str := a.Service.Hello() // 调用Service办法   response.OkWithData(str, c)}

Admin

Admin 提供了简略的后盾治理服务,能够很不便的对数据进行治理。

首先须要在配置文件中开启 Admin

admin:  enable: true  auth: true

auth 会开启认证受权,须要登陆

接入 Admin 也比较简单

// Package app admin.gopackage appimport (   "github.com/songcser/gingo/pkg/admin")func Admin() {   var a App   admin.New(a, "app", "利用")}

在 initialize 中引入 admin

// Package initialize admin.gopackage initializefunc Admin(r *gin.Engine) {   if !config.GVA_CONFIG.Admin.Enable {      return   }   admin.Init(r, nil)   app.Admin()}

在治理页面能够进行简略的查问,创立,批改,删除操作。

Model 字段中能够配置 admin 标签,治理页面能够依据类型展现。

// Package app model.gopackage appimport "github.com/songcser/gingo/pkg/model"type App struct {   model.BaseModel   Name        string `json:"name" form:"name" gorm:"column:name;type:varchar(255);not null" admin:"type:input;name:name;label:利用名"`   Description string `json:"description" form:"description" gorm:"column:description;type:varchar(4096);not null" admin:"type:textarea;name:description;label:形容"`   Level       string `json:"level" form:"level" gorm:"column:level;type:varchar(8);not null" admin:"type:radio;enum:S1,S2,S3,S4,S5;label:级别"`   Type        string `json:"type" form:"type" gorm:"column:type;type:varchar(16);not null" admin:"type:select;enum:container=容器利用,web=前端利用,mini=小程序利用;label:利用类型"`}
  • type: 字段类型,取值 input, textarea, select, radio。
  • name: 字段名称
  • label: 字段展现名称
  • enum: 枚举数据,在select,radio类型时展现更加敌对

须要增加 form 标签,因为是应用 html 的 form 提交数据。

拜访链接

http://localhost:8080/admin/
首页

点击利用,查看利用列表

点击 创立利用 按钮