手记

Beego控制器

控制器逻辑

控制器就是处理具体的逻辑的,路由器将请求分发到指定的controlller,控制器处理请求,然后返回。
首先我们还是从源码分析入手:

package controllersimport (        "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"}

上面的代码显示首先我们声明了一个控制器MainController,这个控制器里面内嵌了beego.Controller,这就是Go的嵌入方式,也就是MainController自动拥有了所有beego.Controller的方法。

beego.Controller拥有很多最方法,其中包括InitPreparePostGetDeleteHead等方法。我们可以通过重写的方式来实现这些方法,而上面我们的代码就是重写了Get方法。

beego是一个RESTful的框架,请求默认是执行对应req.Method的方法。例如浏览器的是GET请求,那么默认就会执行MainController下的Get方法。这样上面的获取方法就会被执行到,就进入了具体的逻辑处理。

里面的代码是需要执行的逻辑,这里只是简单的输出数据,我们可以通过各种方式获取数据,然后赋值到this.Data中,这是一个用来存储输出数据的地图,可以赋值任意类型的值,这里我们只是简单举例输出两个字符串。

最后一个就是需要去渲染的模板,this.TplName就是需要渲染的模板,这里指定了index.tpl,如果用户不设置该参数,那么默认会去到模板目录的Controller/<方法名>.tpl查找,例如上面的方法会去maincontroller/get.tpl (文件,文件夹必须小写)

用户设置了模板之后系统会自动的调用Render函数(这个函数是在beego.Controller中实现的),所以无需用户自己来调用渲染。

当然也可以不使用模版,用直接this.Ctx.WriteString输出字符串,如:

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

下面详细介绍的控制器:

控制器介绍

基于beego的Controller设计,只需要匿名组合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实现了接口beego.ControllerInterfacebeego.ControllerInterface定义了如下函数:

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

    这个函数主要初始化了Context,相应的控制器名称,模板名,初始化模板参数的容器数据,app即为当前执行的控制器的reflecttype,这个app可以用来执行子类的方法。

  • 准备()

    这个函数主要是为了用户扩展用的,这个函数会在下面定义的这些方法之前执行,用户可以重写这个函数实现类似用户验证之类。

  • 得到()

    如果用户请求的HTTP方法是GET,那么就执行该函数,默认是405,用户继承的子结构中可以实现了该方法以处理Get请求。

  • 帖子()

    如果用户请求的HTTP方法是POST,那么就执行该函数,默认是405,用户继承的子结构中可以实现了该方法以处理Post请求。

  • 删除()

    如果用户请求的HTTP方法是DELETE,那么就执行该函数,默认是405,用户继承的子结构中可以实现了该方法以处理删除请求。

  • 放()

    如果用户请求的HTTP方法是PUT,那么就执行该函数,默认是405,用户继承的子结构中可以实现了该方法以处理Put请求。

  • 头()

    如果用户请求的HTTP方法是HEAD,那么就执行该函数,默认是405,用户继承的子结构中可以实现了该方法以处理Head请求。

  • 补丁()

    如果用户请求的HTTP方法是PATCH,那么就执行该函数,默认是405,用户继承的子结构中可以实现了该方法以处理Patch请求。

  • 选项()

    如果用户请求的HTTP方法是OPTIONS,那么就执行该函数,默认是405,用户继承的子结构中可以实现了该方法以处理选项请求。

  • 完()

    这个函数是在执行完相应的HTTP方法方法之后执行的,默认是空,用户可以在子结构中重写这个函数,执行例如数据库关闭,清理数据之类的工作。

  • 渲染()错误

    这个函数主要用来实现渲染模板,如果beego.AutoRender为真的情况下才会执行。

所以通过子结构的方法重写,用户就可以实现自己的逻辑,接下来我们看一个实际的例子:

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

从上面的例子可以看出来,通过重写方法可以实现对应方法的逻辑,实现RESTful结构的逻辑处理。

控制器中数据参数处理

获取参数

我们经常需要获取用户传递的数据,包括Get,POST等方式的请求,beego里面会自动解析这些数据,你可以通过如下方式获取数据:

  • GetString(键字符串)字符串

  • GetStrings(键字符串)[]字符串

  • GetInt(键字符串)(int64,错误)

  • GetBool(键字符串)(bool,错误)

  • GetFloat(键字符串)(float64,错误)

使用例子如下:

func (c *InputController) Get()  {    id := c.GetString("id")
    //c.GetStrings() 数组
    //c.Input().Get()
    c.Ctx.WriteString("id:" + id)
}

如果你需要的数据可能是其他类型的,例如是int类型而不是int64,那么你需要这样处理:

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

更多其他的请求的信息,用户可以通过this.Ctx.Request获取信息,关于该对象的属性和方法参考手册请求

直接解析到struct

如果要把表单里的内容赋值到一个struct里,除了用上面的方法一个一个获取再赋值外,beego提供了通过另外一个更便捷的方式,就是通过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>`)
}

控制器里解析:

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方法共用一个标签

  • 定义结时,字段名后如果有形式这个标签,则会以把形式表单里的名称和标签的名称一样的字段赋值给这个字段,否则就会把形式表单里与字段名一样的表单内容赋值给这个字段。如上面例子中,会把表单中的用户名和年龄分别赋值给用户里的名字和年龄字段,而电子邮件里的内容则会赋给电子邮件这个字段。

  • 调用Controller ParseForm这个方法的时候,传入的参数必须为一个struct的指针,否则对struct的赋值不会成功并返回xx must be a struct pointer的错误。

  • 如果要忽略一个字段,有两种办法,一是:字段名小写开头,二是:form标签的值设置为-

获取Request Body里的内容

在API的开发中,我们经常会用到JSONXML来作为数据交互的格式,如何在beego中获取请求Body里的JSON或XML的数据呢?

  1. 在配置文件里设置 copyrequestbody = true

  2. 在控制器中

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中你可以很容易的处理文件上传,就是别忘记在你的形式表单中增加这个属性enctype="multipart/form-data",否则你的浏览器不会传输你的上传文件。

文件上传之后一般是放在系统的内存里面,如果文件的大小大于设置的缓存内存大小,那么就放在临时文件中,默认的缓存内存是64M,你可以通过如下来调整这个缓存内存大小:

beego.MaxMemory = 1<<22

或者在配置文件中通过如下设置:

maxmemory = 1<<22

Beego提供了两个很方便的方法来处理文件上传:

  • GetFile(键字符串)(multipart.File,* multipart.FileHeader,error)

    该方法主要用于用户读取表单中的文件名the_file,然后返回相应的信息,用户根据这些变量来处理文件上传:过滤,保存文件等。

  • SaveToFile(fromfile,tofile string)错误

    该方法是在GetFile的基础上实现了快速保存的功能
    fromfile是提交时候的html表单中的名字

<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, 没有文件夹要先创建
    }

数据绑定

支持从用户请求中直接数据bind到指定的对象,例如请求地址如下

?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie
var id intthis.Ctx.Input.Bind(&id, "id")  //id ==123var isok boolthis.Ctx.Input.Bind(&isok, "isok")  //isok ==truevar ft float64this.Ctx.Input.Bind(&ft, "ft")  //ft ==1.2ol := 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"}



作者:若与
链接:https://www.jianshu.com/p/74e9ec5245e0

0人推荐
随时随地看视频
慕课网APP