title: Beego脱坑(八)表单数据验证
tags: go,beego
author : Clown95
表单就是用来收集用户的一些信息,既然是用户填写那么可能会出现错误填写错误的情况,比如说手机号码多一位或者少一位啊都有可能。更严重的是存在的一些恶意用户填写非法关键字来获取网站重要数据,比如使用sql注入。为了能够避免这些情况,我们就需要使用表单数据验证。
本章不仅会涉及到表单验证,还将会对之前的知识点进行一些融合,例如表单数据获取、数据解析到结构体、模板动态输出。
beego为我们提供了validation
这个库,它主要用于数据验证和错误收集,我们现在来安装它。
go get -u github.com/astaxie/beego/validation
还记得我之前写的那个注册用户的表单吗?现在我们来对它改造一番。下面是我们表单的效果图:
现在我们需要实现:
我们先实现表单模板:
validation.html
账号注册
具体代码:
package controllers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/validation"
)
type ValidationController struct {
beego.Controller
}
type User struct {
User string
Pwd string
RealName string
Age string //为了使用Numeric 我们先使用string类型
IdCard string
Email string
Tel string
}
func (this *ValidationController) Get() {
this.TplName = "validation.html"
}
func (this *ValidationController) Post() {
this.TplName = "validation.html"
var user User
//解析数据到结构体
if error := this.ParseForm(&user); error != nil {
this.Data["ParseFormErr"] = "数据解析到结构体错误"
} else {
varlid := validation.Validation{} //创建验证数据对象
//验证用户名不能为空且最小长度为6
userresult := varlid.Required(user.User, "User") //检测是否为空
if !userresult.Ok {
this.Data["VerifyUser"] = "用户名不能为空"
} else {
userresult = varlid.MinSize(user.User, 6, "User") //设置用户名最小长度为6
if !userresult.Ok {
this.Data["VerifyUser"] = "用户名最小长度为6位"
}
}
//验证密码不能为空且最小长度为6
pwdresult := varlid.Required(user.Pwd, "Pwd") //检测是否为空
if !pwdresult.Ok {
this.Data["VerifyPwd"] = "密码不能为空"
} else {
pwdresult = varlid.MinSize(user.Pwd, 6, "Pwd") //设置密码最小长度为6
if !pwdresult.Ok {
this.Data["VerifyPwd"] = "密码最小长度为6位"
}
}
//验证密码是否一样
cfmpwd := this.GetString("CfmPwd")
if cfmpwd != "" {
if cfmpwd != user.Pwd {
this.Data["VerifyCfm"] = "两次密码不一样"
}
} else {
this.Data["VerifyCfm"] = "确认密码不能为空"
}
//验证姓名不能为空
realnameresult := varlid.Required(user.RealName, "RealName")
if !realnameresult.Ok {
this.Data["VerifyRealName"] = "真实姓名不能为空"
}
//验证年龄是否为数字
ageresult := varlid.Numeric(user.Age, "Age")
if !ageresult.Ok {
this.Data["VerifyAge"] = "年龄只能是数字"
}
//验证身份证是否合法
idcardresult := varlid.Required(user.IdCard, "IdCard")
if !idcardresult.Ok {
this.Data["VerifyIdCard"] = "身份证不能为空"
} else {
idcardresult = varlid.Length(user.IdCard, 18, "IdCard") // 指定数据长度为18
if !idcardresult.Ok {
this.Data["VerifyIdCard"] = "身份证错误"
}
}
//验证邮箱
emailresult := varlid.Required(user.Email, "Email")
if !emailresult.Ok {
this.Data["VerifyEmail"] = "邮箱不能为空"
} else {
emailresult = varlid.Email(user.Email, "Email") //验证邮箱是否合法
if !emailresult.Ok {
this.Data["VerifyEmail"] = "邮箱格式错误"
}
}
//验证手机
telresult := varlid.Required(user.Tel, "Tel")
if !telresult.Ok {
this.Data["VerifyTel"] = "手机不能为空"
} else {
telresult = varlid.Mobile(user.Tel, "Tel") //验证手机是否合法
if !telresult.Ok {
this.Data["VerifyTel"] = "手机格式错误"
}
}
}
}
注册路由:
beego.Router("/validation",&controllers.ValidationController{})
我们还可以这样,代码简洁性大大增加:
func (this *ValidationController) Post() {
this.TplName = "validation.html"
var user User
//解析数据到结构体
if error := this.ParseForm(&user); error != nil {
this.Data["ParseFormErr"] = "数据解析到结构体错误"
} else {
valid := validation.Validation{} //创建验证数据对象
//验证用户名不能为空且最小长度为6
// Message 是自定义消息
valid.Required(user.User, "User").Message("用户名不能为空" )
valid.MinSize(user.User, 6,"User").Message("用户名最短为6位" )
valid.Required(user.Pwd, "Pwd").Message("密码不能为空" )
valid.MinSize(user.User, 6,"Pwd").Message("密码最短为6位" )
valid.Required(user.RealName, "RealName").Message("真实姓名不能为空" )
valid.Numeric(user.Age, "Age").Message("年龄只能为数字" )
valid.Required(user.IdCard, "IdCard").Message("身份证不能为空" )
valid.Length(user.IdCard, 18,"IdCard").Message("身份证格式非法" )
valid.Required(user.Email, "Email").Message("邮箱不能为空" )
valid.Email(user.Email, "Email").Message("邮箱格式非法" )
valid.Required(user.Tel, "Tel").Message("手机不能为空" )
valid.Mobile(user.Tel, "Tel").Message("手机格式非法" )
if valid.HasErrors() {
// 如果有错误信息,证明验证没通过
// 打印错误信息
for _, err := range valid.Errors {
data:= "Verify"+err.Key
this.Data[data] =err.Message
//log.Println(err.Key, err.Message)
}
}
}
}
我们简单的分析下上面的代码:
我们可以使用StructTag让代码更加简洁:
我们先修改User
结构体,给它加上Tag
type User struct {
User string `valid:"Required;MinSize(6)"` //不为空且最小长度为6
Pwd string `valid:"Required;MinSize(6)"` //不为空且最小长度为6
RealName string `valid:"Required"` //不为空
Age string `valid:"Numeric"` //为数字字符串
IdCard string `valid:"Required;Length(18)"` //不为空且长度为18
Email string `valid:"Required;Email"` //不为空且格式为Email
Tel string `valid:"Required;Mobile"` //不为空且格式为mobile
}
控制器:
func (this *ValidationController) Post() {
var user User
//解析数据到结构体
if error := this.ParseForm(&user); error != nil {
this.Data["ParseFormErr"] = "数据解析到结构体错误"
} else {
this.TplName = "validation.html"
valid := validation.Validation{}
//自定义消息提示,官方默认的是英文,我们手动改成中文,具体内容可以查看 MessageTmpls 。
//下面这段代码,并不是必须的
var MessageTmpls = map[string]string{
"Required": "不能为空",
"MinSize": "最短长度为 %d",
"Length": "长度必须为 %d",
"Numeric": "必须是有效的数字",
"Email": "必须是有效的电子邮件地址",
"Mobile": "必须是有效的手机号码",
}
validation.SetDefaultMessage(MessageTmpls)
// 上面的代码
b, err := valid.Valid(&user)
if err != nil {
// 验证StructTag 是否正确
this.Data["ParseFormErr"] = err
}
if !b {
// 验证没通过 输出错误信息
//valid.Errors 的信息存储在预定义的MessageTmpls中
for _, err := range valid.Errors {
//log.Println(err.Field, err.Message)
data := "Verify" + err.Field
this.Data[data] = err.Field+err.Message
}
}
}
}
这里注意一下,上面所使用的 SetDefaultMessage 方法它可以帮我们重设错误信息,此函数文档中未介绍,但可在包 beego/validation/validators.go 中找到。
我们只是使用了部分验证函数,官方还提供了很多其他的验证,大部分方法的实现原理就是内部帮我们写好了正则表达式,并且根据这个正则帮我们进行验证。