go的应用场景更多情况下应用于后台,也可以用于开发web。后台和web都是用到net和net/http模块,而开发web则还需要html/template模块。当然了实际使用中html/template虽然可以满足很多的要求,但是如果需要快速方便的开发,还可以使用web框架进行更加快捷的开发。这里推荐使用国人开发的beego框架。
注意,网页的函数不是使用驼峰规范的,函数都是小写的,这点需要注意!另外,网页的设计使用dreamwaver进行会比较好,dreamwaver用于专业的网页设计,所以可以使用dreamwaver设计好网络,然后将文件放到IDE中使用。
使用swagger框架可以让API可视化,这样管理和使用API就可以变得简单了。实际上一般的web,后台,应用都有一个后台或者界面用于管理,所以swagger就变得尤为重要了。
对于Restful概念,其实就是能够识别method,并运行相应的处理,例如使用Get调用Restful接口,那么会运行Get方式的相应处理。
对于go的web开发,一般用到的就是net/http模块和html/template模块。其中net/http模块提供网页的相关操作,而html/template一般就是网页的相关io和渲染。
对于net/http模块最重要的是ServeMux类,但同时这个类也是最容易被忽略的,因为实际上我们几乎不回去用它,而系统会帮我们创建一个DefaultServeMux类对象,而我们使用的很多http的函数其实都是在使用DefaultServeMux类对象的方法,比如http.Handle(),http.HandleFunc()等就是调用ServeMux.Handle(),ServeMux.HandleFunc(),当然如果我们需要自行创建一个ServeMux类对象,那么可以http.NewServeMux()函数创建,然后将他传递给http.ListenAndServe()函数,这里ServeMux类其实实现了Handler.ServeHTTP()方法,所以可以创递给http.ListenAndServe()函数。最后注意,ServeMux类有一个map用于存储网址和处理函数。
所以这里,如果我们自行创建ServeMux类对象,那么我们可以直接通过ServeMux.Handle(),ServeMux.HandleFunc()等传递网址和处理函数,然后再传递给http.ListenAndServe()就可以了。
这里其实最简单的网页时直接使用http.ListenAndServe(),其中第一个参数是端口,而第二个Handler类对象用于处理网址和处理函数。同时注意Handler.ServeHTTP()函数。另外,http.Serve()函数跟http.ListenAndServe()函数类似,只是更多的用于监听。
一般情况下不用自己去实现ServeMux类对象,而http.ListenAndServe()的第二个参数一般是nil。
特别注意,其实在设计函数的时候,一般会有一个最底层的函数,然后会衍生出其他的衍生函数来对这个函数进行封装,以更好的使用函数。例如X()函数,他的衍生函数一般就是XSS(),或者SSX()。
http.Handle()和http.HandleFunc()其实意思是差不多,只是前者需要通过一个Handler类对象来处理,而后者直接使用函数,其实这里都是在使用ServeHTTP()函数而已。当然,对应的有Handler,HandlerFunc两个类。同时注意,http.Handle()函数的一般用法是http.Handle("", http.FileServer(http.Dir()))。最后注意,这两个函数都是用于处理网址和处理函数的,底层其实使用的是DefaultServeMux。
对于Handler,其实net/http模块使用装饰器模式为他添加了函数,分别是http.StripPrefix(),http.TimeoutHandler()两个函数,前者用于去掉网址前缀,也就是说,可以给网址添加更长的地址,然后这部分地址可以使用stripPrefix()去掉,而后者用于超时,超过了时间就可以调用相应的操作。另外,http.FileServer()常和http.StripPrefix()联合使用。
这里说道http.FileServer(http.Dir())就应该注意了,这个函数返回一个Handler类对象,而而http.Dir()定位一个路径,如果路径不是一个文件,而是路径,那么这个函数优先定位路径下的index.html文件。
同时注意,http.FileServer(http.Dir())可以读入路径下的文件,所以对于静态文件的读入可以使用这个函数,一般使用方式是http.Handle("", http.FileServer(http.Dir())。另外还可以使用http.ServeFile()这个函数,这个函数是读取文件,如果读取的路径不是文件会输出路径下所有的文件名。所以这两个函数可以用于css,js等静态文件的读取,这样就可以实现静态文件与动态方法的分离了。最后注意,之所以需要读取静态文件,是因为如果不读取静态文件,而html文件刚好使用到了静态文件,那么结果就是html渲染失败。
最后注意,对于css,js等静态文件,如果需要缓冲加载,可以利用go的包加载机制。注意,每个包文件都可以实现多个init()函数,也可以不使用,但是main包下必须要一个main()函数,这是程序的入口。使用init()函数实现缓冲加载。但是需要注意,一个包被多个包同时引用的话,那么init()就只会调用一次,同时每个包都有init(),而只有main包有main()函数,而且init()函数在main()函数之前运行。
这里注意,css,js等被称为静态文件,而html被称为模板。另外html/template模块本身就是模板模块。
在使用中使用http.FormValue()获取POST过来的参数键值对的值。使用http.FormFile()获取整个文件的数据,如果是图像文件的话,这个函数需要先设置ResponseWriter.Header().Set("Content-Type", "image")。而一般这个函数对应的是html的form表单中传递的image文件。例如:
html> <html lang="en"> <head> <meta charset="UTF-8"> <title>GopherWebtitle> head> <body> <form method="POST" action="/upload" enctype="multipart/form-data"> Choose an image to upload: <input name="image" type="file"/> <input type="submit" value="Upload"/> form> body> html>这里可以看出实际上传递使用的是multipart文件的方式,使用POST方式,而http.FormFile("image")对应的是type="file"和name="image"。同时注意submit之后action跳转提交给/upload网址。
最后注意,对于网页的错误输出一般使用http.Error()和http.NotFound()将错误信息输出到网页。可以使用ResponseWriter.WriteHeader()方法添加HTTP状态码!
对于html/template模块,一般使用template.Execute(),template.ExecuteTemplate()函数,这两个函数都是用于将html文件渲染后输出到浏览器的。对于一般的html文件,直接输出到ResponseWriter就可以了,但是对于添加了go代码的html文件,就需要使用这两个函数先进行渲染,然后才能输出,当然一般的html文件也是可以的,但是template.Execute()函数的第二个参数不为nil才行。
其实使用template模板的一般顺序是template.New("").Funcs(template.FuncMap{}).ParseFiles(),这里template.New(“name”)的name就是template.ExecuteTemplate()中第二个参数需要的名字。当然了,这个顺序如果没有给出名字,那么template.ExecuteTempalte()的需要的name应该使用ParseFiles()中文件的名字。其实这里Funcs()函数导入的参数就是html中go代码用到的参数,这些参数其实就是template.Execute()中第二个参数使用的数据。所以简单点说就是template.New()实现了一个模板,这个模板可以使用Funcs()函数嵌入参数数据。
template.Execute()的第二个参数一般就是一个map[string]interface{},用于传递html文件中go代码需要的参数数据。例如:list.html文件:
html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Listtitle> head> <body> <ol> {{range $.images}} <li><a href="/view?={{.|urlquery}}">{{.|html}}a>li> {{end}} ol> body> html>然后传递给http.HandleFunc()第二个参数的函数:
func listHandler(writer http.ResponseWriter, request *http.Request) { fileInfoArr, err := ioutil.ReadDir("./web/uploads") if err != nil { http.Error(writer, err.Error(), http.StatusInternalServerError) return } images := []string{} for _, fileInfo := range fileInfoArr { images = append(images, fileInfo.Name()) } locals := make(map[string]interface{}) //这里将被html文件里面的操作查找,因此map的key需要对应好 locals["images"] = images tmp, err := template.ParseFiles("./web/view/list.html") if err != nil { http.Error(writer, err.Error(), http.StatusInternalServerError) return } tmp.Execute(writer, locals) }
这里可以看到,locals["images']的key是images,在list.html中就是调用这个images的。
另外如果有一些css,js,html等定义的元素需要添加到html中进行渲染的话,一般使用http.Execute()的第二个参数进行传递,而这个参数不应该是map[string]string,而应该是map[string]template.HTML,而为如果使用字符串的话,那么像>这一类的会被当成大于号、小于号。例如使用map[string]template.HTML{"html":"
"},这里的"html"在html中将被{{.|html}}这种形式使用
对于一些错误,一般使用template.Must()函数,这个函数用于如果发生错误,那么一定会panic的场景。
其实对于html/template模块,可以当成io进行记忆,例如使用Parse(),ParseFile(),ParseFiles()函数进行读入渲染,使用Execute(),ExecuteTemplate()函数将渲染页面输出到浏览器。使用New()函数生成Template模板。
应该说,go的html模块都是在使用html/template模块。当然对于如果说到html,那么有两个第三方框架需要说明,一个是goquery,一个是google自己提供的html。html是html解析器,把html解析出来。而goquery基于html包,结合cascadia这个css选择器工具,实现类似jquery功能,操作html非常方便。他们的地址分别是:
https://github.com/PuerkitoBio/goquery
和
http://code.google.com/p/go.net/html
另外,需要注意,go的database/sql模块是数据库模块,这个模块里面有一个driver模块,这个模块其实是用于跟外部数据库实现对接的接口模块,一般不需要查看,所以database/sql模块主要的是使用sql.Open(),sql.Register()返回的DB的对象,使用DB对象可以实现操作数据库,当然,对于不同的数据库需要不同的驱动,这点在连接数据库时需要注意。
所以说,使用net/http模块和html/template模块就基本上可以实现大多数网页操作了。而如果我们需要更加快捷,健壮的框架,或者说需要实现restful API,那么其实可以尝试使用beego框架,这个框架是借鉴了flask,tornado等框架实现的,尽管还是有一些bug需要修复,但是是目前一个很好的选择。
在使用beego之前需要明确:
1、MVC的操作中,model用于隔离数据库与其他模块的耦合,简单点说就是model与数据库交互,而其他模块跟model交互就可以了。
2、模块化项目。应该说除了主要的编码部分,一个项目的配置,全局变量,转发都已经被模块化了,这样做的好处是模块化,便于修改,同时结构更加清晰。
3、go本身实现了http服务器,而apache,nginx这些本身就是服务器,所以在功能上会有部分重叠的,例如路由,index的查找等,可以通过go服务器来学习这些服务器,而实际使用上,我们可以将一些功能使用apache,nginx来实现,就不用我们来实现了,例如日志访问,静态访问。其实apache,nginx都是使用反向代理,将请求往后传递,而apache,nginx都是用配置设置的。总的来说就是,go的http服务器时最简单最底层的服务器,而apache,nginx服务器包含更多的功能,可以实现更多的功能,所以使用apache,nginx来实现已经有的功能可以少打代码。而beego框架的话,其实就是服务器外面嵌套服务器。
4、直接部署项目的话,会将项目暴露在外,所以使用apache,nginx服务器来做负载均衡和认证等。
5、web服务器专门为web服务,一般需要支持HTTP,HTML,URL等,简单点说就是配合浏览器使用的服务器,而HTTP服务器是为了实现服务器功能的服务器,所以总的来说web服务器和http服务器时差不多的概念。而应用服务器是用于实现功能和服务的服务器。
6、项目应该更加专注在逻辑和功能上,而不是配置设置,这些可以分散给其他的服务器和框架。
7、beego项目编译形成二进制文件之后放在服务器上,我们需要将conf,views,static文件夹的放在跟这个二进制文件同目录的文件夹下,因为conf,views,static下的文件是不会被编译的。
8、beego基于go本身的代码进行的封装,而且很多功能本身go也有,beego对这些功能进行封装,例如beego.Handler(),beego.ErrorHandler(),beego.ParseForm(),beego.AddFuncMap(),beego.Get()等,而实际上,beego下的封装也是很有规律的,例如tempalte.go文件下封装了go的template模块,而config.go封装的是配置文件。
9、go的模板里面{{}}里面使用的参数方法都是需要提前设置的,而beego自身也设置了一些可以使用参数方法给模板使用。
app.go这个文件里面有beego的大部分应用功能,例如http功能:beego.Get(),beego,Post(),beego.Put(),beego.Delete(),beego.Any(),beego.Options(),路由功能:beego.router(),beego.Handler(),模板功能beego.ParseForm(),beego.AddFuncMap()等,而且这里http功能封装后使用起来更加简单。总的来说,app.go文件里面封装了go的很多功能。app.go是beego的功能模块源文件.
beego.go源文件里面是beego的生命周期函数,例如beego.Run(),beego.AddAppStartHook()。
beego的配置。beego使用ini作为设置文件,这点和windows一样,ini文件由节,键,值组成,ini文件的尾缀没有要求,所以这里beego的使用.conf格式,例如app.conf,不过需要注意的是,虽然app.conf文件是ini格式,但是却可以使用include "xxx.conf"来包含其他配置文件,另外,mysql的一些配置信息也是可以在app.conf中设置的,而这些信息在conf.go中确实没有相关设置的。需要注意的一点是,app.conf的设置虽然大部分是根据conf.go源文件来设置的,可以查看conf.go文件进行需要的设置,但是却不是所有的设置都可以从conf.go查看到。
app.conf文件可以设置对内监听adminport="",adminaddr="",可以设置http对外端口httpport="",可以设置https对外端口httpsport等。总的来说就是对于设置的东西,通过conf.go源文件查看就可以了。在app.conf文件中,配置最多的其实是MVC部分的设置,controller最多,例如adminport="",adminaddr="",httpport=""等,而model部分,其实数据库设置也在app.conf中设置,例如mysql的设置。另外,其实这里监听端口使用的是go的http.ListenAndServe()。
app.conf文件的默认值可以使用config.NewConfig()函数查看,也就是说,可以在config.go源文件中查看。当然使用config.NewConfig("ini", "my.conf")可以返回配置文件对象Configer,使用Configer.String("section::key")就可以得到相应的配置值了。这是获取配置文件的数据的方式。
beego的路由。路由用于转发请求,并作出相应的处理,将URL路由设置放置在项目的router.go文件内。详细的路由设置可以查看router.go源文件。
beego的路由分为:固定路由,正则路由,自动路由。使用beego.Router()实现,使用这个函数调用相应的Controller。最后需要注意,如果实现大量的整体设置,或者URL分支,那么使用beego.NewNameSpace()设置命名空间会是一个很好的选择,简单点说就是URL分支体系使用命名空间。
可以使用beego.InsertFilter()添加一个路由给URL,用于过滤。
最后特别注意,在go内置的http服务器中,web,http等网络请求是没有并发的,需要我们自己添加并发网络。但是beego中,路由为每一个URL添加一个goroutine,所以对于使用URL跳转到的网页首先就不用我们实现并发了,这点注意。
beego的controller。beego中一个Controller对应一个URL,router会将请求发送到Controller进行处理。Controller其实封装了go的一些功能,例如Controller的TplName相当于http.Handle(http.FileServer())寻找index.html文件的功能,而Data参数则是传递参数给模板使用,而Layout,LayoutSections则是模板可以使用的layout,这会在view模块中知道详细用处。更多的Controller功能,其实在controller.go源文件中都有。
注意,如果在Controller的TplName没有指定的话,那么源代码会使用c.TplName=strings.ToLower(c.controllerName)+"/"+strings.ToLower(c.actionName)+"."+c.TplExt生成需要的tpl文件名。而Controller的Data值如果是结构体,那么需要传递指针,也就是Data[xx]=&XXX{}。
在beego中,使用Controller的TplName参数代替了template.ParseFiles()的文件,而使用beego.AddAppFuncMap()和Controller的Data代替了template.Funcs(template.FuncMap{})。需要注意的是,在beego中,使用http.FileServer()查找index.html文件虽然可以调用index.html文件,但是却不会显示文件需要设置beego.BConfig.WebConfig.DirectoryIndex=true才能显示,另外,调用这个之后能够显示目录下的文件列表。也就是说beego.BConfig.WebConfig.DirectoryIndex=true之后http.FileServer()才能正确使用。
beego的view。程序会预编译并保存views下的模板到map下,但是注意dev模式下不会缓存views下的模板,每次都是重新加载的。这里views下的文件之所以可以是.tpl格式,是因为使用了beego.AddTemplateExt()函数,所以我们可以给模板增加后缀名,另外,beego内置的类型是html和tpl。而且views下的index.tpl文件其实相当于index.html文件。最后需要特别注意的是,go中使用template.Funcs(template.FuncMap{})来给模板增加参数或者函数,而beego下template.go源文件下的是给模板使用的参数,templatefunc.go源文件下的是给模板使用的函数,下面的函数可以作为参数给模板调用。如果需要改变views的路径,可以使用beego.SetViewsPath(),使用beego.SetStaticPath()将views下的静态文件暴露给用户使用。
在使用beego.RenderForm()将struct转化为html,这个函数是templatefunc.go的函数,所以可以知道beego.RenderForm()是在模板中使用的函数。只是这个函数仅仅是转化而已,比较单调。另外实际上,我们调用完方法之后之所以不用我们手动渲染输出,是因为beego已经帮我们Render了,但是如果不需要beego为我们渲染,可以在app.conf中设置autorender=false取消自动渲染。
其实对于go的模板。模板内{{}}如果使用函数,那么函数的小括号是去掉的,参数跟函数名以空格分隔,而函数名以小写出现,这里beego内置的函数可以在templatefunc.go中查看,常用的有print,printf,println用于输出,另外注意常用的命令call,index,len,and,or,not,所以需要注意区分函数与命令。而模板中的比较符号等,例如大于号,小于号等可以在template.go中查看,已经使用gt,lt,eq,ne,le,ge代替。
模板中也是支持流程控制的,需要注意的是,这里range可以和else搭配使用,也就是{{range}}{{else}}{{end}},而with也是可以和else搭配使用的,也就是{{with}}{{else}}{{end}},这里with用于给变量赋值和给pipeline重定向。
模板可以使用嵌套的方式生成,由于目前使用目录下文件进行缓存的方式,所以可以使用如:
{{template "header.html" .}}
Logic code
{{template "footer.html" .}}
这里其实是调用template这个函数,而这里最后的“.”其实是将当前当前当做参数传递给template函数。而template后面的参数可以是路径,这点注意。其实如果使用嵌套,那么使用{{define “文件名”}}内容{{end}},然后在需要的嵌入的文件中调用{{template “文件名”}}。另外,对于html文件的布局,需要注意,一般css文件放在head,而JavaScript放在body的末尾。
go本身实现了模板的嵌套,但是beego对于嵌套设计更加完善。
使用Controller的TplName和Layout可以实现像android那样的布局,也就是将TplName嵌入到Layout里面,只是,Layout指定的文件需要加入{{.LayoutContent}}。单单使用LayoutContent是不够的,所以Controller增加了LayoutSections,而LayoutSections是一个map,然后使用上感觉就是Data,那么设置LayoutSections有什么用呢,其实是因为Data支持的是参数和方法,而LayoutSections支持的是路径文件,所以简单点说就是LayoutSections用于设置多个section,这样就可以使用不同的css,js等用于渲染页面了。总的来说,Controller中,TplName就是一个主文件,Layout是布局,而LayoutSections是零碎的渲染用的布局文件。
在模板中其实除了一般的html,css,JavaScript代码之外,最需要注意的是go的嵌入代码,也就是{{}}的代码,这里{{}}支持pipeline方式操作,pipeline原本的操作格式是:grep 参数 格式 路径。一般没有“”的是参数,而格式一般使用“”括起来,而这里在{{}}中使用一般忽略路径,同时往往将前一个操作的结果作为后一个的参数,例如{{.|html}}将前面的结果“.”作为参数给html函数处理,也就是按html格式输出的意思。所以这里pipeline使用“|”将上一个结果传递给下一个函数处理。最后需要特别注意的是,pipeline这里虽然使用正则进行匹配,但是这里对每一行进行匹配,同时输出的是匹配的行,而不是匹配的部分,这点需要特别注意!
beego的model层。model层一般就是用于跟数据交互,然后其他的逻辑代码就可以直接跟model交互了,这样就起到隔离数据库的操作。在beego中使用orm实现这种操作。orm中最主要关注Ormer,QuerySeter两个类。
orm.RegisterModel()注册定义的model,如果仅仅是使用raw查询,和map struct的话是不用注册model的,简单点说就是,使用数据库和使用数据库生成model的话不用注册model。如果进行高级查询orm.QuerySeter()的话,那么是必须要注册model的。一般讲orm.RegisterModel()放在init(),因为这样的话重启应用之后就会重新注册model了,不会因为释放了注册信息而导致使用错误。总的来说就是使用Ormer可以不调用orm.RegisterModel(),如果使用orm.QuerySeter(),就需要调用orm.RegisterModel()。
使用orm.RegisterDriver(),orm.RegisterDatabase()注册驱动和数据库,使用orm.GetDB()获取DB对象进行数据库操作对象。orm.NewOrm()初始化一个Ormer,然后使用这个Ormer对象进行orm操作,但是注意,链接池无法让两次查询使用同一个链接,需要管理链接池和数据库链接,这个时候可以使用orm.NewOrmWithDB()。使用orm.NewOrm().Using(“database”)切换数据库,如果使用默认的default数据库,那么可以不用Using()进行切换。使用orm.NewOrm().QueryTable()返回QuerySeter对象进行高级查询,如果没有注册model会panic。总的来说就是使用Ormer为主要操作对象,而QuerySeter为高级操作对象。另外注意,如果需要切换数据库和事务的话,不要保存全局的Ormer。
使用orm.NewOrm().QueryTable()就可以返回可以查选的表对象QuerySeter对象了,使用QuerySeter.Filter()可以进行表where操作,也可以在Filter()之后配合SetCond()设置查询条件,当然还可以使用orm.NewCondition()设置条件。另外QuerySeter还可以进行联合查询,使用orm.NewOrm().RelatedSel()进行联合查询,注意,联合查询的效率要比一个个查询的效率高很多,所以多使用内联,外联等联合查询方式。总的来说,就是使用QuerySeter可以进行需要的各种高级查询,而低级的查询使用Ormer就可以了,例如Raw(),Read(),ReadOrCreate(),Update(),Delete(),Commit()等。
需要注意,Ormer一般是简单的CRUD操作,如果需要复杂的操作,可以使用orm.QueryBuilder(),QueryBuilder更适合复杂查询,子查询,多重联结。这里QueryBuilder将很多SQL操作封装成函数进行操作。
使用orm.Insert()可以实现orm操作,将一个类变成表。而这个类一般使用tag来作为生成的表的说明。tag本来在go中是作为reflect使用的,使用reflect.TypeOf().FieldByName()得到StructField和bool对象,然后使用StructField.Tag().Get(“key”)就可以得到相应的值了。这里的类中的tag里面使用键值对,所以使用Get()中使用key获取值。而这里beego的orm使用struct的tag方式设置数据库的表存储方式,常见的格式是:
type Post struct {
Id int
Title string
User *User `orm:"rel(fk)"` //设置一对多关系
Tags []*Tag `orm:"rel(m2m)"`
}
这里value可以是函数,同时注意使用··括起来,因为“”被用在value上了,而key可以不用“”括起来。应该说,orm中,使用带struct的tag一般就是orm:"xxx"格式的。
SQL中,使用AND进行多个语句连接,使用NOT表示排除条件。另外,WHERE name LIKE `%silent%`表示name是否包含silent,大小小写不敏感,而WHERE name LIKE BINARY `%silent%`表示name是否包含silent,大小写敏感,所以BINARY用于表示带小写敏感。而LIKE用在WHERE子句中搜索列匹配的模式,以上面的例子来说的话,就是name作为列名,而LIKE后面作为匹配模式。
validation.Validation{}用于表单验证,而beego.ErrorHandler()用于定义错误页面,beego.ErrorController用于错误处理。
beego作为服务器,不仅是web服务器,还可以是http服务器。在简单的功能上封装了http的常见请求使用beego.Get(),beego.Post(),beego.Put()等,这些封装了go的http操作,使得操作更为简单。但是实际上beego还有一个httplib模块,这个模块也实现了http的请求,但是两者有不同的地方,例如beego.Get()函数,有两个参数,一个是url,而另一个是相应的操作函数参数,而httplib的跟go的一样httplib.Get()函数中参数是url而已,但是httplib.Get()之后的操作却比beego.Get()的更加简单,因为他可以返回各种类型的数据,例如httplib.Get().String(),还可以查看请求的数据httplib.Get().Debug(true).Response()。总的来说应该是,beego的http请求提供了常见方便的操作方式,而httplib的则是更加完善的功能。httplib支持类似jquery的链式请求。
httplib.Post().Param()可以设置post参数,httplib.Post().Body()可以设置大片的数据,httplib.Post().Header()可以设置头信息,可以使用httplib.Post().PostFile()直接发送数据。
同样的如果使用httplib进行https请求,需要使用httplib.Get().SetTLSClientConfig(&tls.Config{InsecureSkipVerify:true})。
beego的功能按照模块分割,这样做除了解耦之外,也更加容易维护,功能也更清晰。beego的功能模块由grace,config,httplib,session,cache,context,logs,i18n,toolbox组成。每个功能模块都相应的对go的功能进行了不同程度的封装。
toolbox是beego的工具模块。可以使用toolbox.NewTask()生成一个任务,然后使用toolbox.AddTask()添加一个任务,然后toolbox.StartTask(),toolbox.StopTask()就可以开始和停止任务了。说白了就是android的TimerTask。这点跟go的time.AfterFunc(),time.Timer,time.Tick()很像。
toolbox的调试模块使用Display()和GetDisplayString()分别输出到console和获取输出到console的字符串。输出参数格式和println一样。
toolbox实现了beego的对内监听,也就是说app.conf中设置adminport="",adminaddr=""用于监听其实是使用toolbox的功能。对内监听可以实现统计和查询应用运行状态。toolbox对内监听默认是localhost:8088,使用adminport="",adminaddr=""可以修改监听的地址。实际上toolbox对内监听可以直接输入localhost:8088/healthcheck,而过滤信息可以使用localhost:8088/listconf?/command=filter。总的来说就是toolbox的对内监听使用的是配置文件和URL获取数据的方式进行。
cache模块是缓冲模块,是基于database/sql设计的,有file,memcache,memory,redis四种引擎,使用cache.NewCache()得到缓存对象,可以进行增删查改缓存等操作,也就是Post(),Get(),Put(),Delete(),IsExist()等操作。
grace模块是热升级模块,使用grace.ListenAndServe()监听。加入这里grace.ListenAndServe("/hello"),那么使用两个命令窗口分别输入ps -ef “应用名“和curl "http://127.0.0.8080/hello",然后热升级,一个窗口输入命令:kill -HUP 进程ID,另一个窗口输入命令:curl "http://127.0.0.8080/hello?sleep=0"。总的来说,就是grace监听摸一个URL进行升级使用,然后我们需要热升级的时候,先使用curl定位到这个URL告诉grace要进行升级了,然后获取进程号,并杀死这个进程,然后在使用curl定位到热升级的URL并告诉他重启进程,而curl的url中有参数告诉sleep的号是多少。
logs模块可以将log数据输出到console和file中,logs.SetLogFuncCall()可以输出调用的文件名和文件行号,当然也可以直接调用beego.SetLogFuncCall()。
session模块是会话模块。session涉及到cookie,实际上cookie和session类似,只是cookie存储在客户端,而session存储在服务端。另外,需要客户端支持cookie才能使用session,如果客户端不支持cookie,那么这个session模块是不能使用的。
我们可以使用Context.GetCookie(),Context.SetCookie()来操作cookie。另外如果使用非memory方式存储,那么需要在main的init()中注册需要存储的结构体,不然重启应用之后会解析出错,这是因为beego使用gob方式注册存储对象。也就是说session的memory方式实用gob序列化存储,而非memory方式则没有使用gob方式。
i18n模块是国际化模块。国际化其实就是实现多语言切换。多语言的切换一般可以在URL中添加一个lang参数设置,也可以在表头的Accept-Language中设置。可以使用Input.Get("lang")获取URL的语言设置,使用Context.GetCookie("lang")获得cookie的语言设置,而是用Request.Header.Get("Accetpt-Language")可以获得表头的语言设置。事实上Context包含了Input,Output,Request,Response等,所以一般的国际化都会涉及到Context对象。
还可以在Context.Output.Header("Access-Control-Allow-Origin","*")设置允许CORS,也就是允许获取地理位置和测量。
在获取语言设置之后,使用i18n.Locale嵌入到Controller的方式实现国际化,一般实现一个baseController,然后让其他Controller继承他,这样就可以不用总是设置国际化了。
i18n实际上有命令行可以使用,在i18n模块下有beei18n.go和sync.go两个文件是用于命令行的,使用beei18n sync命令可以使用一个本地文件创建和同步化其他的文件,例如beei18n sync sourcefile.ini other.ini other2.ini。
beego有自动化文档的功能,API doc比较简单,但是注意,一般API doc针对的是api项目。如果是设置全局的注释,可以再app.conf中的package上添加如//@APIVersion的注释。当然也可以使用代码进行设置,目前beego支持二级设置,而且只支持namespace+include模式。使用beego.NewNamespace()生成Namespace,然后使用beego.AddNamespace()。当然,需要在app.conf中添加autodoc=true开启自动文档,然后再main中import _ "beeapi/docs",这样就内置doc功能到api项目中了。使用命令bee run -gendoc=true -downdoc=true,其中-gendoc=true表示每次都自动化build文档,而-downdoc=true表示自动下载swagger文档查看器。
打开http://localhost:8888/swagger/#!/customer就可以看到文档了。
API doc一般和swagger配合使用,因为doc需要查看,而swagger是一个非常好的API doc查看器,所以beego默认使用swagger查看文档。当然了,也可以直接将swagger下载到项目下,但是这样的话需要设置WebConfig.DirectoryIndex=true,WebConfig.StaticDir[/swagger]="swagger",这样swagger就能作为静态资源导入项目了。注意,其实WebConfig.DirectoryIndex=true,WebConfig.StaticDir[]是beego中web项目设置静态文件的设置方式,而WebConfig.StaticDir[]其实跟beego.SetStaticPath()是一个道理的。
这里有一个概念需要分清楚:热升级和热编译。其中nginx是支持热升级的,这点和beego一样。
未完成