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的使用

我的公众号

最新文章都会在公众号上进行分享,欢迎各位大佬关注

相关文章
相关标签/搜索