基本快完成了,就剩下第四小节用户验证了

This commit is contained in:
xiemengjun
2013-01-13 19:39:19 +08:00
parent 8723b56cf8
commit cab9207caa
8 changed files with 488 additions and 1 deletions

275
14.3.md
View File

@@ -1,4 +1,279 @@
# 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>)

13
14.4.md
View File

@@ -1,4 +1,17 @@
# 14.4 用户认证
我们在开发Web应用的过程中用户认证是我们经常遇到的问题用户登录、注册、登出等操作而一般认证也分为三个方面的认证
- HTTP Basic和 HTTP Digest认证
- 第三方集成认证QQ、微博、豆瓣、OPENID、google、github、facebook和twitter等
- 自定义的用户登录、注册、登出一般都是基于session、cookie认证
beego目前没有针对这三种方式进行任何形式的集成但是可以充分的利用第三方开源库来实现上面的三种方式的用户认证
## HTTP Basic和 HTTP Digest认证
## oauth和oauth2的认证
## 自定义认证
## links
* [目录](<preface.md>)

107
14.5.md
View File

@@ -1,5 +1,112 @@
# 14.5 多语言支持
我们在第十章介绍过国际化和本地化开发了一个go-i18n库这小节我们将把该库集成到beego框架里面来使得我们的框架支持国际化和本地化。
## i18n集成
beego中设置全局变量如下
Translation i18n.IL
Lang string //设置语言包zh、en
LangPath string //设置语言包所在位置
初始化多语言函数:
func InitLang(){
beego.Translation:=i18n.NewLocale()
beego.Translation.LoadPath(beego.LangPath)
beego.Translation.SetLocale(beego.Lang)
}
为了方便在模板中直接调用多语言包,我们设计了三个函数来处理响应的多语言:
beegoTplFuncMap["Trans"] = i18n.I18nT
beegoTplFuncMap["TransDate"] = i18n.I18nTimeDate
beegoTplFuncMap["TransMoney"] = i18n.I18nMoney
func I18nT(args ...interface{}) string {
ok := false
var s string
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
s = fmt.Sprint(args...)
}
return beego.Translation.Translate(s)
}
func I18nTimeDate(args ...interface{}) string {
ok := false
var s string
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
s = fmt.Sprint(args...)
}
return beego.Translation.Time(s)
}
func I18nMoney(args ...interface{}) string {
ok := false
var s string
if len(args) == 1 {
s, ok = args[0].(string)
}
if !ok {
s = fmt.Sprint(args...)
}
return beego.Translation.Money(s)
}
## 多语言开发使用
1. 设置语言以及语言包所在位置然后初始化i18n对象
beego.Lang = "zh"
beego.LangPath = "views/lang"
beego.InitLang()
2. 设计多语言包
上面讲了如何初始化多语言包现在设计多语言包多语言包是json文件如第十章介绍的一样我们需要把设计的文件放在LangPath下面例如zh.json或者en.json
# zh.json
{
"zh": {
"submit": "提交",
"create": "创建"
}
}
#en.json
{
"en": {
"submit": "Submit",
"create": "Create"
}
}
3. 使用语言包
我们可以在controller中调用翻译获取响应的翻译语言如下所示
func (this *MainController) Get() {
this.Data["create"] = beego.Translation.Translate("create")
this.TplNames = "index.tpl"
}
我们也可以在模板中直接调用响应的翻译函数:
//直接文本翻译
{{.create | Trans}}
//时间翻译
{{.time | TransDate}}
//货币翻译
{{.money | TransMoney}}
## links
* [目录](<preface.md>)
* 上一节: [用户认证](<14.4.md>)

93
14.6.md
View File

@@ -1,4 +1,97 @@
# 14.6 pprof支持
Go语言有一个非常棒的设计就是标准库里面带有代码的性能监控工具在两个地方有包
net/http/pprof
runtime/pprof
其实net/http/pprof中只是使用runtime/pprof包来进行封装了一下并在http端口上暴露出来
## beego支持pprof
目前beego框架新增了pprof该特性默认是不开启的如果你需要测试性能查看相应的执行goroutine之类的信息其实Go的默认包"net/http/pprof"已经具有该功能如果按照Go默认的方式执行Web默认就可以使用但是由于beego重新封装了ServHTTP函数所以如果你默认的包含是无法开启该功能的所以需要对beego的内部改造支持pprof。
- 首先在beego.Run函数中根据变量是否自动加载性能包
if PprofOn {
BeeApp.RegisterController(`/debug/pprof`, &ProfController{})
BeeApp.RegisterController(`/debug/pprof/:pp([\w]+)`, &ProfController{})
}
- 设计ProfConterller
package beego
import (
"net/http/pprof"
)
type ProfController struct {
Controller
}
func (this *ProfController) Get() {
switch this.Ctx.Params[":pp"] {
default:
pprof.Index(this.Ctx.ResponseWriter, this.Ctx.Request)
case "":
pprof.Index(this.Ctx.ResponseWriter, this.Ctx.Request)
case "cmdline":
pprof.Cmdline(this.Ctx.ResponseWriter, this.Ctx.Request)
case "profile":
pprof.Profile(this.Ctx.ResponseWriter, this.Ctx.Request)
case "symbol":
pprof.Symbol(this.Ctx.ResponseWriter, this.Ctx.Request)
}
this.Ctx.ResponseWriter.WriteHeader(200)
}
## 使用入门
通过上面的设计你可以通过如下代码开启pprof
beego.PprofOn = true
然后你就可以在浏览器中打开如下URL就看到如下界面
![](images/14.6.pprof.png?raw=true)
点击goroutine我们可以看到很多详细的信息
![](images/14.6.pprof2.png?raw=true)
我们还可以通过命令行获取更多详细的信息
go tool pprof http://localhost:8080/debug/pprof/profile
这时候程序就会进入30秒的profile收集时间在这段时间内拼命刷新浏览器上的页面尽量让cpu占用性能产生数据。
(pprof) top10
Total: 3 samples
1 33.3% 33.3% 1 33.3% MHeap_AllocLocked
1 33.3% 66.7% 1 33.3% os/exec.(*Cmd).closeDescriptors
1 33.3% 100.0% 1 33.3% runtime.sigprocmask
0 0.0% 100.0% 1 33.3% MCentral_Grow
0 0.0% 100.0% 2 66.7% main.Compile
0 0.0% 100.0% 2 66.7% main.compile
0 0.0% 100.0% 2 66.7% main.run
0 0.0% 100.0% 1 33.3% makeslice1
0 0.0% 100.0% 2 66.7% net/http.(*ServeMux).ServeHTTP
0 0.0% 100.0% 2 66.7% net/http.(*conn).serve
(pprof)web
![](images/14.6.pprof3.png?raw=true)
## links
* [目录](<preface.md>)

View File

@@ -9,7 +9,6 @@
这本书目前我放在Github上我现在基本每天晚上抽空会写一些时间有限、能力有限所以希望更多的朋友参与到这个开源项目中来。
**参加了51CTO博客大赛希望你能够投出宝贵的一票[http://blog.51cto.com/contest2012/6177767](http://blog.51cto.com/contest2012/6177767)**
## 撰写方法
### 文件命名

BIN
images/14.6.pprof.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
images/14.6.pprof2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

BIN
images/14.6.pprof3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB