beego控制器函數(shù)

2023-11-20 18:06 更新
提示:在 v1.6 中,此文檔所涉及的 API 有重大變更,this.ServeJson() 更改為 this.ServeJSON(),this.TplNames 更改為 this.TplName。

基于 beego 的 Controller 設(shè)計(jì),只需要匿名組合 beego.Controller 就可以了,如下所示:

type xxxController struct {
    beego.Controller
}

beego.Controller 實(shí)現(xiàn)了接口 beego.ControllerInterface,beego.ControllerInterface 定義了如下函數(shù):

  • Init(ct *context.Context, childName string, app interface{})這個(gè)函數(shù)主要初始化了 Context、相應(yīng)的 Controller 名稱(chēng),模板名,初始化模板參數(shù)的容器 Data,app 即為當(dāng)前執(zhí)行的 Controller 的 reflecttype,這個(gè) app 可以用來(lái)執(zhí)行子類(lèi)的方法。
  • Prepare()這個(gè)函數(shù)主要是為了用戶擴(kuò)展用的,這個(gè)函數(shù)會(huì)在下面定義的這些 Method 方法之前執(zhí)行,用戶可以重寫(xiě)這個(gè)函數(shù)實(shí)現(xiàn)類(lèi)似用戶驗(yàn)證之類(lèi)。
  • Get()如果用戶請(qǐng)求的 HTTP Method 是 GET,那么就執(zhí)行該函數(shù),默認(rèn)是 405,用戶繼承的子 struct 中可以實(shí)現(xiàn)了該方法以處理 Get 請(qǐng)求。
  • Post()如果用戶請(qǐng)求的 HTTP Method 是 POST,那么就執(zhí)行該函數(shù),默認(rèn)是 405,用戶繼承的子 struct 中可以實(shí)現(xiàn)了該方法以處理 Post 請(qǐng)求。
  • Delete()如果用戶請(qǐng)求的 HTTP Method 是 DELETE,那么就執(zhí)行該函數(shù),默認(rèn)是 405,用戶繼承的子 struct 中可以實(shí)現(xiàn)了該方法以處理 Delete 請(qǐng)求。
  • Put()如果用戶請(qǐng)求的 HTTP Method 是 PUT,那么就執(zhí)行該函數(shù),默認(rèn)是 405,用戶繼承的子 struct 中可以實(shí)現(xiàn)了該方法以處理 Put 請(qǐng)求.
  • Head()如果用戶請(qǐng)求的 HTTP Method 是 HEAD,那么就執(zhí)行該函數(shù),默認(rèn)是 405,用戶繼承的子 struct 中可以實(shí)現(xiàn)了該方法以處理 Head 請(qǐng)求。
  • Patch()如果用戶請(qǐng)求的 HTTP Method 是 PATCH,那么就執(zhí)行該函數(shù),默認(rèn)是 405,用戶繼承的子 struct 中可以實(shí)現(xiàn)了該方法以處理 Patch 請(qǐng)求.
  • Options()如果用戶請(qǐng)求的HTTP Method是OPTIONS,那么就執(zhí)行該函數(shù),默認(rèn)是 405,用戶繼承的子 struct 中可以實(shí)現(xiàn)了該方法以處理 Options 請(qǐng)求。
  • Finish()這個(gè)函數(shù)是在執(zhí)行完相應(yīng)的 HTTP Method 方法之后執(zhí)行的,默認(rèn)是空,用戶可以在子 struct 中重寫(xiě)這個(gè)函數(shù),執(zhí)行例如數(shù)據(jù)庫(kù)關(guān)閉,清理數(shù)據(jù)之類(lèi)的工作。
  • Render() error這個(gè)函數(shù)主要用來(lái)實(shí)現(xiàn)渲染模板,如果 beego.AutoRender 為 true 的情況下才會(huì)執(zhí)行。

所以通過(guò)子 struct 的方法重寫(xiě),用戶就可以實(shí)現(xiàn)自己的邏輯,接下來(lái)我們看一個(gè)實(shí)際的例子:

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")
}

從上面的例子可以看出來(lái),通過(guò)重寫(xiě)方法可以實(shí)現(xiàn)對(duì)應(yīng) method 的邏輯,實(shí)現(xiàn) RESTful 結(jié)構(gòu)的邏輯處理。

下面我們?cè)賮?lái)看一種比較流行的架構(gòu),首先實(shí)現(xiàn)一個(gè)自己的基類(lèi) baseController,實(shí)現(xiàn)一些初始化的方法,然后其他所有的邏輯繼承自該基類(lèi):

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()
        }
}

上面定義了基類(lèi),大概是初始化了一些變量,最后有一個(gè) Init 函數(shù)中那個(gè) app 的應(yīng)用,判斷當(dāng)前運(yùn)行的 Controller 是否是 NestPreparer 實(shí)現(xiàn),如果是的話調(diào)用子類(lèi)的方法,下面我們來(lái)看一下 NestPreparer 的實(shí)現(xiàn):

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"
}

這樣我們的執(zhí)行器執(zhí)行的邏輯是這樣的,首先執(zhí)行 Prepare,這個(gè)就是 Go 語(yǔ)言中 struct 中尋找方法的順序,依次往父類(lèi)尋找。執(zhí)行 BaseAdminRouter 時(shí),查找他是否有 Prepare 方法,沒(méi)有就尋找 baseController,找到了,那么就執(zhí)行邏輯,然后在 baseController 里面的 this.AppController 即為當(dāng)前執(zhí)行的控制器 BaseAdminRouter,因?yàn)闀?huì)執(zhí)行 BaseAdminRouter.NestPrepare 方法。然后開(kāi)始執(zhí)行相應(yīng)的 Get 方法或者 Post 方法。

提前終止運(yùn)行

我們應(yīng)用中經(jīng)常會(huì)遇到這樣的情況,在 Prepare 階段進(jìn)行判斷,如果用戶認(rèn)證不通過(guò),就輸出一段信息,然后直接中止進(jìn)程,之后的 Post、Get 之類(lèi)的不再執(zhí)行,那么如何終止呢?可以使用 StopRun 來(lái)終止執(zhí)行邏輯,可以在任意的地方執(zhí)行。

type RController struct {
    beego.Controller
}

func (this *RController) Prepare() {
    this.Data["json"] = map[string]interface{}{"name": "astaxie"}
    this.ServeJSON()
    this.StopRun()
}
調(diào)用 StopRun 之后,如果你還定義了 Finish 函數(shù)就不會(huì)再執(zhí)行,如果需要釋放資源,那么請(qǐng)自己在調(diào)用 StopRun 之前手工調(diào)用 Finish 函數(shù)。

在表單中使用 PUT 方法

首先要說(shuō)明, 在 XHTML 1.x 標(biāo)準(zhǔn)中, 表單只支持 GET 或者 POST 方法. 雖然說(shuō)根據(jù)標(biāo)準(zhǔn), 你不應(yīng)該將表單提交到 PUT 方法, 但是如果你真想的話, 也很容易, 通??梢赃@么做:

首先表單本身還是使用 POST 方法提交, 但是可以在表單中添加一個(gè)隱藏字段:

<form method="post" ...>
  <input type="hidden" name="_method" value="put" />

接著在 Beego 中添加一個(gè)過(guò)濾器來(lái)判斷是否將請(qǐng)求當(dāng)做 PUT 來(lái)解析:

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)
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)