beego——控制器函式
基於beego的Controller設計,只需要匿名組合beego.Controller就可以,如下所示:
type xxxController struct { beego.Controller }
beego.Controller實現了介面beego.ControllerInterface,其原始碼定義如下:
// ControllerInterface is an interface to uniform all controller handler. type ControllerInterface interface { Init(ct *context.Context, controllerName, actionName string, app interface{}) Prepare() Get() Post() Delete() Put() Head() Patch() Options() Finish() Render() error XSRFToken() string CheckXSRFCookie() bool HandlerFunc(fn string) bool URLMapping() }
部分解釋:
(1)Init(ct *context.Context, childName string, app interface{})
這個函式主要初始化了Context、相應的Controller名稱、模板名、初始化模板引數的容器Data,
app即為當前執行的Controller的reflecttype,這個app可以用來執行子類的方法。
(2)Prepare()
這個函式主要是為了使用者擴充套件用的,這個函式會在下面定義的這些Method方法之前執行,使用者重寫這個函式實現類似使用者驗證之類。
(3)Get()、Post()、Delete()、Put()、Head()、Patch()、Options()
這些函式都是使用者請求的方法,使用者請求的HTTP Method是什麼就執行什麼函式,預設是405,使用者繼承的子struct中可以實現該方法以處理相對應的請求。
(4)Finish()
這個函式是在執行完相應的HTTP Method方法之後執行的,預設是空,使用者可以在子struct中重寫這個函式,例如關閉資料庫、清理資料之類的工作。
(5)Render() error
這個函式主要用來實現渲染模板,如果beego.AutoRender為true的情況下才會執行。
通過重寫struct的方法,我們就可以實現自己的邏輯。
示例1:
package control import ( "github.com/astaxie/beego" ) //重寫struct,定義自己的邏輯 type AddController struct { beego.Controller } //定義prepare方法 func (this *AddController) Prepare() { } //定義Post方法 func (this *AddController) Post() { pkgname := this.GetString("pkgname") content := this.GetString("content") pk := models.GetCruPkg(pkgname) if pk.Id == 0 { var pp model.PkgEntitiy pp.Pid = 0 pp.Pathname = pkgname pp.Intro = pkgname model.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.Router("/user", &controllers.AddController{})
下面展示一種常用的架構,首先實現一個自己的基類,實現一些初始化方法,然後,其它所有的邏輯繼承自該基類。
示例2:
type NestPreparer interface { NestPrepare() } // baseRouter為所有其他路由器實現全域性設定。 type baseController struct { beego.Controller i18n.Locale user models.User isLogin bool } //定義prepare方法 func (this *baseController) Prepare() { // 頁面開始時間 this.Data["PageStartTime"] = time.Now() //引數配置 this.Data["AppDescription"] = utils.AppDescription this.Data["AppKeywords"] = utils.AppKeywords this.Data["AppName"] = utils.AppName this.Data["AppVer"] = utils.AppVer this.Data["AppUrl"] = utils.AppUrl this.Data["AppLogo"] = utils.AppLogo this.Data["AvatarURL"] = utils.AvatarURL this.Data["IsProMode"] = utils.IsProMode if app, ok := this.AppController.(NestPreparer); ok { app.NestPrepare() } } //this.Data是一個用來儲存輸出資料的map,可以賦值任意型別的值。
上面定義了基類,大概是初始化了一些變數,最後有一個init函式中那個app應用,
判斷當前執行的Controller是否是NestPreparer實現,如果是的話就呼叫子類的方法。下面看一下NestPreparer的實現。
示例三:
type BaseAdminRouter struct { baseController } //定義方法 func (this *BaseAdminRouter) NestPrepare() { if this.CheckActiveRedirect() { return } //當前使用者不是admin,退出 if !this.user.IsAdmin { models.LogoutUser(&this.Controller) // 寫入flash資訊 this.FlashWrite("NotPermit", "true") //跳轉 this.Redirect("/login", 302) return } // 當前管理頁面 this.Data["IsAdmin"] = true if app, ok := this.AppController.(ModelPreparer); ok { app.ModelPrepare() return } } //定義get方法 func (this *BaseAdminRouter) Get() { this.TplName = "Get.tpl" } //定義post方法 func (this *BaseAdminRouter) Post() { this.TplName = "Post.tpl" }
這樣我們的執行器執行的邏輯是這樣的,首先執行Prepare,這個就是Go語言中struct中尋找方法的順序,依次往父類尋找。
執行BaseAdminRouter時,查詢他是否有prepare方法,沒有就尋找baseController,找到了,那麼就執行邏輯,
然後在baseController裡面的this.AppController,即為當前執行的控制器BaseAdminRouter,因為會執行BaseAdminRouter.NestPrepare方法。
然後就開始執行相應的Get方法或者Post方法。
提前終止執行
我們應用中經常會遇到這樣的情況,在Prepare階段進行判斷,如果使用者認證不通過,就輸出一段資訊,然後直接終止程序,
之後的Post、Get之類的不再執行,那麼如何終止呢?可以使用StopRun來終止執行邏輯,可以在任意的地方執行。
示例3:
type RController struct { beego.Controller } func (this *RController) Prepare() { this.Data["json"] = map[string]interface{}{"name": "astaxie"} this.ServeJSON() this.StopRun() }
呼叫StopRun之後,如果你還定義了Finish函式就不會再執行,如果需要釋放資源,那麼請自己再呼叫StopRun之前手工呼叫Finish函式。
在表單中使用PUT方法
首先要說明,在XHTML 1.x標準中,表單只支援GET或者POST方法。
雖然說根據標準庫,你不應該將表單提交到PUT方法,但是如果你真想的話,也很容易,通常可以這麼做:
(1)首先表單本身還是使用POST方法提交,但是可以在表單中新增一個隱匿欄位。
<form method="post" ...> <input type="hidden" name="_method" value="put" />
接著在Beego中新增一個過濾器來判斷是否將請求當作PUT來解析。
var FilterMethod = func(ctx *context.Context) {
if ctx.BeegoInput.Query("_method")!="" && ctx.BeegoInput.IsPost(){
ctx.Request.Method = ctx.BeegoInput.Query("_method")
}
}
beego.InsertFilter("*", beego.BeforeRouter, FilterMethod)