对象转换

对象转换在请求处理中非常常见。我们推荐将输入和输出定义为struct结构体对象,以便于结构化的参数输入输出维护。GF框架支持非常便捷的对象转换,支持将客户端提交的参数如Query参数、表单参数、内容参数、JSON/XML等参数非常便捷地转换为指定的struct结构体,并且支持提交参数与struct属性的映射关系维护。

对象转换方法使用Request对象的Parse方法或者Get*Struct方法,具体方法定义请参考API文档:https://godoc.org/github.com/gogf/gf/net/ghttp#Request

参数映射

默认规则

客户端提交的参数如果需要映射到服务端定义的struct上,可以采用默认的映射关系,这一点非常方便。默认的转换规则如下:

  1. struct中需要匹配的属性必须为公开属性(首字母大写)。
  2. 参数名称会自动按照 不区分大小写忽略-/_/空格符号 的形式与struct属性进行匹配。
  3. 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略该键值。

以下是几个匹配的示例:

  1. map键名 struct属性 是否匹配
  2. name Name match
  3. Email Email match
  4. nickname NickName match
  5. NICKNAME NickName match
  6. Nick-Name NickName match
  7. nick_name NickName match
  8. nick name NickName match
  9. NickName Nick_Name match
  10. Nick-name Nick_Name match
  11. nick_name Nick_Name match
  12. nick name Nick_Name match

由于底层对象转换实现使用的是gconv模块,因此也支持c/gconv/json标签,更详细的规则可以参考请参考【gconv.Struct】章节。

自定义规则

自定义的参数映射规则可以通过为struct属性绑定tag实现,tag名称可以为p/param/params。例如:

  1. type User struct{
  2. Id int
  3. Name string
  4. Pass1 string `p:"password1"`
  5. Pass2 string `p:"password2"`
  6. }

其中我们使用了p标签来指定该属性绑定的参数名称。password1参数将会映射到Pass1属性,password2将会映射到Pass2属性上。其他属性采用默认的转换规则即可,无需设置tag

Parse转换

v1.11版本开始,我们推荐使用Parse方法来实现struct的转换,该方法是一个便捷方法,内部会自动进行转换及数据校验,但如果struct中没有校验tag的绑定将不会执行校验逻辑。

使用示例:

  1. package main
  2. import (
  3. "github.com/gogf/gf/frame/g"
  4. "github.com/gogf/gf/net/ghttp"
  5. )
  6. type RegisterReq struct {
  7. Name string
  8. Pass string `p:"password1"`
  9. Pass2 string `p:"password2"`
  10. }
  11. type RegisterRes struct {
  12. Code int `json:"code"`
  13. Error string `json:"error"`
  14. Data interface{} `json:"data"`
  15. }
  16. func main() {
  17. s := g.Server()
  18. s.BindHandler("/register", func(r *ghttp.Request) {
  19. var req *RegisterReq
  20. if err := r.Parse(&req); err != nil {
  21. r.Response.WriteJsonExit(RegisterRes{
  22. Code: 1,
  23. Error: err.Error(),
  24. })
  25. }
  26. // ...
  27. r.Response.WriteJsonExit(RegisterRes{
  28. Data: req,
  29. })
  30. })
  31. s.SetPort(8199)
  32. s.Run()
  33. }

在该示例中,我们定义了两个结构体:RegisterReq用于参数接收,RegisterRes用于数据返回。

其中,我们使用r.Parse(&req)将客户端提交的参数转换为RegisterReq对象,当转换成功时req变量将会被初始化赋值(默认情况下为nil),否则该方法返回err并且req变量为nil。返回数据结构通过RegisterRes定义,并且返回格式为JSON,通过r.Response.WriteJsonExit实现,该方法将RegisterRes根据其内部定义的json标签转换为JSON格式并退出当前服务方法,不再执行该服务方法的后续逻辑。

为了演示测试效果,这里在正常的返回结果Data属性中将RegisterReq对象返回,由于该对象没有绑定json标签,因此返回的JSON字段将会为其属性名称。

执行后,我们通过curl工具来测试一下:

  1. $ curl "http://127.0.0.1:8199/register?name=john&password1=123&password2=456"
  2. {"code":0,"error":"","data":{"Name":"john","Pass":"123","Pass2":"456"}}
  3. $ curl -d "name=john&password1=123&password2=456" -X POST "http://127.0.0.1:8199/"
  4. {"code":0,"error":"","data":{"Name":"john","Pass":"123","Pass2":"456"}}

我们使用了GETPOST两种提交方式来做测试,可以看到服务端都能完美地获取到提交参数并完成对象转换。