Beego Controller

controller 邏輯

controller就是處理具體的邏輯的郁妈,router將請(qǐng)求分發(fā)到指定的controlller,controller處理請(qǐng)求绍申,然后返回噩咪。
首先我們還是從源碼分析入手:

package controllers

import (
        "github.com/astaxie/beego"
)

type MainController struct {
        beego.Controller
}

func (this *MainController) Get() {
        this.Data["Website"] = "beego.me"
        this.Data["Email"] = "astaxie@gmail.com"
        this.TplName = "index.tpl"
}

上面的代碼顯示首先我們聲明了一個(gè)控制器 MainController顾彰,這個(gè)控制器里面內(nèi)嵌了 beego.Controller,這就是 Go 的嵌入方式胃碾,也就是 MainController 自動(dòng)擁有了所有 beego.Controller 的方法涨享。

beego.Controller 擁有很多方法,其中包括 Init仆百、Prepare厕隧、PostGet俄周、Delete吁讨、Head 等方法。我們可以通過重寫的方式來實(shí)現(xiàn)這些方法栈源,而我們上面的代碼就是重寫了 Get 方法挡爵。

beego 是一個(gè) RESTful 的框架,請(qǐng)求默認(rèn)是執(zhí)行對(duì)應(yīng) req.Method 的方法甚垦。例如瀏覽器的是 GET 請(qǐng)求茶鹃,那么默認(rèn)就會(huì)執(zhí)行 MainController 下的 Get 方法。這樣上面的 Get 方法就會(huì)被執(zhí)行到艰亮,就進(jìn)入了具體的邏輯處理闭翩。

里面的代碼是需要執(zhí)行的邏輯,這里只是簡(jiǎn)單的輸出數(shù)據(jù)迄埃,我們可以通過各種方式獲取數(shù)據(jù)疗韵,然后賦值到 this.Data 中,這是一個(gè)用來存儲(chǔ)輸出數(shù)據(jù)的 map侄非,可以賦值任意類型的值蕉汪,這里我們只是簡(jiǎn)單舉例輸出兩個(gè)字符串。

最后一個(gè)就是需要去渲染的模板逞怨,this.TplName 就是需要渲染的模板者疤,這里指定了 index.tpl,如果用戶不設(shè)置該參數(shù)叠赦,那么默認(rèn)會(huì)去到模板目錄的 Controller/<方法名>.tpl 查找驹马,例如上面的方法會(huì)去 maincontroller/get.tpl (文件、文件夾必須小寫)除秀。

用戶設(shè)置了模板之后系統(tǒng)會(huì)自動(dòng)的調(diào)用 Render 函數(shù)(這個(gè)函數(shù)是在 beego.Controller 中實(shí)現(xiàn)的)糯累,所以無需用戶自己來調(diào)用渲染。

當(dāng)然也可以不使用模版册踩,直接用 this.Ctx.WriteString 輸出字符串泳姐,如:

func (this *MainController) Get() {
        this.Ctx.WriteString("hello")
}

下面詳細(xì)介紹controller:

控制器介紹

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

type xxxController struct {
    beego.Controller
}

我們來看一下beego.Controller的源碼

type Controller struct {
    // context data
    Ctx  *context.Context
    Data map[interface{}]interface{}

    // route controller info
    controllerName string
    actionName     string
    methodMapping  map[string]func() //method:routertree
    gotofunc       string
    AppController  interface{}

    // template data
    TplName        string
    ViewPath       string
    Layout         string
    LayoutSections map[string]string // the key is the section name and the value is the template name
    TplPrefix      string
    TplExt         string
    EnableRender   bool

    // xsrf data
    _xsrfToken string
    XSRFExpire int
    EnableXSRF bool

    // session
    CruSession session.Store
}

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

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

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

    這個(gè)函數(shù)主要初始化了 Context允耿、相應(yīng)的 Controller 名稱借笙,模板名扒怖,初始化模板參數(shù)的容器 Data,app 即為當(dāng)前執(zhí)行的 Controller 的 reflecttype业稼,這個(gè) app 可以用來執(zhí)行子類的方法盗痒。

  • Prepare()

    這個(gè)函數(shù)主要是為了用戶擴(kuò)展用的,這個(gè)函數(shù)會(huì)在下面定義的這些 Method 方法之前執(zhí)行低散,用戶可以重寫這個(gè)函數(shù)實(shí)現(xiàn)類似用戶驗(yàn)證之類俯邓。

  • 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 中重寫這個(gè)函數(shù)舵稠,執(zhí)行例如數(shù)據(jù)庫關(guān)閉超升,清理數(shù)據(jù)之類的工作入宦。

  • Render() error

    這個(gè)函數(shù)主要用來實(shí)現(xiàn)渲染模板,如果 beego.AutoRender 為 true 的情況下才會(huì)執(zhí)行室琢。

