请求参数(二):结构体接收与对象化请求处理

引言

接口参数一多,逐字段 r.Get 既啰嗦又容易漏。GoFrame 支持把请求参数直接绑定到一个 Go 结构体上,这一章讲结构体接收参数,以及更进一步的"对象化"处理思路。

概念

  • 结构体绑定:定义与参数对应的结构体,调用 r.Parse(&req) 即可完成绑定,字段名与参数名同名即自动匹配。
  • 校验联动:结构体字段可以带 v 标签声明校验规则(下一章 gvalid 展开),r.Parse 发现校验失败会返回错误。
  • 参数来源:Parse 默认综合 Query、Form、路由参数等来源做绑定(具体优先级与自定义映射标签以官方文档为准)。
  • 对象化:把"入参结构体 + 处理函数"当成一个整体来设计,一个接口一个 Req 类型,代码即文档。规范路由(第 12 章)会把这种风格发挥到极致。

代码示例

一个带校验的结构体接收示例:

package main

import (
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

// 入参结构体:字段与请求参数同名即可自动绑定
type CreateUserReq struct {
	Name  string `v:"required"`   // 必填
	Age   int    `v:"between:1,150"` // 取值范围
	Email string `v:"email"`      // 邮箱格式
}

func main() {
	s := g.Server()

	s.Group("/user", func(group *ghttp.RouterGroup) {
		group.POST("/create", func(r *ghttp.Request) {
			var req CreateUserReq
			if err := r.Parse(&req); err != nil {
				// 绑定或校验失败,直接返回错误信息
				r.Response.WriteJson(g.Map{"code": 1, "message": err.Error()})
				return
			}
			r.Response.WriteJson(g.Map{
				"code": 0,
				"data": req, // 后续交给业务层处理
			})
		})
	})

	s.SetPort(8000)
	s.Run()
}

测试:POST /user/create,表单体 name=john&age=20&email=john@example.com,正常返回结构体;把 name 去掉再请求,会收到 required 校验错误。

把"参数定义 + 处理"对象化一点——先定义独立的请求类型,业务函数只依赖结构体:

type CreateUserInput struct {
	Name  string
	Age   int
	Email string
}

// 业务函数只关心结构体,不关心 HTTP 细节,便于单测复用
func createUser(input *CreateUserInput) error {
	// 假设这里调用 service/dao 落库
	return nil
}

注意点

  • Parse 的目标必须是结构体指针:r.Parse(&req),写错会报错。
  • 布尔、数字字段在参数缺失时会取零值,需要区分"没传"与"传了 0"时可配合 *int 指针或 gvar 字段。
  • v 标签规则语法(requiredbetween:1,150email 等)在下一章系统讲解。
  • 参数名与字段名不一致时的映射标签(如 pjson)写法与优先级,以官方文档请求输入章节为准。

小结

r.Parse(&req) 让"取参数"变成"填结构体",代码显著变短、可读性变好,也为参数校验和对象化设计铺路。下一章我们进入规范路由,看看 GoFrame 官方主推的接口定义方式。

笔记加载中…