1. 程式人生 > >beego——控制器函式

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)