GoFrame 請(qǐng)求輸入-對(duì)象處理

2022-04-13 15:30 更新

對(duì)象轉(zhuǎn)換

對(duì)象轉(zhuǎn)換在請(qǐng)求處理中非常常見(jiàn)。我們推薦將輸入和輸出定義為?struct?結(jié)構(gòu)體對(duì)象,以便于結(jié)構(gòu)化的參數(shù)輸入輸出維護(hù)。?GoFrame?框架支持非常便捷的對(duì)象轉(zhuǎn)換,支持將客戶端提交的參數(shù)如?Query?參數(shù)、表單參數(shù)、內(nèi)容參數(shù)、?JSON/XML?等參數(shù)非常便捷地轉(zhuǎn)換為指定的?struct?結(jié)構(gòu)體,并且支持提交參數(shù)與?struct?屬性的映射關(guān)系維護(hù)。

對(duì)象轉(zhuǎn)換方法使用?Request?對(duì)象的?Parse?方法或者?Get*Struct?方法,具體方法定義請(qǐng)參考API文檔: https://pkg.go.dev/github.com/gogf/gf/v2/net/ghttp#Request

參數(shù)映射

默認(rèn)規(guī)則

客戶端提交的參數(shù)如果需要映射到服務(wù)端定義的?struct?屬性上,可以采用默認(rèn)的映射關(guān)系,這一點(diǎn)非常方便。默認(rèn)的轉(zhuǎn)換規(guī)則如下:

  1. ?struct?中需要匹配的屬性必須為公開(kāi)屬性(首字母大寫(xiě))。
  2. 參數(shù)名稱會(huì)自動(dòng)按照 不區(qū)分大小寫(xiě) 且 忽略?-?/?_?/空格符號(hào) 的形式與?struct?屬性進(jìn)行匹配。
  3. 如果匹配成功,那么將鍵值賦值給屬性,如果無(wú)法匹配,那么忽略該鍵值。

以下是幾個(gè)匹配的示例:

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

由于底層對(duì)象轉(zhuǎn)換實(shí)現(xiàn)使用的是?gconv?模塊,因此也支持?c/gconv/json?標(biāo)簽。

自定義規(guī)則

自定義的參數(shù)映射規(guī)則可以通過(guò)為?struct?屬性綁定?tag?實(shí)現(xiàn),?tag?名稱可以為?p/param/params?。例如:

type User struct{
    Id    int
    Name  string
    Pass1 string `p:"password1"`
    Pass2 string `p:"password2"`
}

其中我們使用了?p?標(biāo)簽來(lái)指定該屬性綁定的參數(shù)名稱。?password1?參數(shù)將會(huì)映射到?Pass1?屬性,?password2?將會(huì)映射到?Pass2?屬性上。其他屬性采用默認(rèn)的轉(zhuǎn)換規(guī)則即可,無(wú)需設(shè)置?tag?。

Parse轉(zhuǎn)換

我們同時(shí)可以使用?Parse?方法來(lái)實(shí)現(xiàn)?struct?的轉(zhuǎn)換,該方法是一個(gè)便捷方法,內(nèi)部會(huì)自動(dòng)進(jìn)行轉(zhuǎn)換及數(shù)據(jù)校驗(yàn),但如果?struct?中沒(méi)有校驗(yàn)?tag?的綁定將不會(huì)執(zhí)行校驗(yàn)邏輯。

從?GoFrame v2?版本開(kāi)始,我們推薦使用結(jié)構(gòu)化的方式來(lái)定義路由方法,更便捷地管理輸入輸出數(shù)據(jù)結(jié)構(gòu)及其實(shí)例對(duì)象

使用示例:

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()
}

在該示例中,我們定義了兩個(gè)結(jié)構(gòu)體:?RegisterReq?用于參數(shù)接收,?RegisterRes?用于數(shù)據(jù)返回。

其中,我們使用?r.Parse(&req)?將客戶端提交的參數(shù)轉(zhuǎn)換為?RegisterReq?對(duì)象,當(dāng)轉(zhuǎn)換成功時(shí)?req?變量將會(huì)被初始化賦值(默認(rèn)情況下為?nil?),否則該方法返回?err?并且?req?變量為?nil?。返回?cái)?shù)據(jù)結(jié)構(gòu)通過(guò)?RegisterRes?定義,并且返回格式為?JSON?,通過(guò)?r.Response.WriteJsonExit?實(shí)現(xiàn),該方法將?RegisterRes?根據(jù)其內(nèi)部定義的?json?標(biāo)簽轉(zhuǎn)換為?JSON?格式并退出當(dāng)前服務(wù)方法,不再執(zhí)行該服務(wù)方法的后續(xù)邏輯。

為了演示測(cè)試效果,這里在正常的返回結(jié)果?Data?屬性中將?RegisterReq?對(duì)象返回,由于該對(duì)象沒(méi)有綁定?json?標(biāo)簽,因此返回的?JSON?字段將會(huì)為其屬性名稱。

執(zhí)行后,我們通過(guò)?curl?工具來(lái)測(cè)試一下:

$ 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?兩種提交方式來(lái)做測(cè)試,可以看到服務(wù)端都能完美地獲取到提交參數(shù)并完成對(duì)象轉(zhuǎn)換。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)