所以通過子 struct 的方法重寫乾闰,用戶就可以實(shí)現(xiàn)自己的邏輯,接下來我們看一個(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")
}

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

Controller中數(shù)據(jù)參數(shù)處理

獲取參數(shù)

我們經(jīng)常需要獲取用戶傳遞的數(shù)據(jù)巢钓,包括 Get病苗、POST 等方式的請(qǐng)求,beego 里面會(huì)自動(dòng)解析這些數(shù)據(jù)症汹,你可以通過如下方式獲取數(shù)據(jù):

  • GetString(key string) string
  • GetStrings(key string) []string
  • GetInt(key string) (int64, error)
  • GetBool(key string) (bool, error)
  • GetFloat(key string) (float64, error)

使用例子如下:

func (c *InputController) Get()  {
    id := c.GetString("id")
    //c.GetStrings() 數(shù)組
    //c.Input().Get()
    c.Ctx.WriteString("id:" + id)
}

如果你需要的數(shù)據(jù)可能是其他類型的硫朦,例如是 int 類型而不是 int64,那么你需要這樣處理:

func (this *MainController) Post() {
    id := this.Input().Get("id")
    intid, err := strconv.Atoi(id)
}

更多其他的 request 的信息背镇,用戶可以通過 this.Ctx.Request 獲取信息咬展,關(guān)于該對(duì)象的屬性和方法參考手冊(cè) Request

直接解析到 struct

如果要把表單里的內(nèi)容賦值到一個(gè) struct 里芽世,除了用上面的方法一個(gè)一個(gè)獲取再賦值外挚赊,beego 提供了通過另外一個(gè)更便捷的方式,就是通過 struct 的字段名或 tag 與表單字段對(duì)應(yīng)直接解析到 struct济瓢。

定義 struct:

type User struct {
    Username string
    Password string
}

表單:

func (c *InputController) Get()  {
    name := c.GetSession("name")
    if name != "" {}
    c.Ctx.WriteString(`<html><form action="http://127.0.0.1:8080/input" method="post">
                                <input type="text" name="Username"/>
                                <input type="password" name="Password"/>    
                                <input type="submit" value="提交"/>   

            </form></html>`)
}

Controller 里解析:

func (c *InputController) Post()  {

    u := User{}
    if err := c.ParseForm(&u); err != nil {

    }
    c.Ctx.WriteString("Username:" + u.Username +  "password:" + u.Password)
}

注意:

  • StructTag form 的定義和 renderform方法 共用一個(gè)標(biāo)簽
  • 定義 struct 時(shí)荠割,字段名后如果有 form 這個(gè) tag,則會(huì)以把 form 表單里的 name 和 tag 的名稱一樣的字段賦值給這個(gè)字段旺矾,否則就會(huì)把 form 表單里與字段名一樣的表單內(nèi)容賦值給這個(gè)字段蔑鹦。如上面例子中,會(huì)把表單中的 username 和 age 分別賦值給 user 里的 Name 和 Age 字段箕宙,而 Email 里的內(nèi)容則會(huì)賦給 Email 這個(gè)字段嚎朽。
  • 調(diào)用 Controller ParseForm 這個(gè)方法的時(shí)候,傳入的參數(shù)必須為一個(gè) struct 的指針柬帕,否則對(duì) struct 的賦值不會(huì)成功并返回 xx must be a struct pointer 的錯(cuò)誤哟忍。
  • 如果要忽略一個(gè)字段,有兩種辦法陷寝,一是:字段名小寫開頭锅很,二是:form 標(biāo)簽的值設(shè)置為 -

獲取 Request Body 里的內(nèi)容

在 API 的開發(fā)中,我們經(jīng)常會(huì)用到 JSONXML 來作為數(shù)據(jù)交互的格式凤跑,如何在 beego 中獲取 Request Body 里的 JSON 或 XML 的數(shù)據(jù)呢爆安?

  1. 在配置文件里設(shè)置 copyrequestbody = true
  2. 在 Controller 中
func (this *ObjectController) Post() {
    var ob models.Object
    var err error
    if err = json.Unmarshal(this.Ctx.Input.RequestBody, &ob); err == nil {
        objectid := models.AddOne(ob)
        this.Data["json"] = "{\"ObjectId\":\"" + objectid + "\"}"
    } else {
        this.Data["json"] = err.Error()
    }
    this.ServeJSON()
}

文件上傳

在 beego 中你可以很容易的處理文件上傳,就是別忘記在你的 form 表單中增加這個(gè)屬性 enctype="multipart/form-data"仔引,否則你的瀏覽器不會(huì)傳輸你的上傳文件扔仓。

文件上傳之后一般是放在系統(tǒng)的內(nèi)存里面褐奥,如果文件的 size 大于設(shè)置的緩存內(nèi)存大小,那么就放在臨時(shí)文件中翘簇,默認(rèn)的緩存內(nèi)存是 64M撬码,你可以通過如下來調(diào)整這個(gè)緩存內(nèi)存大小:

beego.MaxMemory = 1<<22

或者在配置文件中通過如下設(shè)置:

maxmemory = 1<<22

Beego 提供了兩個(gè)很方便的方法來處理文件上傳:

  • GetFile(key string) (multipart.File, *multipart.FileHeader, error)

    該方法主要用于用戶讀取表單中的文件名 the_file,然后返回相應(yīng)的信息缘揪,用戶根據(jù)這些變量來處理文件上傳:過濾耍群、保存文件等义桂。

  • SaveToFile(fromfile, tofile string) error

    該方法是在 GetFile 的基礎(chǔ)上實(shí)現(xiàn)了快速保存的功能
    fromfile 是提交時(shí)候的 html 表單中的 name

<form enctype="multipart/form-data" method="post">
    <input type="file" name="uploadname" />
    <input type="submit">
</form>

保存的代碼例子如下:

func (c *FormController) Post() {
    f, h, err := c.GetFile("uploadname")
    if err != nil {
        log.Fatal("getfile err ", err)
    }
    defer f.Close()
    c.SaveToFile("uploadname", "static/upload/" + h.Filename) // 保存位置在 static/upload, 沒有文件夾要先創(chuàng)建
    
}

數(shù)據(jù)綁定

支持從用戶請(qǐng)求中直接數(shù)據(jù) bind 到指定的對(duì)象,例如請(qǐng)求地址如下

?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie
var id int
this.Ctx.Input.Bind(&id, "id")  //id ==123

var isok bool
this.Ctx.Input.Bind(&isok, "isok")  //isok ==true

var ft float64
this.Ctx.Input.Bind(&ft, "ft")  //ft ==1.2

ol := make([]int, 0, 2)
this.Ctx.Input.Bind(&ol, "ol")  //ol ==[1 2]

ul := make([]string, 0, 2)
this.Ctx.Input.Bind(&ul, "ul")  //ul ==[str array]

user struct{Name}
this.Ctx.Input.Bind(&user, "user")  //user =={Name:"astaxie"}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末找筝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子慷吊,更是在濱河造成了極大的恐慌袖裕,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溉瓶,死亡現(xiàn)場(chǎng)離奇詭異急鳄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)堰酿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門疾宏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人触创,你說我怎么就攤上這事坎藐。” “怎么了哼绑?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵岩馍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我抖韩,道長(zhǎng)蛀恩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任茂浮,我火速辦了婚禮双谆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘席揽。我一直安慰自己顽馋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布驹尼。 她就那樣靜靜地躺著趣避,像睡著了一般。 火紅的嫁衣襯著肌膚如雪新翎。 梳的紋絲不亂的頭發(fā)上程帕,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天住练,我揣著相機(jī)與錄音,去河邊找鬼愁拭。 笑死讲逛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岭埠。 我是一名探鬼主播盏混,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼惜论!你這毒婦竟也來了许赃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤馆类,失蹤者是張志新(化名)和其女友劉穎混聊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乾巧,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡句喜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沟于。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咳胃。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖旷太,靈堂內(nèi)的尸體忽然破棺而出展懈,到底是詐尸還是另有隱情,我是刑警寧澤泳秀,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布标沪,位于F島的核電站,受9級(jí)特大地震影響嗜傅,放射性物質(zhì)發(fā)生泄漏金句。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一吕嘀、第九天 我趴在偏房一處隱蔽的房頂上張望违寞。 院中可真熱鬧,春花似錦偶房、人聲如沸趁曼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挡闰。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摄悯,已是汗流浹背赞季。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奢驯,地道東北人申钩。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像瘪阁,于是被迫代替她去往敵國和親撒遣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,416評(píng)論 8 265
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理管跺,服務(wù)發(fā)現(xiàn)义黎,斷路器,智...
    卡卡羅2017閱讀 134,697評(píng)論 18 139
  • 繁華未盡 道路仍在逡巡 需要個(gè)龍頭拐杖 伴他走過人生迷茫 他已無藥可救 誰也無力回天 遠(yuǎn)看他平靜自然 又怎知他色彩...
    不老青春老男孩閱讀 315評(píng)論 4 9
  • “白雪伙菜,我們終于把日子定下來了轩缤!明年五一我們結(jié)婚。你記得來胺啡啤!” 通過冰冷的電話壶愤,白雪都能感受到閨蜜激動(dòng)澎湃的心情...
    小城市里的正能量閱讀 745評(píng)論 12 11
  • 好幾天沒有更新日記了淑倾,堅(jiān)持一件事真的不容易,何況是件不太簡(jiǎn)單的事征椒。那就不要想著堅(jiān)持了吧娇哆,把堅(jiān)持變成剛需,把壓力變成...
    黃瑤光閱讀 277評(píng)論 0 0