# 14.3 表单及验证支持
在Web开发中对于这样的一个流程可能很眼熟：

- 打开一个网页显示出表单。
- 用户填写并提交了表单。
- 如果用户提交了一些无效的信息，或者可能漏掉了一个必填项，表单将会连同用户的数据和错误问题的描述信息返回。
- 用户再次填写，继续上一步过程，直到提交了一个有效的表单。

在接收端，脚本必须：

- 检查用户递交的表单数据。
- 验证数据是否为正确的类型，合适的标准。例如，如果一个用户名被提交，它必须被验证是否只包含了允许的字符。它必须有一个最小长度，不能超过最大长度。用户名不能与已存在的他人用户名重复，甚至是一个保留字等。
- 过滤数据并清理不安全字符，保证逻辑处理中接收的数据是安全的。
- 如果需要，预格式化数据（数据需要清除空白或者经过HTML编码等等。）
- 准备好数据，插入数据库。

尽管上面的过程并不是很复杂，但是通常情况下需要编写很多代码，而且为了显示错误信息，在网页中经常要使用多种不同的控制结构。创建表单验证虽简单，实施起来实在枯燥无味。

## 表单和验证
对于开发者来说，一般开发过程都是相当复杂，而且大多是在重复一样的工作。假设一个场景项目中忽然需要增加一个表单数据，那么局部代码的整个流程都需要修改。我们知道Go里面struct是常用的一个数据结构，因此beego的form采用了struct来处理表单信息。

首先定义一个开发Web应用时相对应的struct，一个字段对应一个form元素，通过struct的tag来定义相应的元素信息和验证信息，如下所示：

	type User struct{
		Username 	string 	`form:text,valid:required`
		Nickname 	string 	`form:text,valid:required`
		Age			int 	`form:text,valid:required|numeric`
		Email 		string 	`form:text,valid:required|valid_email`
		Introduce 	string 	`form:textarea`
	}
	
定义好struct之后接下来在controller中这样操作

	func (this *AddController) Get() {
		this.Data["form"] = beego.Form(&User{})
		this.Layout = "admin/layout.html"
		this.TplNames = "admin/add.tpl"
	}		
	
在模板中这样显示表单

	<h1>New Blog Post</h1>
	<form action="" method="post">
	{{.form.render()}}
	</form>
	
上面我们定义好了整个的第一步，从struct到显示表单的过程，接下来就是用户填写信息，服务器端接收数据然后验证，最后插入数据库。

	func (this *AddController) Post() {
		var user User
		form := this.GetInput(&user)
		if !form.Validates() {
			return 
		}
		models.UserInsert(&user)
		this.Ctx.Redirect(302, "/admin/index")
	}		
	
## 表单类型
以下列表列出来了对应的form元素信息：
<table cellpadding="0" cellspacing="1" border="0" style="width:100%" class="tableborder">
<tbody><tr>
<th>名称</th>
<th>参数</th>
<th>功能描述</th>
</tr>

<tr>
<td class="td"><strong>text</strong></td>
<td class="td">No</td>
<td class="td">textbox输入框</td>
</tr>

<tr>
<td class="td"><strong>button</strong></td>
<td class="td">No</td>
<td class="td">按钮</td>
</tr>

<tr>
<td class="td"><strong>checkbox</strong></td>
<td class="td">No</td>
<td class="td">多选择框</td>
</tr>

<tr>
<td class="td"><strong>dropdown</strong></td>
<td class="td">No</td>
<td class="td">下拉选择框</td>
</tr>

<tr>
<td class="td"><strong>file</strong></td>
<td class="td">No</td>
<td class="td">文件上传</td>
</tr>

<tr>
<td class="td"><strong>hidden</strong></td>
<td class="td">No</td>
<td class="td">隐藏元素</td>
</tr>

<tr>
<td class="td"><strong>password</strong></td>
<td class="td">No</td>
<td class="td">密码输入框</td>
</tr>

<tr>
<td class="td"><strong>radio</strong></td>
<td class="td">No</td>
<td class="td">单选框</td>
</tr>

<tr>
<td class="td"><strong>textarea</strong></td>
<td class="td">No</td>
<td class="td">文本输入框</td>
</tr>

