ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

golang beego后端开发框架(二):配置、路由和控制器

2022-04-11 11:34:51  阅读:251  来源: 互联网

标签:web beego string golang key Data 路由


1. beego参数配置

beego目前支持INI、XML、JSON、YAML格式的配置文件解析,但是默认采用了INI格式解析,用户可以通过简单的配置就可以获得很大的灵活性

 

1.1 默认配置解析

neego会默认解析当前应用下的 conf/app.conf 文件

当我们使用 bee new 命令新建一个项目时,app.conf 文件默认参数只有以下几个:

appname = pro01  // appname随便改
httpport = 8080  // 服务端口
runmode = dev  // 开发模式

 

这里面可写的参数不是任意的,都会被维护在结构体 beego/server/web#Config 中

beego的参数主要包含了以下这些 https://godoc.org/github.com/beego/beego#pkg-constants

 

可以在配置文件中配置应用需要的配置信息,比如mysql的连接信息

mysqluser =  "root"
mysqlpass =  "rootpass"

 

需要这些配置信息时,只需要使用AppConfig的一系列方法就可以取到数据

user,err := beego.AppConfig.String( "mysqluser" )

 

AppConfig支持的方法如下:

Set(key, val string) error
String(key string) string
Strings(key string) []string
Int(key string) (int, error)
Int64(key string) (int64, error)
Bool(key string) (bool, error)
Float(key string) (float64, error)
DefaultString(key string, defaultVal string) string
DefaultStrings(key string, defaultVal []string)
DefaultInt(key string, defaultVal int) int
DefaultInt64(key string, defaultVal int64) int64
DefaultBool(key string, defaultVal bool) bool
DefaultFloat(key string, defaultVal float64) float64
DIY(key string) ( interface {}, error)
GetSection(section string) ( map [string]string, error)
SaveConfigFile(filename string) error

 

1.2 不同级别的配置

在配置文件中里面支持section,可以有不同的 Runmode 的配置,默认优先读取 runmode 下的配置信息,例如下面的配置文件:

appname = beepkg
httpport = 9090
runmode = "dev"

[dev]
httpport = 8080
[prod]
httpport = 8088
[test]
httpport = 8888

  

上面的配置文件就是在不同 runmode 下解析不同的配置

在dev模式下,服务端口是8080,在prod模式下是8088

读取不同模式下配置参数的方法是 模式::配置参数名 ,比如:

beego.AppConfig.String( "dev::mysqluser" )

 

1.3 多个配置文件

INI格式支持include方式引用多个配置文件例如下面的例子

app.conf

appname = pro01
httpport = 8080
runmode = dev

include  "app2.conf"

 

app2.conf

runmode = "dev"
autorender = false
recoverpanic = false
viewspath =  "myview"

[dev]
httpport = 8080
[prod]
httpport = 8088
[test]
httpport = 8888

  

1.4 支持环境变量配置

配置文件解析支持从环境变量中获取配置,配置项格式 ${环境变量}

例如下面的配置中优先使用环境变量中配置的 runmode 和 httpport

如果有配置环境变量 ProRunMode 则优先使用该环境变量值;如果不存在或者为空,则使用 “dev” 作为 runmode

runmode  =  "${ProRunMode||dev}"
httpport =  "${ProPort||9090}"

  

1.5 系统默认参数

参数配置 - beego: 简约 & 强大并存的 Go 应用框架

 

2. beego路由设置

beego路由存在三种方式:固定路由、正则路由、自动路由

 

2.1 固定路由

固定路由是最常见的路由方式,一个固定的路由地址加一个控制器模式

固定路由示例如下所示:

beego.Router( "/" , &controllers.MainController{})
beego.Router( "/admin" , &admin.UserController{})
beego.Router( "/admin/index" , &admin.ArticleController{})
beego.Router( "/admin/addpkg" , &admin.AddController{})

 

2.2 正则路由

形如下面这种路由设置

http://localhost:8080/api/?:id
http://localhost:8080/api/:id

 

这两个路由的默认匹配都是 /api/123类型的,但是第一个路由 /api/可以正常匹配,第二个就会匹配失败

可以在Controller中通过如下方式获取上面的变量,记得添加冒号!

c.Ctx.Input.Param(":id")

 

2.3 自动路由

自动路由需要先把需要路由的控制器注册到自动路由中

beego.AutoRouter(&controllers.ObjectController{})

 

那么beego就会通过反射来获取该结构体的所有实现方法,就可以通过下面的方式访问到对应的方法

两个前缀分别为controller的名字和方法名 /:controller/:method

/object/login   调用 ObjectController 中的 Login 方法
/object/logout  调用 ObjectController 中的 Logout 方法

 

除了两个前缀的匹配外,剩下的 URL beego会自动解析为参数,保存在 this.Ctx.Input.Params中

/object/blog/2013/09/12  调用 ObjectController 中的 Blog 方法,参数如下: map [0:2013 1:09 2:12]

 

现在已经可以通过自动识别出来下面类似的所有 url,都会把请求分发到 controller 的 simple 方法

后缀名可以通过 this.Ctx.Input.Param(":ext") 来获取

/controller/simple
/controller/simple.html
/controller/simple.json
/controller/simple.xml

 

2.4 自定义方法和RESTful规则

如果用户期望使用自定义函数名,那么可以使用如下方式:

beego.Router( "/" ,&IndexController{}, "*:Index" )

 

使用第三个参数,第三个参数就是用来设置对应method到函数名,定义如下:

  • * 表示任意的method都执行该函数
  • 使用httpmethod:funcname格式来展示
  • 多个不同的格式使用 ; 分隔
  • 多个method对应同一个funcname,method之间采用 , 分隔

比如下面的例子中,我们要为同一个URL针对不同类型的请求,绑定不同的控制器

