示例代码
首先来看一下结构,第一次看可能会觉得有点复杂:
.
├── api
├── go.mod
├── go.sum
├── hack
├── internal
├── main
├── main.go
├── Makefile
├── manifest
├── README.MD
├── resource
└── utility
main.go
先看看主入口的文件
package main
import (
_ "demo/internal/packed"
"github.com/gogf/gf/v2/os/gctx"
"demo/internal/cmd"
)
func main() {
cmd.Main.Run(gctx.GetInitCtx())
}
是一个正常的一句话启动,但是引入了cmd模块,看来主要入口在cmd的Main变量中
cmd.go
package cmd
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gcmd"
"demo/internal/controller/hello"
)
var (
Main = gcmd.Command{
Name: "main",
Usage: "main",
Brief: "start http server",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind(
hello.NewV1(),
)
})
s.Run()
return nil
},
}
)
可以看到,主要内容是Func,其中创建了一个Server,然后调用Group方法为根添加路由,Bind加入的是hello模块中的东西,是人为写的,跟进去看看
controller/hello
.
└── hello
├── hello.go
├── hello_new.go
└── hello_v1_hello.go
hello模块中总共三个文件,我们一个一个看
controller/hello/hello.go
这个文件是空的
controller/hello/hello_new.go
package hello
import (
"demo/api/hello"
)
type ControllerV1 struct{}
func NewV1() hello.IHelloV1 {
return &ControllerV1{}
}
这个文件里出现了上面cmd.go文件中调用的方法,它返回的是一个空结构体的引用,而方法定义的返回值又是另外一个东西
看来应该是一个接口,然后通过空结构体继承?我并不是特别熟悉这里的语法,实在抱歉本人go语言之学了半个月
不过可以看出这个hello.IHelloV1是很重要的东西了,但这里还有一个文件,先看看这个文件,里面应该是api的具体的逻辑
controller/hello/hello_v1_hello.go
package hello
import (
"context"
"github.com/gogf/gf/v2/frame/g"
v1 "demo/api/hello/v1"
)
func (c *ControllerV1) Hello(ctx context.Context, req *v1.HelloReq) (res *v1.HelloRes, err error) {
g.RequestFromCtx(ctx).Response.Writeln("Hello World!")
return
}
这里是方法的具体实现,为上一个名为ControllerV1的结构体定义了一个名为Hello的方法接受参数然后发送文本,大概是要实现接口吧
但req与res的类型并不是gf提供的通用类型,而是自定义的,咱们再跟进去看看
api
.
└── hello
├── hello.go
└── v1
└── hello.go
该文件夹主要用来表示接口格式,所以里面放的基本都是struct和interface
api/hello/hello.go
package hello
import (
"context"
"demo/api/hello/v1"
)
type IHelloV1 interface {
Hello(ctx context.Context, req *v1.HelloReq) (res *v1.HelloRes, err error)
}
这里是NewV1()方法的返回类型,一个接口,里面包含一个方法,也就是 controller/hello/hello_v1_hello.go 中的方法,该接口的具体实现也就是ControllerV1结构体
api/hello/v1/hello.go
package v1
import (
"github.com/gogf/gf/v2/frame/g"
)
type HelloReq struct {
g.Meta `path:"/hello" tags:"Hello" method:"get" summary:"You first hello api"`
}
type HelloRes struct {
g.Meta `mime:"text/html" example:"string"`
}
这里是最主要的地方,定义了请求的路径,参数类型等,甚至还有接口分类和概述,大概是为了接口文档而准备
总结
至此已经捋顺了一变示例代码的主要逻辑
- 在cmd.go中创建server和配置路由( 配置路由这一步我觉得可以与cmd.go分开来做 )
- 在api文件夹中创建接口和request&response的路径和参数等
- 在controller文件夹中实现api文件夹中定义的接口中方法的具体实现并返回给路由
当然,其中还有许多其他的内容,并且本文并没有讲到这些东西的内部具体是怎么实现的,我估计我暂时也不会
例如:
- 为什么NewV1方法仅用返回一个空的结构体即可
- 为什么在实现Hello方法的时候只要在参数中加入了定义过path的结构体HelloReq就代表注册了呢?并且创建一个新方法再加入这个参数就会报错起冲突
本人学go语言的时间并不算久,很多内容还不是很熟悉,仅停留在理论阶段,实战技能很少,请谅解