Gin(四):表單提交校驗和模型綁定

文章首發於 ISLAND前端

上一個章節中已經開始逐漸搭建了一個 web 頁面,如今咱們開始逐步完善頁面上的功能,首先要完成的是登陸和註冊功能。mysql

接受表單數據

註冊頁面的 HTML 元素不在詳細寫出,具體頁面代碼能夠直接參考Github 上代碼。git

頁面完成後佈局:github

註冊頁面有三個輸入框,分別爲 email ,passwordpassword againweb

完善後端 Gin 代碼。咱們在 initRouteruserGroup 中編寫新的接口。sql

userRouter.POST("/register", handler.UserRegister)
複製代碼

編寫完新的接口就要開始編寫 Handlerjson

func UserRegister(context *gin.Context) {
	email := context.PostForm("email")
	password := context.DefaultPostForm("password", "Wa123456")
	passwordAgain := context.DefaultPostForm("password-again", "Wa123456")
	println("email", email, "password", password, "password again", passwordAgain)
}
複製代碼

UserRegister 方法中採用新的方式來接受 Post 請求提交的表單參數,PostFormDefaultPostFormPostForm 直接接受參數,而 DefaultPostForm 能夠設置一個默認值,若是前端沒有進行傳值,那麼咱們能夠設置默認值,如上面的代碼,若是前端沒有將密碼傳輸過來咱們能夠設置一個默認密碼。後端

當咱們運行而且輸入的時候,在控制檯上能夠清楚的看到咱們在表單上的輸入。瀏覽器

當咱們項目功能完善的時候,就能夠完善咱們的單元測試。cookie

此時的單元測試交以前有點複雜。

首先咱們要構造一個結構,該結構是爲了幫助咱們將咱們要提交的信息存放到表單中,同時要指定請求頭信息。

func TestUserPostForm(t *testing.T) {
	value := url.Values{}
	value.Add("email", "youngxhui@gmail.com")
	value.Add("password", "1234")
	value.Add("password-again", "1234")
	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodPost, "/user/register", bytes.NewBufferString(value.Encode()))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded; param=value")
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
}
複製代碼

單元測試編寫完成後能夠運行單元測試,發現控制檯答應了咱們在測試中寫的數據。

模型綁定

上例中咱們的表單僅僅傳輸了三個參數,若是後期項目出現了十多個參數,每次寫一遍都很花費時間,也很消耗經歷。下面就對該方法進行改善

Gin 中提供了 模型綁定,將咱們的表單數據與咱們的模型進行同樣綁定。GIn會將數據統一封裝到模型中,方便咱們往後使用。

首先定義咱們的模型,新建 model 文件夾,創建 userModel.go

package model

type UserModel struct {
	Email         string `form:"email"`
	Password      string `form:"password"`
	PasswordAgain string `form:"password-again"`
}
複製代碼

經過 form:"email" 來對錶單中的 email 輸入數據進行綁定。而後須要修改一下 Handler 方法。

func UserRegister(context *gin.Context) {
   var user model.UserModel
   if err := context.ShouldBind(&user); err != nil {
   	println("err ->", err.Error())
   	return
   }
   println("email", user.Email, "password", user.Password, "password again", user.PasswordAgain)
}
複製代碼

此時咱們的模型綁定已經寫好,運行 TestUserPostForm 測試用例,測試用例能夠完美的經過。說明咱們的模型綁定方法是正確的。同時模型綁定仍是從 jsonxmlyml 等格式數據的綁定,往後會有介紹和說明。固然也能夠經過瀏覽器中的註冊表單進行提交。

數據校驗

作後端開發的人都明白一個道理:永遠不要相信前端傳過來的數據。全部的數據在進事後端時,務必要進行數據的校驗。

在模型中可用 binding 來對數據進行校驗。Gin 對於數據校驗使用的是 validator.v8 庫,該庫提供多種校驗方法。經過 binding:"" 方式來進行對數據的校驗。

咱們將 UserModel 進行修改,添加一些規則,郵箱驗證和密碼校驗,要求第二次重複密碼要和第一次密碼一致。更多的校驗規則能夠看官方文檔

type UserModel struct {
	Email         string `form:"email" binding:"email"`
	Password      string `form:"password"`
	PasswordAgain string `form:"password-again" binding:"eqfield=Password"`
}
複製代碼

咱們從新寫一個測試用例用來測試郵箱和密碼校驗是否有效。

func TestUserPostFormEmailErrorAndPasswordError(t *testing.T) {
	value := url.Values{}
	value.Add("email", "youngxhui")
	value.Add("password", "1234")
	value.Add("password-again", "qwer")
	w := httptest.NewRecorder()
	req, _ := http.NewRequest(http.MethodPost, "/user/register", bytes.NewBufferString(value.Encode()))
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded; param=value")
	router.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
}
複製代碼

運行測試,發現測試雖然經過了,可是會有兩行 error 信息

err ->  Key: 'UserModel.Email' Error:Field validation for 'Email' failed on the 'email' tag
Key: 'UserModel.PasswordAgain' Error:Field validation for 'PasswordAgain' failed on the 'eqfield' tag
複製代碼

該信息說明了咱們的 EmailPasswordAgain 信息校驗沒有經過。

使用Log和重定向

測試經過是由於不管咱們代碼如何都會返回 200 狀態碼,這是不符合http 狀態碼的規範的,因此咱們要對http狀態碼進行規範化。同時咱們以前的代碼中一直使用 Printf 來打印日誌信息,也是不規範的,由於 Printf 打印的日誌信息相對侷限,因此應該選用 Log 進行日誌打印。

func UserRegister(context *gin.Context) {
	var user model.UserModel
	if err := context.ShouldBind(&user); err != nil {
		log.Println("err ->", err.Error())
		context.String(http.StatusBadRequest, "輸入的數據不合法")
	} else {
		log.Println("email", user.Email, "password", user.Password, "password again", user.PasswordAgain)
		context.Redirect(http.StatusMovedPermanently, "/")
	}
}
複製代碼

首先咱們將原來只用 Println 打印的數據都改爲了 log 去打印數據。

同時將原來的狀態碼都進行了更改,不一樣的狀態碼錶明不一樣的請求響應結果。

最後在請求成功的時候咱們對路由進行了重定向,將頁面轉跳到首頁。

同時咱們也要將測試用例裏的返回狀態碼進行修改。

總結

本節將表單提交,模型綁定和數據校驗有了一個相對細緻的介紹,代碼中也經過不一樣的測試用例來檢查代碼是否正確。

本章節代碼

Github

其餘章節索引

Gin(一):Hello
Gin(二):路由Router
Gin(三):模板tmpl
Gin(四):表單提交校驗和模型綁定
Gin(五):鏈接MySQL
Gin(六):文件的上傳
Gin(七):中間件的使用和定義 Gin(八):Cookie的使用

我的公衆號

最新文章都會在公衆號上進行分享,歡迎各位大佬關注

相關文章
相關標籤/搜索