</tbody></table>

		
## 表单验证		
以下列表将列出可被使用的原生规则
<table cellpadding="0" cellspacing="1" border="0" style="width:100%" class="tableborder">
<tbody><tr>
<th>规则</th>
<th>参数</th>
<th>描述</th>
<th>举例</th>
</tr>

<tr>
<td class="td"><strong>required</strong></td>
<td class="td">No</td>
<td class="td">如果元素为空，则返回FALSE</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>matches</strong></td>
<td class="td">Yes</td>
<td class="td">如果表单元素的值与参数中对应的表单字段的值不相等，则返回FALSE</td>
<td class="td">matches[form_item]</td>
</tr>

  <tr>
    <td class="td"><strong>is_unique</strong></td>
    <td class="td">Yes</td>
    <td class="td">如果表单元素的值与指定数据表栏位有重复，则返回False（译者注：比如is_unique[User.Email]，那么验证类会去查找User表中Email栏位有没有与表单元素一样的值，如存重复，则返回false，这样开发者就不必另写Callback验证代码。）</td>
    <td class="td">is_unique[table.field]</td>
  </tr>

<tr>
<td class="td"><strong>min_length</strong></td>
<td class="td">Yes</td>
<td class="td">如果表单元素值的字符长度少于参数中定义的数字，则返回FALSE</td>
<td class="td">min_length[6]</td>
</tr>

<tr>
<td class="td"><strong>max_length</strong></td>
<td class="td">Yes</td>
<td class="td">如果表单元素值的字符长度大于参数中定义的数字，则返回FALSE</td>
<td class="td">max_length[12]</td>
</tr>

<tr>
<td class="td"><strong>exact_length</strong></td>
<td class="td">Yes</td>
<td class="td">如果表单元素值的字符长度与参数中定义的数字不符，则返回FALSE</td>
<td class="td">exact_length[8]</td>
</tr>

  <tr>
    <td class="td"><strong>greater_than</strong></td>
    <td class="td">Yes</td>
    <td class="td">如果表单元素值是非数字类型，或小于参数定义的值，则返回FALSE</td>
    <td class="td">greater_than[8]</td>
  </tr>

  <tr>
    <td class="td"><strong>less_than</strong></td>
    <td class="td">Yes</td>
    <td class="td">如果表单元素值是非数字类型，或大于参数定义的值，则返回FALSE</td>
    <td class="td">less_than[8]</td>
  </tr>

<tr>
<td class="td"><strong>alpha</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值中包含除字母以外的其他字符，则返回FALSE</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>alpha_numeric</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值中包含除字母和数字以外的其他字符，则返回FALSE</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>alpha_dash</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值中包含除字母/数字/下划线/破折号以外的其他字符，则返回FALSE</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>numeric</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值中包含除数字以外的字符，则返回 FALSE</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>integer</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素中包含除整数以外的字符，则返回FALSE</td>
<td class="td">&nbsp;</td>
</tr>

  <tr>
    <td class="td"><strong>decimal</strong></td>
    <td class="td">Yes</td>
    <td class="td">如果表单元素中输入（非小数）不完整的值，则返回FALSE</td>
    <td class="td">&nbsp;</td>
  </tr>

<tr>
<td class="td"><strong>is_natural</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值中包含了非自然数的其他数值 （其他数值不包括零），则返回FALSE。自然数形如：0,1,2,3....等等。</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>is_natural_no_zero</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值包含了非自然数的其他数值 （其他数值包括零），则返回FALSE。非零的自然数：1,2,3.....等等。</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>valid_email</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值包含不合法的email地址，则返回FALSE</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>valid_emails</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素值中任何一个值包含不合法的email地址（地址之间用英文逗号分割），则返回FALSE。</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>valid_ip</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素的值不是一个合法的IP地址，则返回FALSE。</td>
<td class="td">&nbsp;</td>
</tr>

<tr>
<td class="td"><strong>valid_base64</strong></td>
<td class="td">No</td>
<td class="td">如果表单元素的值包含除了base64 编码字符之外的其他字符，则返回FALSE。</td>
<td class="td">&nbsp;</td>
</tr>

</tbody></table>


## links
   * [目录](<preface.md>)
   * 上一节: [Session支持](<14.2.md>)
   * 下一节: [用户认证](<14.4.md>)