回调函数注册

回调函数+执行对象混合注册是推荐的服务注册方式。

这种方式是最简单且最灵活的的服务注册方式,注册的服务可以是一个实例化对象的方法地址,也可以是一个包方法地址。服务需要的数据可以通过模块内部变量形式或者对象内部变量形式进行管理,开发者可根据实际情况进行灵活控制。

我们可以直接通过ghttp.BindHandler方法完成回调函数的注册,在框架的开发手册中很多地方都使用了回调函数注册的方式来做演示,因为这种注册方式比较简单。

使用示例1,与执行对象混合使用

gitee.com/johng/gf/blob/master/geg/frame/mvc/controller/demo/product.go

  1. package demo
  2. import (
  3. "gitee.com/johng/gf/g"
  4. "gitee.com/johng/gf/g/net/ghttp"
  5. )
  6. type Product struct {
  7. total int
  8. }
  9. func init() {
  10. p := &Product{}
  11. g.Server().BindHandler("/product/total", p.Total)
  12. g.Server().BindHandler("/product/list/{page}.html", p.List)
  13. }
  14. func (p *Product) Total(r *ghttp.Request) {
  15. p.total++
  16. r.Response.Write("total: ", p.total)
  17. }
  18. func (p *Product) List(r *ghttp.Request) {
  19. r.Response.Write("page: ", r.Get("page"))
  20. }

在这个示例中,我们使用对象来封装业务逻辑和所需的变量,使用回调函数注册来灵活注册对应的对象方法。

使用示例2,使用包变量管理内部变量

gitee.com/johng/gf/blob/master/geg/frame/mvc/controller/stats/stats.go

  1. package stats
  2. import (
  3. "gitee.com/johng/gf/g"
  4. "gitee.com/johng/gf/g/net/ghttp"
  5. )
  6. var (
  7. total int
  8. )
  9. func init() {
  10. g.Server().BindHandler("/stats/total", showTotal)
  11. }
  12. func showTotal(r *ghttp.Request) {
  13. total++
  14. r.Response.Write("total:", total)
  15. }

使用示例3,请求参数绑定到struct对象

gitee.com/johng/gf/blob/master/geg/net/ghttp/server/request/request_struct.go

  1. package main
  2. import (
  3. "gitee.com/johng/gf/g"
  4. "gitee.com/johng/gf/g/net/ghttp"
  5. )
  6. type User struct {
  7. Uid int `json:"uid"`
  8. Name string `json:"name" params:"username"`
  9. Pass1 string `json:"pass1" params:"password1,userpass1"`
  10. Pass2 string `json:"pass2" params:"password3,userpass2"`
  11. }
  12. func main() {
  13. s := g.Server()
  14. s.BindHandler("/user", func(r *ghttp.Request){
  15. user := new(User)
  16. r.GetToStruct(user)
  17. //r.GetPostToStruct(user)
  18. //r.GetQueryToStruct(user)
  19. r.Response.WriteJson(user)
  20. })
  21. s.SetPort(8199)
  22. s.Run()
  23. }

可以看到,我们可以在定义struct的时候使用params的标签来指定匹配绑定的参数名称,并且支持多个参数名称的绑定,多个参数名称以,号分隔。在使用中我们可以使用GetRequestToStruct/GetPostToStruct/GetQueryToStruct三种方式来获得指定Method提交方式的参数map,此外GetToStructGetRequestToStruct的别名,大多数情况下我们使用该方式获取参数即可。

如果是其他方式提交参数,如果Json/Xml等等,由于设计到自定义参数格式的解析再绑定,请参考gconv模块map转换struct的标签名称gconv用法示例

以上示例执行后,我们手动访问地址http://127.0.0.1:8199/user?uid=1&name=john&password1=123&userpass2=123,输出结果为:

  1. {"name":"john","pass1":"123","pass2":"123","uid":1}

使用示例4,请求参数绑定+数据校验示例

gitee.com/johng/gf/blob/master/geg/net/ghttp/server/request/request_validation.go

  1. package main
  2. import (
  3. "gitee.com/johng/gf/g"
  4. "gitee.com/johng/gf/g/net/ghttp"
  5. "gitee.com/johng/gf/g/util/gvalid"
  6. "gitee.com/johng/gf/g/encoding/gparser"
  7. )
  8. func main() {
  9. type User struct {
  10. Uid int `gvalid:"uid@min:1"`
  11. Name string `params:"username" gvalid:"username @required|length:6,30"`
  12. Pass1 string `params:"password1" gvalid:"password1@required|password3"`
  13. Pass2 string `params:"password2" gvalid:"password2@required|password3|same:password1#||两次密码不一致,请重新输入"`
  14. }
  15. s := g.Server()
  16. s.BindHandler("/user", func(r *ghttp.Request){
  17. user := new(User)
  18. r.GetToStruct(user)
  19. result := gvalid.CheckStruct(user, nil)
  20. json, _ := gparser.VarToJsonIndent(result)
  21. r.Response.Write(json)
  22. })
  23. s.SetPort(8199)
  24. s.Run()
  25. }

其中,gvalid标签为gavlid数据校验包特定的校验规则标签,具体请参考【数据校验】章节。此外,为了便于查看返回的json结果,这里在示例中使用gparser模块的VarToJsonIndent方法,平常开发中往往直接使用像上一个示例中使用的r.Response.WriteJson方法返回json结果即可。执行后,访问URLhttp://127.0.0.1:8199/user?uid=1&name=john&password1=123&password2=456,输出结果为:

  1. {
  2. "password1": {
  3. "password3": "密码格式不合法,密码格式为任意6-18位的可见字符,必须包含大小写字母、数字和特殊字符"
  4. },
  5. "password2": {
  6. "password3": "密码格式不合法,密码格式为任意6-18位的可见字符,必须包含大小写字母、数字和特殊字符",
  7. "same": "字段值不合法"
  8. },
  9. "username": {
  10. "length": "字段长度为6到30个字符"
  11. }
  12. }