我从头到尾实现了一个Golang的依赖注入框架,并且集成了gin、xorm、redis、cron、消息中间件等功能;自己觉得还挺好用的,推荐给你!也欢迎一起维护!
github地址:https://github.com/gone-io/gone
文档地址:https://goner.fun/
如果可能,请帮忙在github上点个 ⭐️ ;万分感谢!!
1.安装gone辅助工具
go install github.com/gone-io/gone/tools/gone@latest
安装可以使用gone命令:
gone -h
支持的功能:
- create,创建一个gone app,暂时只支持创建web app
- priest,为项目自动生成 Priest 函数,了解更多
- 生成用于测试的mock代码
2.创建一个web项目并运行代码
# 创将一个名为 web-app 的项目
gone create web-app
cd web-app
make run
项目结构
- cmd/server/main.go: 启动文件,main函数所在文件
- config/: 项目配置文件目录,支持
.properties
文件 - internal/router/: 在该目录定义路由器
- internal/middleware/: 中间件目录,如果需要定义web中间件,在该目录编写
- internal/controller/: controller目录,在该目录中的文件定义路由
- internal/interface/service/: 该目录放服务的接口定义
- internal/domain/: 该目录放领域对象
- internal/entity/: 该目录放一些无逻辑的结构体,类似于Java 的POJO
- internal/module/: 模块目录,下面的每一个子目录实现一个模块的功能,一般是internal/interface/service/中定义的服务的业务实现;
- internal/pkg/: 在该目录可以放一些项目共用的工具代码
- internal/master.go: 存放MasterPriest函数
- internal/priest.go: gone priest 命令生成的 Priest函数,用于埋葬所有Goner
3.Router
在目录internal/router
中分别实现了两个gin.IRouter
:
- pubRouter,公开的路由,挂载在该路由下的接口,请求将无需授权即可访问。
- authRouter,鉴权的路由,挂载在该路由下的接口,请求必须先要经过授权。
我们来分析internal/router/pub_router.go
的代码:
package router
import (
"web-app/internal/middleware"
"github.com/gone-io/gone"
"github.com/gone-io/gone/goner/gin"
)
const IdRouterPub = "router-pub"
//go:gone
func NewPubRouter() (gone.Goner, gone.GonerId) {
return &pubRouter{}, IdRouterPub
}
type pubRouter struct {
gone.Flag
gin.IRouter
root gin.IRouter `gone:"gone-gin-router"`
pub *middleware.PubMiddleware `gone:"*"`
}
func (r *pubRouter) AfterRevive() gone.AfterReviveError {
r.IRouter = r.root.Group("/api", r.pub.Next)
return nil
}
- 对于router,需要实现了
gin.IRouter
接口中定义的方法; - 结构体
pubRouter
内嵌了一个gin.IRouter
,就等于直接实现了gin.IRouter
接口,只在AfterRevive()
中将其赋予一个值就可以了; r.IRouter = r.root.Group("/api", r.pub.Next)
意思是当前路由是根路由下/api
的子路由,并且默认的增加了一个中间r.pub.Next
;root gin.IRouter
是一个Gone框架中github.com/gone-io/gone/goner/gin
包提供的一个框架级Goner,具名注入的gone-gin-router
。
4.Controller
下面是Controller接口的定义:
// Controller 控制器接口,由业务代码编码实现,用于挂载和处理路由
// 使用方式参考 [示例代码](https://gitlab.openviewtech.com/gone/gone-example/-/tree/master/gone-app)
type Controller interface {
// Mount 路由挂载接口,改接口会在服务启动前被调用,该函数的实现通常情况应该返回`nil`
Mount() MountError
}
编写http接口,我们需要实现Controller
接口,在Mount
方法中实现接口路由的挂载,如internal/controller/demo_ctr.go
的代码:
package controller
import (
"web-app/internal/interface/service"
"web-app/internal/pkg/utils"
"github.com/gone-io/gone"
"github.com/gone-io/gone/goner/gin"
)
//go:gone
func NewDemoController() gone.Goner {
return &demoController{}
}
type demoController struct {
gone.Flag
demoSvc service.IDemo `gone:"*"` //注入依赖的服务
authRouter gin.IRouter `gone:"router-auth"` //注入路由器
pubRouter gin.IRouter `gone:"router-pub"` //注入路由器
}
func (ctr *demoController) Mount() gin.MountError {
//需要鉴权的路由分组
ctr.
authRouter.
Group("/demo").
GET("/show", ctr.showDemo)
//不需要鉴权的路由分组
ctr.
pubRouter.
Group("/demo2").
GET("/show", ctr.showDemo).
GET("/error", ctr.error).
GET("/echo", ctr.echo)
return nil
}
func (ctr *demoController) showDemo(ctx *gin.Context) (any, error) {
return ctr.demoSvc.Show()
}
func (ctr *demoController) error(ctx *gin.Context) (any, error) {
return ctr.demoSvc.Error()
}
func (ctr *demoController) echo(ctx *gin.Context) (any, error) {
type Req struct {
Echo string `form:"echo"`
}
var req Req
if err := ctx.Bind(&req); err != nil {
return nil, gin.NewParameterError(err.Error(), utils.ParameterParseError)
}
return ctr.demoSvc.Echo(req.Echo)
}
5.Service
规范上,我们要求将服务的接口定义在internal/interface/service
目录,文件名以i_
打头,接口类型以I
打头,例如:
文件:i_demo.go
package service
import "web-app/internal/interface/domain"
type IDemo interface {
Show() (*domain.DemoEntity, error)
Echo(input string) (string, error)
Error() (any, error)
}
服务的逻辑实现,放到internal/module
目录分模块实现。
求赞助
如果觉得还可以,请帮忙在github上点个 ⭐️吧:
github地址:https://github.com/gone-io/gone
福利:🔥添加交流群,赠送 Golang 多套 学习资料,夯实基础👍🏻👍🏻