golang的web框架—beego入門簡介
原文地址:https://my.oschina.net/astaxie/blog/124040
你對beego一無所知?沒關係,這篇文件會很好的詳細介紹beego的各個方面,看這個文件之前首先確認你已經安裝了beego,如果你沒有安裝的話,請看這篇安裝指南
導航
最小應用
一個最小最簡單的應用如下程式碼所示:
package main
import (
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func(this *MainController)Get() {
this.Ctx.WriteString("hello world" )
}
funcmain() {
beego.Router("/", &MainController{})
beego.Run()
}
把上面的程式碼儲存為hello.go,然後通過命令列進行編譯並執行:
$ go build main.go
$ ./hello
這個時候你可以開啟你的瀏覽器,通過這個地址瀏覽http://127.0.0.1:8080返回“hello world”
那麼上面的程式碼到底做了些什麼呢?
1、首先我們引入了包github.com/astaxie/beego,我們知道Go語言裡面引入包會深度優先的去執行引入包的初始化(變數和init函式,更多),beego包中會初始化一個BeeAPP的應用,初始化一些引數。
2、定義Controller,這裡我們定義了一個struct為MainController,充分利用了Go語言的組合的概念,匿名包含了beego.Controller,這樣我們的MainController就擁有了beego.Controller的所有方法。
3、定義RESTFul方法,通過匿名組合之後,其實目前的MainController已經擁有了Get、Post、Delete、Put等方法,這些方法是分別用來對應使用者請求的Method函式,如果使用者發起的是POST請求,那麼就執行Post函式。所以這裡我們定義了MainController的Get方法用來重寫繼承的Get函式,這樣當用戶GET請求的時候就會執行該函式。
4、定義main函式,所有的Go應用程式和C語言一樣都是Main函式作為入口,所以我們這裡定義了我們應用的入口。
5、Router註冊路由,路由就是告訴beego,當用戶來請求的時候,該如何去呼叫相應的Controller,這裡我們註冊了請求/的時候,請求到MainController。這裡我們需要知道,Router函式的兩個引數函式,第一個是路徑,第二個是Controller的指標。
6、Run應用,最後一步就是把在1中初始化的BeeApp開啟起來,其實就是內部監聽了8080埠:Go預設情況會監聽你本機所有的IP上面的8080埠
停止服務的話,請按ctrl+c
新建專案
通過如下命令建立beego專案,首先進入gopath目錄
bee create hello
這樣就建立了一個專案hello,目錄結構如下所示
.
├── conf
│ └── app.conf
├── controllers
│ └── default.go
├── main.go
├── models
├── static
│ ├── css
│ ├── img
│ └── js
└── views
└── index.tpl
開發模式
通過bee建立的專案,beego預設情況下是開發模式。
我們可以通過如下的方式改變我們的模式:
beego.RunMode = "pro"
或者我們在conf/app.conf下面設定如下:
runmode = pro
以上兩種效果一樣。
開發模式中
-
開發模式下,如果你的目錄不存在views目錄,那麼會出現類似下面的錯誤提示:
2013/04/13 19:36:17 [W] [stat views: no such file or directory]
-
模板會自動重新載入不快取。
-
如果服務端出錯,那麼就會在瀏覽器端顯示如下類似的截圖:
路由設定
路由的主要功能是實現從請求地址到實現方法,beego中封裝了Controller,所以路由是從路徑到ControllerInterface的過程,ControllerInterface的方法有如下:
typeControllerInterface interface {
Init(ct *Context, cnstring)
Prepare()
Get()
Post()
Delete()
Put()
Head()
Patch()
Options()
Finish()
Render() error
}
這些方法beego.Controller都已經實現了,所以只要使用者定義struct的時候匿名包含就可以了。當然更靈活的方法就是使用者可以去自定義類似的方法,然後實現自己的邏輯。
使用者可以通過如下的方式進行路由設定:
beego.Router("/", &controllers.MainController{})
beego.Router("/admin", &admin.UserController{})
beego.Router("/admin/index", &admin.ArticleController{})
beego.Router("/admin/addpkg", &admin.AddController{})
為了使用者更加方便的路由設定,beego參考了sinatra的路由實現,支援多種方式的路由:
-
beego.Router("/api/:id([0-9]+)", &controllers.RController{})
自定義正則匹配 //匹配 /api/123 :id= 123 -
beego.Router("/news/:all", &controllers.RController{})
全匹配方式 //匹配 /news/path/to/123.html :all= path/to/123.html -
beego.Router("/user/:username([\w]+)", &controllers.RController{})
正則字串匹配 //匹配 /user/astaxie :username = astaxie -
beego.Router("/download/*.*", &controllers.RController{})
*匹配方式 //匹配 /download/file/api.xml :path= file/api :ext=xml -
beego.Router("/download/ceshi/*", &controllers.RController{})
*全匹配方式 //匹配 /download/ceshi/file/api.json :splat=file/api.json -
beego.Router("/int", &controllers.RController{})
int型別設定方式 //匹配 :id為int型別,框架幫你實現了正則([0-9]+) -
beego.Router("/:hi:string", &controllers.RController{})
string型別設定方式 //匹配 :hi為string型別。框架幫你實現了正則([\w]+)
靜態檔案
Go語言內部其實已經提供了http.ServeFile,通過這個函式可以實現靜態檔案的服務。beego針對這個功能進行了一層封裝,通過下面的方式進行靜態檔案註冊:
beego.SetStaticPath("/static","public")
- 第一個引數是路徑,url路徑資訊
- 第二個引數是靜態檔案目錄(相對應用所在的目錄)
beego支援多個目錄的靜態檔案註冊,使用者可以註冊如下的靜態檔案目錄:
beego.SetStaticPath("/images","images")
beego.SetStaticPath("/css","css")
beego.SetStaticPath("/js","js")
設定瞭如上的靜態目錄之後,使用者訪問/images/login/login.png,那麼就會訪問應用對應的目錄下面的images/login/login.png檔案。如果是訪問/static/img/logo.png,那麼就訪問public/img/logo.png檔案。
過濾和中介軟體
beego支援自定義過濾中介軟體,例如安全驗證,強制跳轉等
如下例子所示,驗證使用者名稱是否是admin,應用於全部的請求:
var FilterUser = func(w http.ResponseWriter, r *http.Request) {
if r.URL.User == nil || r.URL.User.Username() != "admin" {
http.Error(w, "", http.StatusUnauthorized)
}
}
beego.Filter(FilterUser)
還可以通過引數進行過濾,如果匹配引數就執行
beego.Router("/:id([0-9]+)", &admin.EditController{})
beego.FilterParam("id", func(rw http.ResponseWriter, r *http.Request) {
dosomething()
})
當然你還可以通過字首過濾
beego.FilterPrefixPath("/admin", func(rw http.ResponseWriter, r *http.Request) {
dosomething()
})
控制器設計
基於beego的Controller設計,只需要匿名組合beego.Controller就可以了,如下所示:
type xxxController struct {
beego.Controller
}
beego.Controller實現了介面beego.ControllerInterface,beego.ControllerInterface定義瞭如下函式:
-
Init(ct *Context, cn string)
這個函式主要初始化了Context、相應的Controller名稱,模板名,初始化模板引數的容器Data
-
Prepare()
這個函式主要是為了使用者擴充套件用的,這個函式會在下面定義的這些Method方法之前執行,使用者可以重寫這個函式實現類似使用者驗證之類。
-
Get()
如果使用者請求的HTTP Method是GET, 那麼就執行該函式,預設是403,使用者繼承的子struct中可以實現了該方法以處理Get請求.
-
Post()
如果使用者請求的HTTP Method是POST, 那麼就執行該函式,預設是403,使用者繼承的子struct中可以實現了該方法以處理Post請求.
-
Delete()
如果使用者請求的HTTP Method是DELETE, 那麼就執行該函式,預設是403,使用者繼承的子struct中可以實現了該方法以處理Delete請求.
-
Put()
如果使用者請求的HTTP Method是PUT, 那麼就執行該函式,預設是403,使用者繼承的子struct中可以實現了該方法以處理Put請求.
-
Head()
如果使用者請求的HTTP Method是HEAD, 那麼就執行該函式,預設是403,使用者繼承的子struct中可以實現了該方法以處理Head請求.
-
Patch()
如果使用者請求的HTTP Method是PATCH, 那麼就執行該函式,預設是403,使用者繼承的子struct中可以實現了該方法以處理Patch請求.
-
Options()
如果使用者請求的HTTP Method是OPTIONS, 那麼就執行該函式,預設是403,使用者繼承的子struct中可以實現了該方法以處理Options請求.
-
Finish()
這個函式實在執行完相應的http Method方法之後執行的,預設是空,使用者可以在子Strcut中重寫這個函式,執行例如資料庫關閉,清理資料之類的工作
-
Render() error
這個函式主要用來實現渲染模板,如果beego.AutoRender為true的情況下才會執行。
所以通過子struct的方法重寫,使用者就可以實現自己的邏輯,接下來我們看一個實際的例子:
type AddController struct {
beego.Controller
}
func (this *AddController) Prepare() {
}
func (this *AddController) Get() {
this.Data["content"] ="value"
this.Layout = "admin/layout.html"
this.TplNames = "admin/add.tpl"
}
func (this *AddController) Post() {
pkgname := this.GetString("pkgname")
content := this.GetString("content")
pk := models.GetCruPkg(pkgname)
if pk.Id == 0 {
var pp models.PkgEntity
pp.Pid = 0
pp.Pathname = pkgname
pp.Intro = pkgname
models.InsertPkg(pp)
pk = models.GetCruPkg(pkgname)
}
var at models.Article
at.Pkgid = pk.Id
at.Content = content
models.InsertArticle(at)
this.Ctx.Redirect(302, "/admin/index")
}
模板處理
模板目錄
beego中預設的模板目錄是views,使用者可以把你的模板檔案放到該目錄下,beego會自動在該目錄下的所有模板檔案進行解析並快取,開發模式下會每次重新解析,不做快取。當然使用者可以通過如下的方式改變模板的目錄:
beego.ViewsPath = "/myviewpath"
自動渲染
beego中使用者無需手動的呼叫渲染輸出模板,beego會自動的在呼叫玩相應的method方法之後呼叫Render函式,當然如果你的應用是不需要模板輸出的,那麼你可以在配置檔案或者在main.go中設定關閉自動渲染。
配置檔案配置如下:
autorender = false
main.go檔案中設定如下:
beego.AutoRender = false
模板資料
模板中的資料是通過在Controller中this.Data獲取的,所以如果你想在模板中獲取內容{{.Content}},那麼你需要在Controller中如下設定:
this.Data["Context"] = "value"
模板名稱
beego採用了Go語言內建的模板引擎,所有模板的語法和Go的一模一樣,至於如何寫模板檔案,詳細的請參考模板教程。
使用者通過在Controller的對應方法中設定相應的模板名稱,beego會自動的在viewpath目錄下查詢該檔案並渲染,例如下面的設定,beego會在admin下面找add.tpl檔案進行渲染:
this.TplNames = "admin/add.tpl"
我們看到上面的模板字尾名是tpl,beego預設情況下支援tpl和html字尾名的模板檔案,如果你的字尾名不是這兩種,請進行如下設定:
beego.AddTemplateExt("你檔案的字尾名")
當你設定了自動渲染,然後在你的Controller中沒有設定任何的TplNames,那麼beego會自動設定你的模板檔案如下:
c.TplNames = c.ChildName + "/" + c.Ctx.Request.Method + "." + c.TplExt
也就是你對應的Controller名字+請求方法名.模板字尾,也就是如果你的Controller名是AddController,請求方法是POST,預設的檔案字尾是tpl,那麼就會預設請求/viewpath/AddController/POST.tpl檔案。
lauout設計
beego支援layout設計,例如你在管理系統中,其實整個的管理介面是固定的,支會變化中間的部分,那麼你可以通過如下的設定:
this.Layout = "admin/layout.html"
this.TplNames = "admin/add.tpl"
在layout.html中你必須設定如下的變數:
{{.LayoutContent}}
beego就會首先解析TplNames指定的檔案,獲取內容賦值給LayoutContent,然後最後渲染layout.html檔案。
目前採用首先把目錄下所有的檔案進行快取,所以使用者還可以通過類似這樣的方式實現layout:
{{template "header.html"}}
處理邏輯
{{template "footer.html"}}
模板函式
beego支援使用者定義模板函式,但是必須在beego.Run()呼叫之前,設定如下:
func hello(instring)(outstring){
out = in + "world"
return
}
beego.AddFuncMap("hi",hello)
定義之後你就可以在模板中這樣使用了:
{{.Content | hi}}
目前beego內建的模板函式有如下:
-
markdown
實現了把markdown文字轉化為html資訊,使用方法{{markdown .Content}}
-
dateformat
實現了時間的格式化,返回字串,使用方法{{dateformat .Time "2006-01-02T15:04:05Z07:00"}}
-
date
實現了類似PHP的date函式,可以很方便的根據字串返回時間,使用方法{{date .T "Y-m-d H:i:s"}}
-
compare
實現了比較兩個物件的比較,如果相同返回true,否者false,使用方法{{compare .A .B}}
-
substr
實現了字串的擷取,支援中文擷取的完美擷取,使用方法{{substr .Str 0 30}}
-
html2str
實現了把html轉化為字串,剔除一些script、css之類的元素,返回純文字資訊,使用方法{{html2str .Htmlinfo}}
-
str2html
實現了把相應的字串當作HTML來輸出,不轉義,使用方法{{str2html .Strhtml}}
-
htmlquote
實現了基本的html字元轉義,使用方法{{htmlquote .quote}}
-
htmlunquote
實現了基本的反轉移字元,使用方法{{htmlunquote .unquote}}
request處理
我們經常需要獲取使用者傳遞的資料,包括Get、POST等方式的請求,beego裡面會自動解析這些資料,你可以通過如下方式獲取資料
- GetString(key string) string
- GetInt(key string) (int64, error)
- GetBool(key string) (bool, error)
使用例子如下:
func (this *MainController) Post() {
jsoninfo := this.GetString("jsoninfo")
if jsoninfo == "" {
this.Ctx.WriteString("jsoninfo is empty")
return
}
}
如果你需要的資料可能是其他型別的,例如是int型別而不是int64,那麼你需要這樣處理:
func (this *MainController) Post() {
id := this.Input().Get("id")
intid, err := strconv.Atoi(id)
}
更多其他的request的資訊,使用者可以通過this.Ctx.Request獲取資訊,關於該物件的屬性和方法參考手冊Request
檔案上傳
在beego中你可以很容易的處理檔案上傳,就是別忘記在你的form表單中增加這個屬性enctype="multipart/form-data",否者你的瀏覽器不會傳輸你的上傳檔案。
檔案上傳之後一般是放在系統的記憶體裡面,如果檔案的size大於設定的快取記憶體大小,那麼就放在臨時檔案中,預設的快取記憶體是64M,你可以通過如下來調整這個快取記憶體大小:
beego.MaxMemory = 1<<22
或者在配置檔案中通過如下設定
maxmemory = 1<<22
beego提供了兩個很方便的方法來處理檔案上傳:
-
GetFile(key string) (multipart.File, *multipart.FileHeader, error)
該方法主要用於使用者讀取表單中的檔名the_file,然後返回相應的資訊,使用者根據這些變數來處理檔案上傳:過濾、儲存檔案等。
-
SaveToFile(fromfile, tofile string) error
該方法是在GetFile的基礎上實現了快速儲存的功能
儲存的程式碼例子如下:
func (this *MainController) Post() {
this.SaveToFile("the_file","/var/www/uploads/uploaded_file.txt"")
}
JSON和XML輸出
beego當初設計的時候就考慮了API功能的設計,而我們在設計API的時候經常是輸出JSON或者XML資料,那麼beego提供了這樣的方式直接輸出:
JSON資料直接輸出,設定content-type為application/json:
func (this *AddController) Get() {
mystruct := { ... }
this.Data["json"] = &mystruct
this.ServeJson()
}
XML資料直接輸出,設定content-type為application/xml:
func (this *AddController) Get() {
mystruct := { ... }
this.Data["xml"]=&mystruct
this.ServeXml()
}
跳轉和錯誤
我們在做Web開發的時候,經常會遇到頁面調整和錯誤處理,beego這這方面也進行了考慮,通過Redirect方法來進行跳轉:
func (this *AddController) Get() {
this.Redirect("/", 302)
}
@todo 錯誤處理還需要後期改進
response處理
response可能會有集中情況:
-
模板輸出
模板輸出上面模板介紹裡面已經介紹,beego會在執行完相應的Controller裡面的對應的Method之後輸出到模板。
-
跳轉
上一節介紹的跳轉就是我們經常用到的頁面之間的跳轉
-
字串輸出
有些時候我們只是想輸出相應的一個字串,那麼我們可以通過如下的程式碼實現
this.Ctx.WriteString("ok")
Sessions
beego內建了session模組,目前session模組支援的後端引擎包括memory、file、mysql、redis四中,使用者也可以根據相應的interface實現自己的引擎。
beego中使用session相當方便,只要在main入口函式中設定如下:
beego.SessionOn = true
或者通過配置檔案配置如下:
sessionon = true
通過這種方式就可以開啟session,如何使用session,請看下面的例子:
func (this *MainController) Get() {
v := this.GetSession("asta")
if v == nil {
this.SetSession("asta", int(1))
this.Data["num"] = 0
} else {
this.SetSession("asta", v.(int)+1)
this.Data["num"] = v.(int)
}
this.TplNames = "index.tpl"
}
上面的例子中我們知道session有幾個方便的方法:
- SetSession(name string, value interface{})
- GetSession(name string) interface{}
- DelSession(name string)
session操作主要有設定session、獲取session、刪除session
當然你要可以通過下面的方式自己控制相應的邏輯這些邏輯:
sess:=this.StartSession()
defer sess.SessionRelease()
sess物件具有如下方法:
- sess.Set()
- sess.Get()
- sess.Delete()
- sess.SessionID()
但是我還是建議大家採用SetSession、GetSession、DelSession三個方法來操作,避免自己在操作的過程中資源沒釋放的問題。
關於Session模組使用中的一些引數設定:
-
SessionOn
設定是否開啟Session,預設是false,配置檔案對應的引數名:sessionon
-
SessionProvider
設定Session的引擎,預設是memory,目前支援還有file、mysql、redis等,配置檔案對應的引數名:sessionprovider
-
SessionName
設定cookies的名字,Session預設是儲存在使用者的瀏覽器cookies裡面的,預設名是beegosessionID,配置檔案對應的引數名是:sessionname
-
SessionGCMaxLifetime
設定Session過期的時間,預設值是3600秒,配置檔案對應的引數:sessiongcmaxlifetime
-
SessionSavePath
設定對應file、mysql、redis引擎的儲存路徑或者連結地址,預設值是空,配置檔案對應的引數:sessionsavepath
當SessionProvider為file時,SessionSavePath是隻儲存檔案的目錄,如下所示:
beego.SessionProvider = "file"
beego.SessionSavePath = "./tmp"
當SessionProvider為mysql時,SessionSavePath是連結地址,採用go-sql-driver,如下所示:
beego.SessionProvider = "mysql"
beego.SessionSavePath = "username:[email protected](address)/dbname?param=value"
當SessionProvider為redis時,SessionSavePath是redis的連結地址,採用了redigo,如下所示:
beego.SessionProvider = "redis"
beego.SessionSavePath = "127.0.0.1:6379"
Cache設定
beego內建了一個cache模組,實現了類似memcache的功能,快取資料在記憶體中,主要的使用方法如下:
var (
urllist *beego.BeeCache
)
funcinit() {
urllist = beego.NewBeeCache()
urllist.Every = 0 //不過期
urllist.Start()
}
func(this *ShortController)Post() {
var result ShortResult
longurl := this.Input().Get("longurl")
beego.Info(longurl)
result.UrlLong = longurl
urlmd5 := models.GetMD5(longurl)
beego.Info(urlmd5)
if urllist.IsExist(urlmd5) {
result.UrlShort = urllist.Get(urlmd5).(string)
} else {
result.UrlShort = models.Generate()
err := urllist.Put(urlmd5, result.UrlShort, 0)
if err != nil {
beego.Info(err)
}
err = urllist.Put(result.UrlShort, longurl, 0)
if err != nil {
beego.Info(err)
}
}
this.Data["json"] = result
this.ServeJson()
}
上面這個例子演示瞭如何使用beego的Cache模組,主要是通過beego.NewBeeCache初始化一個物件,然後設定過期時間,開啟過期檢測,在業務邏輯中就可以通過如下的介面進行增刪改的操作:
- Get(name string) interface{}
- Put(name string, value interface{}, expired int) error
- Delete(name string) (ok bool, err error)
- IsExist(name string) bool
安全的Map
我們知道在Go語言裡面map是非執行緒安全的,詳細的atomic_maps。但是我們在平常的業務中經常需要用到執行緒安全的map,特別是在goroutine的情況下,所以beego內建了一個簡單的執行緒安全的map:
bm := NewBeeMap()
if !bm.Set("astaxie", 1) {
t.Error("set Error")
}
if !bm.Check("astaxie") {
t.Error("check err")
}
if v := bm.Get("astaxie"); v.(int) != 1 {
t.Error("get err")
}
bm.Delete("astaxie")
if bm.Check("astaxie") {
t.Error("delete err")
}
上面演示瞭如何使用執行緒安全的Map,主要的介面有:
- Get(k interface{}) interface{}
- Set(k interface{}, v interface{}) bool
- Check(k interface{}) bool
- Delete(k interface{})
日誌處理
beego預設有一個初始化的BeeLogger物件輸出內容到stdout中,你可以通過如下的方式設定自己的輸出:
beego.SetLogger(*log.Logger)
只要你的輸出符合*log.Logger就可以,例如輸出到檔案:
fd,err := os.OpenFile("/var/log/beeapp/beeapp.log", os.O_RDWR|os.O_APPEND, 0644)
if err != nil {
beego.Critical("openfile beeapp.log:", err)
return
}
lg := log.New(fd, "", log.Ldate|log.Ltime)
beego.SetLogger(lg)
不同級別的log日誌函式
- Trace(v ...interface{})
- Debug(v ...interface{})
- Info(v ...interface{})
- Warn(v ...interface{})
- Error(v ...interface{})
- Critical(v ...interface{})
你可以通過下面的方式設定不同的日誌分級:
beego.SetLevel(beego.LevelError)
當你程式碼中有很多日誌輸出之後,如果想上線,但是你不想輸出Trace、Debug、Info等資訊,那麼你可以設定如下:
beego.SetLevel(beego.LevelWarning)
這樣的話就不會輸出小於這個level的日誌,日誌的排序如下:
LevelTrace、LevelDebug、LevelInfo、LevelWarning、 LevelError、LevelCritical
使用者可以根據不同的級別輸出不同的錯誤資訊,如下例子所示:
Examples of log messages
-
Trace
- "Entered parse function validation block"
- "Validation: entered second 'if'"
- "Dictionary 'Dict' is empty. Using default value"
-
Debug
- "Web page requested: http://somesite.com Params='...'"
- "Response generated. Response size: 10000. Sending."
- "New file received. Type:PNG Size:20000"
-
Info
- "Web server restarted"
- "Hourly statistics: Requested pages: 12345 Errors: 123 ..."
- "Service paused. Waiting for 'resume' call"
-
Warn
- "Cache corrupted for file='test.file'. Reading from back-end"
- "Database 192.168.0.7/DB not responding. Using backup 192.168.0.8/DB"
- "No response from statistics server. Statistics not sent"
-
Error
- "Internal error. Cannot process request #12345 Error:...."
- "Cannot perform login: credentials DB not responding"
-
Critical
- "Critical panic received: .... Shutting down"
- "Fatal error: ... App is shutting down to prevent data corruption or loss"
Example
funcinternalCalculationFunc(x, y int)(result int, err error) {
beego.Debug("calculating z. x:",x," y:",y)
z := y
switch {
case x == 3 :
beego.Trace("x == 3")
panic("Failure.")
case y == 1 :
beego.Trace("y == 1")
return 0, errors.New("Error!")
case y == 2 :
beego.Trace("y == 2")
z = x
default :
beego.Trace("default")
z += x
}
retVal := z-3
beego.Debug("Returning ", retVal)
return retVal, nil
}
funcprocessInput(input inputData) {
defer func() {
if r := recover(); r != nil {
beego.Error("Unexpected error occurred: ", r)
outputs <- outputData{result : 0, error : true}
}
}()
beego.Info("Received input signal. x:",input.x," y:", input.y)
res, err := internalCalculationFunc(input.x, input.y)
if err != nil {
beego.Warn("Error in calculation:", err.Error())
}
beego.Info("Returning result: ",res," error: ",err)
outputs <- outputData{result : res, error : err != nil}
}
funcmain() {
inputs = make(chan inputData)
outputs = make(chan outputData)
criticalChan = make(chan int)
beego.Info("App started.")
go consumeResults(outputs)
beego.Info("Started receiving results.")
go generateInputs(inputs)
beego.Info("Started sending signals.")
for {
select {
case input := <- inputs:
processInput(input)
case <- criticalChan:
beego.Critical("Caught value from criticalChan: Go shut down.")
panic("Shut down due to critical fault.")
}
}
}
配置管理
beego支援解析ini檔案, beego預設會解析當前應用下的conf/app.conf檔案
通過這個檔案你可以初始化很多beego的預設引數
appname = beepkg
httpaddr = "127.0.0.1"
httpport = 9090
runmode ="dev"
autorender = false
autorecover = false
viewspath = "myview"
上面這些引數會替換beego預設的一些引數。
你可以在配置檔案中配置應用需要用的一些配置資訊,例如下面所示的資料庫資訊:
mysqluser = "root"
mysqlpass = "rootpass"
mysqlurls = "127.0.0.1"
mysqldb = "beego"
那麼你就可以通過如下的方式獲取設定的配置資訊:
beego.AppConfig.String("mysqluser")
beego.AppConfig.String("mysqlpass")
beego.AppConfig.String("mysqlurls")
beego.AppConfig.String("mysqldb")
AppConfig支援如下方法
- Bool(key string) (bool, error)
- Int(key string) (int, error)
- Int64(key string) (int64, error)
- Float(key string) (float64, error)
- String(key string) string
系統預設引數
beego中帶有很多可配置的引數,我們來一一認識一下它們,這樣有利於我們在接下來的beego開發中可以充分的發揮他們的作用:
-
BeeApp
beego預設啟動的一個應用器入口,在應用import beego的時候,在init中已經初始化的。
-
AppConfig
beego的配置檔案解析之後的物件,也是在init的時候初始化的,裡面儲存有解析conf/app.conf下面所有的引數資料
-
HttpAddr
應用監聽地址,預設為空,監聽所有的網絡卡IP
-
HttpPort
應用監聽埠,預設為8080
-
AppName
應用名稱,預設是beego
-
RunMode
應用的模式,預設是dev,為開發模式,在開發模式下出錯會提示友好的出錯頁面,如前面錯誤描述中所述。
-
AutoRender
是否模板自動渲染,預設值為true,對於API型別的應用,應用需要把該選項設定為false,不需要渲染模板。
-
RecoverPanic
是否異常恢復,預設值為true,即當應用出現異常的情況,通過recover恢復回來,而不會導致應用異常退出。
-
PprofOn
是否啟用pprof,預設是false,當開啟之後,使用者可以通過如下地址檢視相應的goroutine執行情況
/debug/pprof /debug/pprof/cmdline /debug/pprof/profile /debug/pprof/symbol
關於pprof的資訊,請參考官方的描述pprof
-
ViewsPath
模板路徑,預設值是views
-
SessionOn
session是否開啟,預設是false
-
SessionProvider
session的引擎,預設是memory
-
SessionName
存在客戶端的cookie名稱,預設值是beegosessionID
-
SessionGCMaxLifetime
session過期時間,預設值是3600秒
-
SessionSavePath
session儲存路徑,預設是空
-
UseFcgi
是否啟用fastcgi,預設是false
-
MaxMemory
檔案上傳預設記憶體快取大小,預設值是1 << 26(64M)
第三方應用整合
beego支援第三方應用的整合,使用者可以自定義http.Handler,使用者可以通過如下方式進行註冊路由:
beego.RouterHandler("/chat/:info(.*)", sockjshandler)
sockjshandler實現了介面http.Handler。
目前在beego的example中有支援sockjs的chat例子,示例程式碼如下:
package main
import (
"fmt"
"github.com/astaxie/beego"
"github.com/fzzy/sockjs-go/sockjs"
"strings"
)
var users *sockjs.SessionPool = sockjs.NewSessionPool()
funcchatHandler(s sockjs.Session) {
users.Add(s)
defer users.Remove(s)
for {
m := s.Receive()
if m == nil {
break
}
fullAddr := s.Info().RemoteAddr
addr := fullAddr[:strings.LastIndex(fullAddr, ":")]
m = []byte(fmt.Sprintf("%s: %s", addr, m))
users.Broadcast(m)
}
}
type MainController struct {
beego.Controller
}
func(m *MainController)Get() {
m.TplNames = "index.html"
}
funcmain() {
conf := sockjs.NewConfig()
sockjshandler := sockjs.NewHandler("/chat", chatHandler, conf)
beego.Router("/", &MainController{})
beego.RouterHandler("/chat/:info(.*)", sockjshandler)
beego.Run()
}
通過上面的程式碼很簡單的實現了一個多人的聊天室。上面這個只是一個sockjs的例子,我想通過大家自定義http.Handler,可以有很多種方式來進行擴充套件beego應用。
部署編譯應用
Go語言的應用最後編譯之後是一個二進位制檔案,你只需要copy這個應用到伺服器上,執行起來就行。beego由於帶有幾個靜態檔案、配置檔案、模板檔案三個目錄,所以使用者部署的時候需要同時copy這三個目錄到相應的部署應用之下,下面以我實際的應用部署為例:
$ mkdir /opt/app/beepkg
$ cp beepkg /opt/app/beepkg
$ cp -fr views /opt/app/beepkg
$ cp -fr static /opt/app/beepkg
$ cp -fr conf /opt/app/beepkg
這樣在/opt/app/beepkg目錄下面就會顯示如下的目錄結構:
.
├── conf
│ ├── app.conf
├── static
│ ├── css
│ ├── img
│ └── js
└── views
└── index.tpl
├── beepkg
這樣我們就已經把我們需要的應用搬到伺服器了,那麼接下來就可以開始部署了,我現在伺服器端用兩種方式來run,
-
Supervisord
-
nohup方式
nohup ./beepkg &
個人比較推薦第一種方式,可以很好的管理起來應用