最近刚刚入门了Go语言,因为之前主要使用Java语言,相比之下Go语言去掉了一些如extend、implement这种东西,更加的简洁,并且保留了指针等底层的操作,并且在容器操作支持这方面还挺好。Beego算是go语言web框架中比较流行的,这篇记录一下Beego的路由机制学习。
Beego整体框架
Beego的整体设计架构如下图:
目前beego已经到了v2的版本https://github.com/beego/beego/releases/tag/v2.0.1
,所以从上图中可以看到主要有八个模块:task、ORM、httplib、cache、web、log、config、admin。这八个模块可以独立使用。
下图是其MVC架构的执行逻辑图

Beego路由
我们先建立一个demo项目,这里推荐使用bee
命令来完成,安装:
1 | go get -u github.com/beego/bee/v2 |
记得把你的$GOPATH\bin
路径加入环境变量,如果是开发web项目,那么使用bee
new [项目名称]就可以了:

如果是开发api项目,如restful
api,使用bee api [项目名称]
就可以了。下面是web项目初始化后的目录。可以看到结构很清晰,controllers
放控制器,models
放模型,views和static
放置视图层代码,routers
放路由,入口是main.go
,go.mod
记录依赖。非常的清晰。
1 | │ go.mod |
new之后可以使用`bee run
命令一键执行,免去了前面的环节:

下面正式看一下路由部分,Beego中的路由从大类上可分为三种路由:固定路由、正则路由、自动路由。其他的什么注解路由、namespace其实和那三个效果差不多。
基本GET、POST路由
先来看一下如何进行基本的GET、POST路由,代码如下,其中我们只需要直接调用web的方法GET、POST即可实现GET和POST请求的路由处理。这里写的比较简单,直接嵌套了一个函数定义来处理业务逻辑,实际上,一般每一个路由规则应该交由一个handler来处理。
1 | package routers |
固定路由
一个简单的例子如下,首先我们自定义一个控制器:
1 | package controllers |
其中BookController继承了web.Controller类(其实go没有类的概念,他就是个结构体,你直接覆写方法就可以了,就。。。开始还是觉得挺奇怪的
),我们覆写Get方法,指定接收者为BookController的指针类型(意思就是BookController指针类型有这个方法了),然后其中为web.Controller结构体中定义的变量进行复制,比如在Data中定义了BookName这个变量,然后TplName指的是该方法返回的视图层代码是book.tpl(就是个html文件,我还不清楚问啥叫tpl)。
然后我们在router.go中添加固定路由:
1 | package routers |
然后在views下增加book.tpl文件:
1 |
|
其中{{.BookName}}
是用来从我们刚才为Data
字典赋的名为BookName
的键值,等于就是那种动态模板,这里直接可以读取值进行填充。然后bee
run起来看看效果:
可以看到按照预期运行了,这就是固定路由,简单直接.
正则路由
这个功能是Beego参考sinatra的设计,通过一些正则符号来进行url和对应控制器的匹配。这里直接看官方给的例子:
1 | web.Router(“/api/?:id”, &controllers.RController{}) |
自动路由
自动路由则更为简单,你只需要把控制器注册到路由中就可以了,比如上面那个例子我们去掉url:
1 | package routers |
这时候我们直接访问url,beego会自动映射到对应的方法上去:
比如我们定义的BookController,我们只需要写/book就可以了,然后要执行他的get方法就写/book/get就可以了。
注解路由(1.3 新增)
注解路由免去了我们如上面几个一样添加路由的代码,而只需要我们写一个controller,然后将它include进去就可以了。我们继续修改BookController的例子:
1 | package controllers |
我们覆写了URLMapping这个函数,在其中定义映射的url和指定处理的方法,然后在方法上添加注解// @router /viewbook [get]
,前面@router
为固定,后面两个分别为url地址以及可以使用的方法,其实上面这个就等同于下面这条语句的效果:
1 | beego.Router("/viewbook", &Controllers.BookController, "get:check") |
其中第三个参数就是用来指定http方法与处理函数对应关系的。
namespace
这个貌似用的多一点,因为看起来更加清晰一点,并且可以对多个接口进行管理,主要使用到的函数如下:
Namespace
接口方法如下:
NewNamespace(prefix string, funcs ...interface{})
- 初始化 namespace 对象,下面这些函数都是 namespace 对象的方法,但是强烈推荐使用 NS 开头的相应函数注册,因为这样更容易通过 gofmt 工具看的更清楚路由的级别关系
NSCond(cond namespaceCond)
- 支持满足条件的就执行该 namespace, 不满足就不执行
NSBefore(filiterList …FilterFunc) 以及 NSAfter(filiterList …FilterFunc)
- 分别对应 beforeRouter 和 FinishRouter 两个过滤器,可以同时注册多个过滤器、
NSNamespace(prefix string, params ...innerNamespace)
- 嵌套其他namespace 上面这些方法与beego定义的get、post、router什么的是一样的效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 注册相关
NSInclude(cList …ControllerInterface)
NSRouter(rootpath string, c ControllerInterface, mappingMethods …string)
NSHandler(rootpath string, h http.Handler)
NSAutoRouter(c ControllerInterface)
NSAutoPrefix(prefix string, c ControllerInterface)
// 请求相关
NSGet(rootpath string, f FilterFunc)
NSPost(rootpath string, f FilterFunc)
NSDelete(rootpath string, f FilterFunc)
NSPut(rootpath string, f FilterFunc)
NSHead(rootpath string, f FilterFunc)
NSOptions(rootpath string, f FilterFunc)
NSPatch(rootpath string, f FilterFunc)
NSAny(rootpath string, f FilterFunc)*Namespace
也有一些方法,但是官方说明和上面这些效果是一样的,不如上面这些个优雅。
- 嵌套其他namespace
我们还是以BookController为例子来使用Namespace来进行改造:
1 | // router.go |