title: Beego脱坑(三)Router
tags: go,beego
author : Clown95
beego中的路由的主要功能是实现从请求地址到实现方法 ,简单的说就是路由就是能够自动匹配url地址,并调用相应的控制器处理信息。
在之前创建beego项目中,我们为了完成hello world的输出,在 router.go 中添加了
beego.Router("/hello",&controllers.HelloControllers{})
我们这段代码的意思就是把 /hello 这个地址分配给 HelloControllers 这个控制器去处理。
简单路由
我们先来了解下最基本的 GET路由和PSOT路由。
GET路由
func (hello * HelloControllers) Get() {
hello.Ctx.WriteString("hello world\n")
}
还记得我们之前写hello.go的代码吗?我们是通过HelloControllers控制器,执行Get方法,来输出 hello world
现在我们不通过控制器,直接使用GET路由来输出 Hello Beego
package routers
import (
"github.com/astaxie/beego/context"
)
func init() {
/**/
beego.Get("hello1", func(context *context.Context) {
context.WriteString("Hello Beego\n")
})
}
我们运行程序,并且打开请求可以看到,成功的输出了 Hello Beego ,日志中显示的是 GET 请求。
POST路由
接着我们再来说下POST路由,我们把刚刚的代码简单修改下
beego.Post("hello2", func(context *context.Context) {
context.WriteString("Hello Beego\n")
})
现在我们执行的是POST请求,直接使用浏览器打开肯定是不行的。
所以我们使用postman模拟下post请求
固定路由
那么固定路由又是什么呢?从字面意思理解是不会改变的路由,我们刚刚使用的 /hello /hello1 /hello2 都可以被成为固定路由。
只有我们正确的输入才能够匹配到相应的结果,即完全匹配,比如说输入/hello 只会匹配到 hello world ,而不会匹配到 hello beego。
正则路由
正则路由则跟固定路由有所区别了,它并不需要完全匹配,只需要符合这个路由所设置的规则即可,我们来演示下。
先添加路由
beego.Router("/Api/?:id",&controllers.RegularController{}) //我们定义一个正则路由
在controllers目录下创建 reg.go文件
package controllers
import "github.com/astaxie/beego"
type RegularController struct {
beego.Controller
}
func (reg * RegularController) Get() {
id:= reg.Ctx.Input.Param(":id")
reg.Ctx.WriteString("id="+id+"\n")
}
我们来看下多次运行结果:
正则路由就是能够让我们更灵活的匹配内容,并且减少开发者的代码量
https://blog.csdn.net/yang731227/article/details/82251316 比如说我们看CSDN这个文章地址,文章控制器都是通用的,我们没必要为每一篇文章都添加一个控制器,我们看这个地址中文章编号已经是8000多万了,我们想象下写8000多万个控制器是什么概念,即使我们有那功夫写这么多控制器,那也是不可行的,因为这个文章数是不确定的,用户可能会增加文章或者删除文章,我们不可能完全一一对应,所以使用根据一定的规则来写路由是这类型地址的最佳选择。
更多正则路由说明,请查看官方文档https://beego.me/docs/mvc/controller/router.md#%E6%AD%A3%E5%88%99%E8%B7%AF%E7%94%B1
自定义方法及 RESTful 规则
我们上面的请求方法,不是GET就是POST,那我们能不能自定义请求方法呢?答案是肯定的
我们先来看下面的一行代码,可以看到它既没有使用GET也没有使用POST
beego.Router("/",&IndexController{},"*:Index")
我们之前使用Router都是只传递了两个参数,上面的代码增加了一个参数,那么这第三个参数能干什么?
第三个参数就是用来设置对应 method 到函数名,定义如下
-
*
表示任意的 method 都执行该函数 - 使用 httpmethod:funcname 格式来展示
- 如果想要使用多个不同的方法使用
;
分割 - 多个 method 对应同一个 funcname,method 之间通过
,
来分割
我们来演示下自定义方法:
创建文件 Custom.go
package controllers
import (
"github.com/astaxie/beego"
)
type CustomController struct {
beego.Controller
}
func (this *CustomController) GetFunc() {
username := this.GetString("username")
password := this.GetString("password")
this.Ctx.WriteString("username = " + username + "\npassword = " + password + "\n用于处理get请求")
}
注册路由:
beego.Router("/rest",&controllers.CustomController{},"Get:GetFunc")
执行地址;
刚刚演示了一个自定义的Get方法,现在我们就来改成Post
func (this *CustomController) PostFunc() {
username := this.GetString("username")
password := this.GetString("password")
this.Ctx.WriteString("username = " + username + "\npassword = " + password + "\n用于处理post请求")
}
我们在之前的路由后面追加Post方法
beego.Router("/rest",&controllers.CustomController{},"Get:GetFunc;Post:PostFunc")
使用PostMan模拟请求
除了Get:GetFunc 和Post:PostFunc。我们还可以定义 *:AllFunc,即两个方法都可以,具体的演示这里不在叙述,如果有不明白的地方可以查看官方文档。
如果同时存在 * 和对应的 HTTP Method,那么优先执行 HTTP Method 的方法,如执行的时候请求了Post,首先执行的是PostFunc而不是AllFunc。
值得注意的是:不要被GetFunc 、PostFunc和AllFunc 这些方法名混淆,并不是强制要求这么写,这些名字可以是任意符合方法命名规则的名字。
自动匹配
自动匹配比较有意思,它不需要我们指定请求地址,它可以根据我们传来的请求自动匹配方法。这么说是不是有点迷惑?没关系我们还是来看代码:
package controllers
import (
"github.com/astaxie/beego"
)
type AutoController struct {
beego.Controller
}
func (this *AutoController) GetFunc(){
p:=this.Ctx.Input.Params() //Params是解析多个参数,返回map
for k,v:=range p{
this.Ctx.WriteString(k+"="+v+"\n")
}
}
下面注意路由使用的函数,我们可以清楚的看到 beego调用了 AutoRouter 函数并且参数只有一个控制器。
beego.AutoRouter(&controllers.AutoController{})
AutoRouter的实现原理是反射,具体细节可以自己看golang代码研究。
小伙伴们是不是不知道怎么填写地址了?没有关系先跟着我们来,我们在浏览器或者使用Curl命令打开
http://localhost:8080/Auto/GetFunc/123/456
我们先来简单了解下 AutoRouter怎么匹配的 ,通过地址我们可以猜想,Auto/GetFunc
这段的意思是先匹配AutoController控制器,然后执行GetFunc
这个方法 ,接着解析123/456
这两个参数。除了前缀两个 /:controller(控制器名称)/:method(函数名称)
的匹配之外,剩下的 url beego 会帮你自动化解析为参数,保存在 this.Ctx.Input.Params
当中。
有一个点必须要强调,首先我们先来看下我们定义的所有控制的名字 HelloController 、RegularController 、CustomController 和 AutoController 你是不是发现了什么?对没错我们的控制器都是以 xxxController 命名的。自动匹配就会根据地址自动匹配xxx,所以使用自动匹配,控制器的名字一定要符合规则,不然会提示404的。
注解路由
什么是注解路由?注解路由就是我们不需要在router.go中注册路由了,只需要在相对应的controller上方写上一定格式的注释,即可注册路由。
注解路由的格式为:
// @router /xxx/:key [get]
必须以@router开头 然后 / 后面是制定地址 接着后面是参数 [get]是表示get的传递方式 。
现在我们把 /hello 这个固定路由改造下,改成注解路由。
比如说我们之前注册的 HelloController 路由,正常的方法是在router.go 中添加下面代码
beego.Router("/hello",&controllers.HelloController{})
现在我们使用include注册注解路由,替换上面固定路由。
beego.Include(&controllers.HelloController{})
然后在控制器方法上方,添加注解路由
// @router /hello
func (hello * HelloController) Get() {
hello.Ctx.WriteString("hello world\n")
}
然后我们执行程序,成功的调用了HelloController 控制器
URLMapping
在新版中beego 可以使用URLMapping 方法来指定执行对应函数,提高注解路由性能。
具体用法如下:
// @router /hello
func (hello * HelloController) Get() {
hello.Ctx.WriteString("hello world\n")
}
func (hello * HelloController) URLMapping() {
hello.Mapping("Get",hello.Get)
}
对于注解路由,我个人是不太建议使用,虽然这个写法可以很直观的看到是什么请求调用什么方法,但是我感觉还是比较容易踩坑。首先它效率上比不上固定路由或者正则路由,而且有时候可能会匹配不到控制器,比如说我之前遇到过如果我不为控制器添加URLMapping方法,请求怎么都匹配不到控制器,所以我们真的没必要使用注解路由。