文章首發於 ISLAND前端
上一個章節中已經開始逐漸搭建了一個 web 頁面,如今咱們開始逐步完善頁面上的功能,首先要完成的是登陸和註冊功能。mysql
註冊頁面的 HTML 元素不在詳細寫出,具體頁面代碼能夠直接參考Github 上代碼。git
頁面完成後佈局:github
註冊頁面有三個輸入框,分別爲 email
,password
和 password again
。web
完善後端 Gin 代碼。咱們在 initRouter
中 userGroup
中編寫新的接口。sql
userRouter.POST("/register", handler.UserRegister)
複製代碼
編寫完新的接口就要開始編寫 Handler
。json
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 請求提交的表單參數,PostForm
和 DefaultPostForm
。PostForm
直接接受參數,而 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
測試用例,測試用例能夠完美的經過。說明咱們的模型綁定方法是正確的。同時模型綁定仍是從 json
, xml
,yml
等格式數據的綁定,往後會有介紹和說明。固然也能夠經過瀏覽器中的註冊表單進行提交。
作後端開發的人都明白一個道理:永遠不要相信前端傳過來的數據。全部的數據在進事後端時,務必要進行數據的校驗。
在模型中可用 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
複製代碼
該信息說明了咱們的 Email
和 PasswordAgain
信息校驗沒有經過。
測試經過是由於不管咱們代碼如何都會返回 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
去打印數據。
同時將原來的狀態碼都進行了更改,不一樣的狀態碼錶明不一樣的請求響應結果。
最後在請求成功的時候咱們對路由進行了重定向,將頁面轉跳到首頁。
同時咱們也要將測試用例裏的返回狀態碼進行修改。
本節將表單提交,模型綁定和數據校驗有了一個相對細緻的介紹,代碼中也經過不一樣的測試用例來檢查代碼是否正確。
Gin(一):Hello
Gin(二):路由Router
Gin(三):模板tmpl
Gin(四):表單提交校驗和模型綁定
Gin(五):鏈接MySQL
Gin(六):文件的上傳
Gin(七):中間件的使用和定義 Gin(八):Cookie的使用
最新文章都會在公衆號上進行分享,歡迎各位大佬關注