对象注册是在注册时便给定一个实例化的对象,以后每一个请求都交给该对象(同一对象)处理, 该对象常驻内存不释放。服务端进程在启动时便需要初始化这些对象,并且这些对象需要自行负责对自身数据的并发安全维护(往往对象的成员变量应当是并发安全的,每个请求执行完毕后该对象不会销毁,其成员变量也不会释放)。
对象注册
我们可以通过 BindObject
方法完成对象的注册。
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
type Controller struct{}
func (c *Controller) Index(r *ghttp.Request) {
r.Response.Write("index")
}
func (c *Controller) Show(r *ghttp.Request) {
r.Response.Write("show")
}
func main() {
s := g.Server()
c := new(Controller)
s.BindObject("/object", c)
s.SetPort(8199)
s.Run()
}
可以看到,对象在进行路由注册时便生成了一个对象(对象在 Server
启动时便生成),此后不管多少请求进入, Server
都是将请求转交给该对象对应的方法进行处理。需要注意的是,公开方法的定义,必须为以下形式:
func(r *ghttp.Request)
否则无法完成注册,调用注册方法时会有错误提示,例如:
panic: interface conversion: interface {} is xxx, not func(*ghttp.Request)
该示例执行后,终端输出的路由表如下:
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
|---------|---------|---------|--------|---------------|--------------------------|------------|
default | default | :8199 | ALL | /object | main.(*Controller).Index |
|---------|---------|---------|--------|---------------|--------------------------|------------|
default | default | :8199 | ALL | /object/index | main.(*Controller).Index |
|---------|---------|---------|--------|---------------|--------------------------|------------|
default | default | :8199 | ALL | /object/show | main.(*Controller).Show |
|---------|---------|---------|--------|---------------|--------------------------|------------|
随后可以通过 http://127.0.0.1:8199/object/show 查看效果。
默认路由方法
控制器中的 Index
方法是一个特殊的方法,例如,当注册的路由规则为 /user
时,HTTP请求到 /user
时,将会自动映射到控制器的 Index
方法。也就是说,访问地址 /user
和 /user/index
将会达到相同的执行效果。
路由内置变量
当使用 BindObject
方法进行对象注册时,在路由规则中可以使用两个内置的变量: {.struct}
和 {.method}
,前者表示当前 对象名称,后者表示当前注册的 方法名。
我们来看一个例子:
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
type Order struct{}
func (o *Order) List(r *ghttp.Request) {
r.Response.Write("list")
}
func main() {
s := g.Server()
o := new(Order)
s.BindObject("/{.struct}-{.method}", o)
s.SetPort(8199)
s.Run()
}
执行后,终端输出的路由表如下:
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
|---------|---------|---------|--------|-------------|--------------------|------------|
default | default | :8199 | ALL | /order-list | main.(*Order).List |
|---------|---------|---------|--------|-------------|--------------------|------------|
我们尝试着访问 http://127.0.0.1:8199/order-list ,可以看到页面输出 list
。如果路由规则中不使用内置变量,那么默认的情况下,方法将会被追加到指定的路由规则末尾。
命名风格规则
通过对象进行路由注册时,可以根据对象及方法名称自动生成路由规则,默认的路由规则为:当方法名称带有多个 单词
(按照字符大写区分单词)时,路由控制器默认会自动使用英文连接符号 -
进行拼接,因此访问的时候方法名称需要带 -
号。
例如,方法名为 UserName
时,生成的路由为 user-name
;方法名为 ShowListItems
时,生成的路由为 show-list-items
;以此类推。
此外,我们可以通过 .Server.SetNameToUriType
方法来设置对象方法名称的路由生成方式。支持的方式目前有 4
种,对应 4
个常量定义:
URI_TYPE_DEFAULT = 0 // (默认)全部转为小写,单词以'-'连接符号连接
URI_TYPE_FULLNAME = 1 // 不处理名称,以原有名称构建成URI
URI_TYPE_ALLLOWER = 2 // 仅转为小写,单词间不使用连接符号
URI_TYPE_CAMEL = 3 // 采用驼峰命名方式
注意:需要在通过对象进行路由注册前进行该参数的设置,在路由注册后设置将不会生效,那么将使用默认规则。
我们来看一个示例:
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
type User struct{}
func (u *User) ShowList(r *ghttp.Request) {
r.Response.Write("list")
}
func main() {
u := new(User)
s1 := g.Server("DEFAULT ")
s2 := g.Server("FULLNAME")
s3 := g.Server("ALLLOWER")
s4 := g.Server("CAMEL ")
s1.SetNameToUriType(ghttp.URI_TYPE_DEFAULT)
s2.SetNameToUriType(ghttp.URI_TYPE_FULLNAME)
s3.SetNameToUriType(ghttp.URI_TYPE_ALLLOWER)
s4.SetNameToUriType(ghttp.URI_TYPE_CAMEL)
s1.BindObject("/{.struct}/{.method}", u)
s2.BindObject("/{.struct}/{.method}", u)
s3.BindObject("/{.struct}/{.method}", u)
s4.BindObject("/{.struct}/{.method}", u)
s1.SetPort(8100)
s2.SetPort(8200)
s3.SetPort(8300)
s4.SetPort(8400)
s1.Start()
s2.Start()
s3.Start()
s4.Start()
g.Wait()
}
为了对比演示效果,这个示例采用了 多Server
运行方式,将不同的名称转换方式使用了不同的 Server
来配置运行,因此我们可以方便地在同一个程序中,访问不同的 Server
(通过不同的端口绑定)看到不同的结果。
执行后,终端输出的路由表如下:
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
|----------|---------|---------|--------|-----------------|-----------------------|------------|
DEFAULT | default | :8100 | ALL | /user/show-list | main.(*User).ShowList |
|----------|---------|---------|--------|-----------------|-----------------------|------------|
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
|----------|---------|---------|--------|-----------------|-----------------------|------------|
FULLNAME | default | :8200 | ALL | /User/ShowList | main.(*User).ShowList |
|----------|---------|---------|--------|-----------------|-----------------------|------------|
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
|----------|---------|---------|--------|-----------------|-----------------------|------------|
ALLLOWER | default | :8300 | ALL | /user/showlist | main.(*User).ShowList |
|----------|---------|---------|--------|-----------------|-----------------------|------------|
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
|----------|---------|---------|--------|-----------------|-----------------------|------------|
CAMEL | default | :8400 | ALL | /user/showList | main.(*User).ShowList |
|----------|---------|---------|--------|-----------------|-----------------------|------------|
可以分别访问以下URL地址得到期望的结果:
http://127.0.0.1:8100/user/show-list
http://127.0.0.1:8200/User/ShowList
http://127.0.0.1:8300/user/showlist
http://127.0.0.1:8400/user/showList
对象方法注册
假如控制器中有若干公开方法,但是我只想注册其中几个,其余的方法我不想对外公开,怎么办?
我们可以通过 BindObject
传递 第三个非必需参数 替换实现,参数支持传入 多个 方法名称,多个名称以英文 ,
号分隔( 方法名称参数区分大小写)。
示例:
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
type Controller struct{}
func (c *Controller) Index(r *ghttp.Request) {
r.Response.Write("index")
}
func (c *Controller) Show(r *ghttp.Request) {
r.Response.Write("show")
}
func main() {
s := g.Server()
c := new(Controller)
s.BindObject("/object", c, "Show")
s.SetPort(8199)
s.Run()
}
执行后,终端输出路由表为:
SERVER | DOMAIN | ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
|---------|---------|---------|--------|--------------|-------------------------|------------|
default | default | :8199 | ALL | /object/show | main.(*Controller).Show |
|---------|---------|---------|--------|--------------|-------------------------|------------|