{% raw %}
# 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"> </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"> </td>
</tr>
<tr>
<td class="td"><strong>alpha_numeric</strong></td>
<td class="td">No</td>
<td class="td">如果表單元素值中包含除字母和數字以外的其他字符,則返回FALSE</td>
<td class="td"> </td>
</tr>
<tr>
<td class="td"><strong>alpha_dash</strong></td>
<td class="td">No</td>
<td class="td">如果表單元素值中包含除字母/數字/下劃線/破折號以外的其他字符,則返回FALSE</td>
<td class="td"> </td>
</tr>
<tr>
<td class="td"><strong>numeric</strong></td>
<td class="td">No</td>
<td class="td">如果表單元素值中包含除數字以外的字符,則返回 FALSE</td>
<td class="td"> </td>
</tr>
<tr>
<td class="td"><strong>integer</strong></td>
<td class="td">No</td>
<td class="td">如果表單元素中包含除整數以外的字符,則返回FALSE</td>
<td class="td"> </td>
</tr>
<tr>
<td class="td"><strong>decimal</strong></td>
<td class="td">Yes</td>
<td class="td">如果表單元素中輸入(非小數)不完整的值,則返回FALSE</td>
<td class="td"> </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"> </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"> </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"> </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"> </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"> </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"> </td>
</tr>
</tbody></table>
## links
* [目錄](<preface.md>)
* 上一節: [Session支持](<14.2.md>)
* 下一節: [用戶認證](<14.4.md>)
{% endraw %}
- 目錄
- Go環境配置
- Go安裝
- GOPATH 與工作空間
- Go 命令
- Go開發工具
- 小結
- Go語言基礎
- 你好,Go
- Go基礎
- 流程和函數
- struct
- 面向對象
- interface
- 并發
- 小結
- Web基礎
- web工作方式
- Go搭建一個簡單的web服務
- Go如何使得web工作
- Go的http包詳解
- 小結
- 表單
- 處理表單的輸入
- 驗證表單的輸入
- 預防跨站腳本
- 防止多次遞交表單
- 處理文件上傳
- 小結
- 訪問數據庫
- database/sql接口
- 使用MySQL數據庫
- 使用SQLite數據庫
- 使用PostgreSQL數據庫
- 使用beedb庫進行ORM開發
- NOSQL數據庫操作
- 小結
- session和數據存儲
- session和cookie
- Go如何使用session
- session存儲
- 預防session劫持
- 小結
- 文本文件處理
- XML處理
- JSON處理
- 正則處理
- 模板處理
- 文件操作
- 字符串處理
- 小結
- Web服務
- Socket編程
- WebSocket
- REST
- RPC
- 小結
- 安全與加密
- 預防CSRF攻擊
- 確保輸入過濾
- 避免XSS攻擊
- 避免SQL注入
- 存儲密碼
- 加密和解密數據
- 小結
- 國際化和本地化
- 設置默認地區
- 本地化資源
- 國際化站點
- 小結
- 錯誤處理,調試和測試
- 錯誤處理
- 使用GDB調試
- Go怎么寫測試用例
- 小結
- 部署與維護
- 應用日志
- 網站錯誤處理
- 應用部署
- 備份和恢復
- 小結
- 如何設計一個Web框架
- 項目規劃
- 自定義路由器設計
- controller設計
- 日志和配置設計
- 實現博客的增刪改
- 小結
- 擴展Web框架
- 靜態文件支持
- Session支持
- 表單支持
- 用戶認證
- 多語言支持
- pprof支持
- 小結
- 參考資料