beego——控制器函数
基于beego的Controller设计,只需要匿名组合beego.Controller就可以,如下所示:
1 2 3 | type xxxController struct { beego.Controller } |
beego.Controller实现了接口beego.ControllerInterface,其源码定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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的实现。
示例三:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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:
1 2 3 4 5 6 7 8 9 | 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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
2017-12-14 MySQL——并发控制(锁)
2017-12-14 MySQL——多版本并发控制
2017-12-14 MySQL——事务
2017-12-14 Redis的特性
2017-12-14 Docker与虚拟化