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.go
package app
import "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 model
type 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.go
package 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.go
package app
import (
"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.go
package api
import "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.go
package app
import (
"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.go
package app
func (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 app
import (
"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.go
func 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.go
func (s Service) Hello() string {return "Hello World"}
Api 实现
// Package app api.go
package app
type 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.go
package app
import ("github.com/songcser/gingo/pkg/admin")
func Admin() {
var a App
admin.New(a, "app", "利用")
}
在 initialize 中引入 admin
// Package initialize admin.go
package initialize
func Admin(r *gin.Engine) {
if !config.GVA_CONFIG.Admin.Enable {return}
admin.Init(r, nil)
app.Admin()}
在治理页面能够进行简略的查问,创立,批改,删除操作。
Model 字段中能够配置 admin 标签,治理页面能够依据类型展现。
// Package app model.go
package app
import "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/
首页
点击利用,查看利用列表
点击 创立利用 按钮