对象转换
对象转换在请求处理中非常常见。我们推荐将输入和输出定义为 struct
结构体对象,以便于结构化的参数输入输出维护。 GoFrame
框架支持非常便捷的对象转换,支持将客户端提交的参数如 Query
参数、表单参数、内容参数、 JSON/XML
等参数非常便捷地转换为指定的 struct
结构体,并且支持提交参数与 struct
属性的映射关系维护。
对象转换方法使用 Request
对象的 Parse
方法或者 Get*Struct
方法,具体方法定义请参考API文档: https://pkg.go.dev/github.com/gogf/gf/v2/net/ghttp#Request
参数映射
默认规则
客户端提交的参数如果需要映射到服务端定义的 struct
属性上,可以采用默认的映射关系,这一点非常方便。默认的转换规则如下:
struct
中需要匹配的属性必须为公开属性
(首字母大写)。- 参数名称会自动按照
不区分大小写
且 忽略-/_/空格
符号 的形式与struct
属性进行匹配。 - 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略该键值。
以下是几个匹配的示例:
map键名 struct属性 是否匹配
name Name match
Email Email match
nickname NickName match
NICKNAME NickName match
Nick-Name NickName match
nick_name NickName match
nick name NickName match
NickName Nick_Name match
Nick-name Nick_Name match
nick_name Nick_Name match
nick name Nick_Name match
由于底层对象转换实现使用的是 gconv
模块,因此也支持 c/gconv/json
标签,更详细的规则可以参考请参考 类型转换-Struct转换 章节。
自定义规则
请在对象属性与参数命长差异较大的业务场景下使用自定义映射规则,否则请使用默认的参数映射规则。因为大量的自定义规则标签会增加代码的维护成本。
自定义的参数映射规则可以通过为 struct
属性绑定 tag
实现, tag
名称可以为 p/param/params
。例如:
type User struct{
Id int
Name string
Pass1 string `p:"password1"`
Pass2 string `p:"password2"`
}
其中我们使用了 p
标签来指定该属性绑定的参数名称。 password1
参数将会映射到 Pass1
属性, password2
将会映射到 Pass2
属性上。其他属性采用默认的转换规则即可,无需设置 tag
。
Parse
转换
我们同时可以使用 Parse
方法来实现 struct
的转换,该方法是一个便捷方法,内部会自动进行转换及数据校验,但如果 struct
中没有校验 tag
的绑定将不会执行校验逻辑。
从 GoFrame v2
版本开始,我们推荐使用结构化的方式来定义路由方法,更便捷地管理输入输出数据结构及其实例对象,具体请参考: 路由注册-规范路由
使用示例:
package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
type RegisterReq struct {
Name string
Pass string `p:"password1"`
Pass2 string `p:"password2"`
}
type RegisterRes struct {
Code int `json:"code"`
Error string `json:"error"`
Data interface{} `json:"data"`
}
func main() {
s := g.Server()
s.BindHandler("/register", func(r *ghttp.Request) {
var req *RegisterReq
if err := r.Parse(&req); err != nil {
r.Response.WriteJsonExit(RegisterRes{
Code: 1,
Error: err.Error(),
})
}
// ...
r.Response.WriteJsonExit(RegisterRes{
Data: req,
})
})
s.SetPort(8199)
s.Run()
}
在该示例中,我们定义了两个结构体: RegisterReq
用于参数接收, RegisterRes
用于数据返回。
其中,我们使用 r.Parse(&req)
将客户端提交的参数转换为 RegisterReq
对象,当转换成功时 req
变量将会被初始化赋值(默认情况下为 nil
),否则该方法返回 err
并且 req
变量为 nil
。返回数据结构通过 RegisterRes
定义,并且返回格式为 JSON
,通过 r.Response.WriteJsonExit
实现,该方法将 RegisterRes
根据其内部定义的 json
标签转换为 JSON
格式并退出当前服务方法,不再执行该服务方法的后续逻辑。
为了演示测试效果,这里在正常的返回结果 Data
属性中将 RegisterReq
对象返回,由于该对象没有绑定 json
标签,因此返回的 JSON
字段将会为其属性名称。
执行后,我们通过 curl
工具来测试一下:
$ curl "http://127.0.0.1:8199/register?name=john&password1=123&password2=456"
{"code":0,"error":"","data":{"Name":"john","Pass":"123","Pass2":"456"}}
$ curl -d "name=john&password1=123&password2=456" -X POST "http://127.0.0.1:8199/register"
{"code":0,"error":"","data":{"Name":"john","Pass":"123","Pass2":"456"}}
我们使用了 GET
和 POST
两种提交方式来做测试,可以看到服务端都能完美地获取到提交参数并完成对象转换。