diff --git a/14.3.md b/14.3.md index b513cf31..6ef20572 100644 --- a/14.3.md +++ b/14.3.md @@ -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" + } + +在模板中这样显示表单 + +

New Blog Post

+
+ {{.form.render()}} +
+ +上面我们定义好了整个的第一步,从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元素信息: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名称参数功能描述
textNotextbox输入框
buttonNo按钮
checkboxNo多选择框
dropdownNo下拉选择框
fileNo文件上传
hiddenNo隐藏元素
passwordNo密码输入框
radioNo单选框
textareaNo文本输入框
+ + +## 表单验证 +以下列表将列出可被使用的原生规则 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
规则参数描述举例
requiredNo如果元素为空,则返回FALSE 
matchesYes如果表单元素的值与参数中对应的表单字段的值不相等,则返回FALSEmatches[form_item]
is_uniqueYes如果表单元素的值与指定数据表栏位有重复,则返回False(译者注:比如is_unique[User.Email],那么验证类会去查找User表中Email栏位有没有与表单元素一样的值,如存重复,则返回false,这样开发者就不必另写Callback验证代码。)is_unique[table.field]
min_lengthYes如果表单元素值的字符长度少于参数中定义的数字,则返回FALSEmin_length[6]
max_lengthYes如果表单元素值的字符长度大于参数中定义的数字,则返回FALSEmax_length[12]
exact_lengthYes如果表单元素值的字符长度与参数中定义的数字不符,则返回FALSEexact_length[8]
greater_thanYes如果表单元素值是非数字类型,或小于参数定义的值,则返回FALSEgreater_than[8]
less_thanYes如果表单元素值是非数字类型,或大于参数定义的值,则返回FALSEless_than[8]
alphaNo如果表单元素值中包含除字母以外的其他字符,则返回FALSE 
alpha_numericNo如果表单元素值中包含除字母和数字以外的其他字符,则返回FALSE 
alpha_dashNo如果表单元素值中包含除字母/数字/下划线/破折号以外的其他字符,则返回FALSE 
numericNo如果表单元素值中包含除数字以外的字符,则返回 FALSE 
integerNo如果表单元素中包含除整数以外的字符,则返回FALSE 
decimalYes如果表单元素中输入(非小数)不完整的值,则返回FALSE 
is_naturalNo如果表单元素值中包含了非自然数的其他数值 (其他数值不包括零),则返回FALSE。自然数形如:0,1,2,3....等等。 
is_natural_no_zeroNo如果表单元素值包含了非自然数的其他数值 (其他数值包括零),则返回FALSE。非零的自然数:1,2,3.....等等。 
valid_emailNo如果表单元素值包含不合法的email地址,则返回FALSE 
valid_emailsNo如果表单元素值中任何一个值包含不合法的email地址(地址之间用英文逗号分割),则返回FALSE。 
valid_ipNo如果表单元素的值不是一个合法的IP地址,则返回FALSE。 
valid_base64No如果表单元素的值包含除了base64 编码字符之外的其他字符,则返回FALSE。 
+ ## links * [目录]() diff --git a/14.4.md b/14.4.md index d266f1b1..f9b9c74f 100644 --- a/14.4.md +++ b/14.4.md @@ -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 * [目录]() diff --git a/14.5.md b/14.5.md index 72420b06..422904a0 100644 --- a/14.5.md +++ b/14.5.md @@ -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 * [目录]() * 上一节: [用户认证](<14.4.md>) diff --git a/14.6.md b/14.6.md index c02c13c6..8c76f35c 100644 --- a/14.6.md +++ b/14.6.md @@ -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 * [目录]() diff --git a/README.md b/README.md index 0e540c8c..5d866d5d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ 这本书目前我放在Github上,我现在基本每天晚上抽空会写一些,时间有限、能力有限,所以希望更多的朋友参与到这个开源项目中来。 -**参加了51CTO博客大赛,希望你能够投出宝贵的一票:[http://blog.51cto.com/contest2012/6177767](http://blog.51cto.com/contest2012/6177767)** ## 撰写方法 ### 文件命名 diff --git a/images/14.6.pprof.png b/images/14.6.pprof.png new file mode 100644 index 00000000..532f1a76 Binary files /dev/null and b/images/14.6.pprof.png differ diff --git a/images/14.6.pprof2.png b/images/14.6.pprof2.png new file mode 100644 index 00000000..610c93a4 Binary files /dev/null and b/images/14.6.pprof2.png differ diff --git a/images/14.6.pprof3.png b/images/14.6.pprof3.png new file mode 100644 index 00000000..a3b9f7ba Binary files /dev/null and b/images/14.6.pprof3.png differ