beego.Router( "/api/food" ,&RestController{}, "get:ListFood" )
beego.Router( "/api/food" ,&RestController{}, "post:CreateFood" )
beego.Router( "/api/food" ,&RestController{}, "put:UpdateFood" )
beego.Router( "/api/food" ,&RestController{}, "delete:DeleteFood" )

 

在使用时不推荐采用 ;分隔的方式来加入多个method:func,会使得代码可读性不强

在绑定时支持的http方法包含以下几类,都要小写就行

  • * 所有请求
  • GET
  • POST
  • PUT
  • DELETE
  • PATCH
  • OPTIONS
  • HEAD

如果同时存在 * 和具体的HTTP方法对应的函数,那么优先执行HTTP方法对应的函数

 

2.5 namespace

namespace就是需要优先解析的一个URL参数

比如在下面这个例子中,通过NewNamespace方法定义了一个 /v1 namespace

在namesapce中首先通过NSCond()方法来判断是不是满足该 namespace的执行条件

然后后续通过NS+HTTP method格式的方法绑定了很多控制器

最后通过 beego.AddNamespace(ns) 将这个namesapce注册到路由中

//初始化 namespace
ns :=
web.NewNamespace( "/v1" ,
    web.NSCond( func (ctx *context.Context) bool {
        if ctx.Input.Domain() ==  "api.beego.vip" {
            return true
        }
        return false
    }),
    web.NSBefore(auth),
    web.NSGet( "/notallowed" ,  func (ctx *context.Context) {
        ctx.Output.Body([]byte( "notAllowed" ))
    }),
    web.NSRouter( "/version" , &AdminController{},  "get:ShowAPIVersion" ),
    web.NSRouter( "/changepassword" , &UserController{}),
    web.NSNamespace( "/shop" ,
        web.NSBefore(sentry),
        web.NSGet( "/:id" ,  func (ctx *context.Context) {
            ctx.Output.Body([]byte( "notAllowed" ))
        }),
    ),
    web.NSNamespace( "/cms" ,
        web.NSInclude(
            &controllers.MainController{},
            &controllers.CMSController{},
            &controllers.BlockController{},
        ),
    ),
)
//注册 namespace
web.AddNamespace(ns)

 

上面这个代码支持了如下的URL请求:

  • GET /v1/notallowed
  • GET /v1/version
  • GET /v1/changepassword
  • POST /v1/changepassword
  • GET /v1/shop/123
  • GET /v1/cms/ 对应 MainController、CMSController、BlockController 中的注解路由

 

3. beego控制器

自定义controller的实现需要继承beego.Controller

package controllers

import beego  "github.com/beego/beego/v2/server/web"

type UserController  struct {
    beego.Controller
}

 

3.1 控制器方法

beego.Controller实现了接口 beego.ControllerInterface,主要包含了以下函数

type ControllerInterface  interface {
    Init(ct *context.Context, controllerName, actionName string, app  interface {})
    Prepare()
    Get()
    Post()
    Delete()
    Put()
    Head()
    Patch()
    Options()
    Trace()
    Finish()
    Render() error
    XSRFToken() string
    CheckXSRFCookie() bool
    HandlerFunc(fn string) bool
    URLMapping()
}
  • Init():初始化context、Controller名称、模板名等
  • Prepare():用户扩展,这个函数会在下面定义的这些Method方法之前执行,用户可以重写这个函数实现类似于用户验证的工作
  • Finish():这个函数是在执行完HTTP method之后执行,默认为nil,用户可以重写这个函数用于关闭数据库、清理缓存等工作
  • Render():这个函数主要用来实现渲染模板,如果 beego.AutoRender 为 true 的情况下才会执行

 

3.2 子类扩展

通过子类对于方法的重写,用户可以实现自己的逻辑,下面是一个实际的例子

type AddController  struct {
    web.Controller
}

func (this *AddController) Prepare() {

}

// Get 渲染一个模板
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" )
}

 

下面是一个比较流行的架构,首先实现一个自己的基类 baseController,实现以下初始化的方法,然后其他所有逻辑继承自该基类

type NestPreparer  interface {
        NestPrepare()
}

// baseRouter implemented global settings for all other routers.
type baseController  struct {
        web.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()
        }
}

 

上面定义了基类,大概是初始化了一些变量,最后有一个 Init() 函数中的那个 app 的应用

判断当前运行的Controller是否是NestPreparer的实现,如果是的话调用子类的方法,下面是NestPreparer的实现:

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

 

这样我们的执行器执行的逻辑是这样的,首先执行 Prepare,这个就是 Go 语言中 struct 中寻找方法的顺序,依次往父类寻找。

执行 BaseAdminRouter 时,查找他是否有 Prepare 方法,没有就寻找 baseController,找到了,那么就执行逻辑,

然后在 baseController 里面的 this.AppController 即为当前执行的控制器 BaseAdminRouter,因为会执行 BaseAdminRouter.NestPrepare 方法。

然后开始执行相应的 Get 方法或者 Post 方法

 

3.3 提前终止运行

我们应用中经常会遇到这种情况,在Prepare阶段进行判断,如果用户认证不通过,则输出一段提示信息然后终止进程

可以使用StopRun来终止执行逻辑,可以在任意地方执行

type RController  struct {
    beego.Controller
}

func (this *RController) Prepare() {
    this.Data[ "json" ] =  map [string] interface {}{ "name" :  "astaxie" }
    this.ServeJSON()
    this.StopRun()
}

  

在调用StopRun()之后,如果还定义了Finish(),那么Finish()不会执行,如果需要释放资源,需要在StopRun()之前手动调用Finish()

 

标签:web,beego,string,golang,key,Data,路由
来源: https://www.cnblogs.com/aganippe/p/16126586.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有