beego控制器介紹


控制器介紹

提示:在 v1.6 中,此文檔所涉及的 API 有重大變更,this.ServeJson() 更改為 this.ServeJSON()this.TplNames 更改為 this.TplName

基於 beego 的 Controller 設計,只需要匿名組合 beego.Controller 就可以了,如下所示:

type xxxController struct { beego.Controller }

beego.Controller 實現了接口 beego.ControllerInterfacebeego.ControllerInterface 定義了如下函數:

  • Init(ct *context.Context, childName string, app interface{})

    這個函數主要初始化了 Context、相應的 Controller 名稱,模板名,初始化模板參數的容器 Dataapp 即為當前執行的 Controller 的 reflecttype,這個 app 可以用來執行子類的方法

  • Prepare()

    這個函數主要是為了用戶擴展用的,這個函數會在下面定義的這些 Method 方法之前執行,用戶可以重寫這個函數實現類似用戶驗證之類。

  • Get()

    如果用戶請求的 HTTP Method 是 GET,那么就執行該函數,默認是 405,用戶繼承的子 struct 中可以實現了該方法以處理 Get 請求。

  • Post()

    如果用戶請求的 HTTP Method 是 POST,那么就執行該函數,默認是 405,用戶繼承的子 struct 中可以實現了該方法以處理 Post 請求。

  • Delete()

    如果用戶請求的 HTTP Method 是 DELETE,那么就執行該函數,默認是 405,用戶繼承的子 struct 中可以實現了該方法以處理 Delete 請求。

  • Put()

    如果用戶請求的 HTTP Method 是 PUT,那么就執行該函數,默認是 405,用戶繼承的子 struct 中可以實現了該方法以處理 Put 請求.

  • Head()

    如果用戶請求的 HTTP Method 是 HEAD,那么就執行該函數,默認是 405,用戶繼承的子 struct 中可以實現了該方法以處理 Head 請求。

  • Patch()

    如果用戶請求的 HTTP Method 是 PATCH,那么就執行該函數,默認是 405,用戶繼承的子 struct 中可以實現了該方法以處理 Patch 請求.

  • Options()

    如果用戶請求的HTTP Method是OPTIONS,那么就執行該函數,默認是 405,用戶繼承的子 struct 中可以實現了該方法以處理 Options 請求。

  • Finish()

    這個函數是在執行完相應的 HTTP Method 方法之后執行的,默認是空,用戶可以在子 struct 中重寫這個函數,執行例如數據庫關閉,清理數據之類的工作。

  • 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.TplName = "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") }

從上面的例子可以看出來,通過重寫方法可以實現對應 method 的邏輯,實現 RESTful 結構的邏輯處理。

下面我們再來看一種比較流行的架構,首先實現一個自己的基類 baseController,實現一些初始化的方法,然后其他所有的邏輯繼承自該基類:

type NestPreparer interface { NestPrepare() } // baseRouter implemented global settings for all other routers. type baseController struct { beego.Controller i18n.Locale user models.User isLogin bool } // Prepare implemented Prepare method for baseRouter. func (this *baseController) Prepare() { // page start time this.Data["PageStartTime"] = time.Now() // Setting properties. 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() } }
/*
分析一線init方法的實現過程
c.AppController 代表接口,可以調用子類的方法
this.AppController.(NestPreparer)
判斷當前運行的 Controller 是否是 NestPreparer 實現
 
// Init generates default values of controller operations.
func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) {
	c.Layout = ""
	c.TplName = ""
	c.controllerName = controllerName
	c.actionName = actionName
	c.Ctx = ctx
	c.TplExt = "tpl"
 c.AppController = app
	c.EnableRender = true
	c.EnableXSRF = true
	c.Data = ctx.Input.Data()
	c.methodMapping = make(map[string]func())
}


*/

上面定義了基類,大概是初始化了一些變量,最后有一個 Init 函數中那個 app 的應用,判斷當前運行的 Controller 是否是 NestPreparer 實現,如果是的話調用子類的方法,下面我們來看一下 NestPreparer 的實現:

type BaseAdminRouter struct { baseController } func (this *BaseAdminRouter) NestPrepare() { if this.CheckActiveRedirect() { return } // if user isn't admin, then logout user if !this.user.IsAdmin { models.LogoutUser(&this.Controller) // write flash message this.FlashWrite("NotPermit", "true") this.Redirect("/login", 302) return } // current in admin page this.Data["IsAdmin"] = true if app, ok := this.AppController.(ModelPreparer); ok { app.ModelPrepare() return } } func (this *BaseAdminRouter) Get(){ this.TplName = "Get.tpl" } 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 來終止執行邏輯,可以在任意的地方執行。

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 方法, 但是如果你真想的話, 也很容易, 通常可以這么做:

首先表單本身還是使用 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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM