f10@t's blog

Beego学习-路由设置

字数统计: 2.3k阅读时长: 10 min
2021/07/06

最近刚刚入门了Go语言,因为之前主要使用Java语言,相比之下Go语言去掉了一些如extend、implement这种东西,更加的简洁,并且保留了指针等底层的操作,并且在容器操作支持这方面还挺好。Beego算是go语言web框架中比较流行的,这篇记录一下Beego的路由机制学习。

Beego整体框架

Beego的整体设计架构如下图:

architecture

目前beego已经到了v2的版本https://github.com/beego/beego/releases/tag/v2.0.1,所以从上图中可以看到主要有八个模块:task、ORM、httplib、cache、web、log、config、admin。这八个模块可以独立使用。

下图是其MVC架构的执行逻辑图

flow

Beego路由

我们先建立一个demo项目,这里推荐使用bee命令来完成,安装:

1
go get -u github.com/beego/bee/v2

记得把你的$GOPATH\bin路径加入环境变量,如果是开发web项目,那么使用bee new [项目名称]就可以了:

image-20210706120201114

如果是开发api项目,如restful api,使用bee api [项目名称]就可以了。下面是web项目初始化后的目录。可以看到结构很清晰,controllers放控制器,models放模型,views和static放置视图层代码,routers放路由,入口是main.gogo.mod记录依赖。非常的清晰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
│  go.mod
│ main.go
├─conf
│ app.conf
├─controllers
│ default.go
├─models
├─routers
│ router.go
├─static
│ ├─css
│ ├─img
│ └─js
│ reload.min.js
├─tests
│ default_test.go
└─views
index.tpl

new之后可以使用`bee run命令一键执行,免去了前面的环节:

image-20210706121108832

image-20210706121130509

下面正式看一下路由部分,Beego中的路由从大类上可分为三种路由:固定路由、正则路由、自动路由。其他的什么注解路由、namespace其实和那三个效果差不多。

基本GET、POST路由

先来看一下如何进行基本的GET、POST路由,代码如下,其中我们只需要直接调用web的方法GET、POST即可实现GET和POST请求的路由处理。这里写的比较简单,直接嵌套了一个函数定义来处理业务逻辑,实际上,一般每一个路由规则应该交由一个handler来处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package routers

import (
"BeegoDemo/controllers"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/server/web/context"
)

func init() {
// GET请求
beego.Get("/hello", func(ctx *context.Context) {
ctx.Output.Body([]byte("hello GET!"))
})
// POST请求
beego.Post("/hello", func(ctx *context.Context) {
ctx.Output.Body([]byte("hello POST!"))
})
// Any
beego.Any("/any", func(ctx *context.Context) {
ctx.Output.Body([]byte("This can recive any type of request."))
})
beego.Router("/", &controllers.MainController{})
}

image-20210706165627097

固定路由

一个简单的例子如下,首先我们自定义一个控制器:

1
2
3
4
5
6
7
8
9
10
11
12
package controllers

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

type BookController struct {
web.Controller
}

func (book *BookController) Get() {
book.Data["BookName"] = "Go 语言实战"
book.TplName = "book.tpl"
}

其中BookController继承了web.Controller类(其实go没有类的概念,他就是个结构体,你直接覆写方法就可以了,就。。。开始还是觉得挺奇怪的),我们覆写Get方法,指定接收者为BookController的指针类型(意思就是BookController指针类型有这个方法了),然后其中为web.Controller结构体中定义的变量进行复制,比如在Data中定义了BookName这个变量,然后TplName指的是该方法返回的视图层代码是book.tpl(就是个html文件,我还不清楚问啥叫tpl)。

然后我们在router.go中添加固定路由

1
2
3
4
5
6
7
8
9
10
11
package routers

import (
"BeegoDemo/controllers"
beego "github.com/beego/beego/v2/server/web"
)

func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/book", &controllers.BookController{}) // 这就是新增加的固定路由
}

然后在views下增加book.tpl文件:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Book</title>
</head>
<body>
the Book name is {{.BookName}}
</body>
</html>

其中{{.BookName}}是用来从我们刚才为Data字典赋的名为BookName的键值,等于就是那种动态模板,这里直接可以读取值进行填充。然后bee run起来看看效果:

image-20210706173521890

可以看到按照预期运行了,这就是固定路由,简单直接.

正则路由

这个功能是Beego参考sinatra的设计,通过一些正则符号来进行url和对应控制器的匹配。这里直接看官方给的例子:

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
web.Router(“/api/?:id”, &controllers.RController{})
默认匹配 //例如对于URL”/api/123”可以匹配成功,此时变量”:id”值为”123”,URL”/api/“可正常匹配

web.Router(“/api/:id”, &controllers.RController{})
默认匹配 //例如对于URL”/api/123”可以匹配成功,此时变量”:id”值为”123”,但URL”/api/“匹配失败

web.Router(“/api/:id([0-9]+)“, &controllers.RController{})
自定义正则匹配 //例如对于URL”/api/123”可以匹配成功,此时变量”:id”值为”123”

web.Router(“/user/:username([\\w]+)“, &controllers.RController{})
正则字符串匹配 //例如对于URL”/user/astaxie”可以匹配成功,此时变量”:username”值为”astaxie”

web.Router(“/download/*.*”, &controllers.RController{})
*匹配方式 //例如对于URL”/download/file/api.xml”可以匹配成功,此时变量”:path”值为”file/api”, “:ext”值为”xml”

web.Router(“/download/ceshi/*“, &controllers.RController{})
*全匹配方式 //例如对于URL”/download/ceshi/file/api.json”可以匹配成功,此时变量”:splat”值为”file/api.json”

web.Router(“/:id:int”, &controllers.RController{})
int 类型设置方式,匹配 :id为int 类型,框架帮你实现了正则 ([0-9]+)

web.Router(“/:hi:string”, &controllers.RController{})
string 类型设置方式,匹配 :hi 为 string 类型。框架帮你实现了正则 ([\w]+)

web.Router(“/cms_:id([0-9]+).html”, &controllers.CmsController{})
带有前缀的自定义正则 //匹配 :id 为正则类型。匹配 cms_123.html 这样的 url :id = 123

自动路由

自动路由则更为简单,你只需要把控制器注册到路由中就可以了,比如上面那个例子我们去掉url:

1
2
3
4
5
6
7
8
9
10
11
package routers

import (
"BeegoDemo/controllers"
beego "github.com/beego/beego/v2/server/web"
)

func init() {
beego.Router("/", &controllers.MainController{})
beego.AutoRouter(&controllers.BookController{}) // 去掉url,改为使用AutoRouter方法来进行注册
}

这时候我们直接访问url,beego会自动映射到对应的方法上去:

image-20210706175632259

比如我们定义的BookController,我们只需要写/book就可以了,然后要执行他的get方法就写/book/get就可以了。

注解路由(1.3 新增)

注解路由免去了我们如上面几个一样添加路由的代码,而只需要我们写一个controller,然后将它include进去就可以了。我们继续修改BookController的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
package controllers

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

type BookController struct {
web.Controller
}

// @router /viewbook [get]
func (book *BookController) check() {
book.Data["BookName"] = "Go 语言实战"
book.TplName = "book.tpl"
}

我们覆写了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
      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)
      上面这些方法与beego定义的get、post、router什么的是一样的效果。*Namespace也有一些方法,但是官方说明和上面这些效果是一样的,不如上面这些个优雅。

我们还是以BookController为例子来使用Namespace来进行改造:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// router.go
package routers

import (
"BeegoDemo/controllers"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/server/web/context"
)

func init() {
beego.AddNamespace( // 注册一个新的namespace
beego.NewNamespace("/v1", // 定义一个新的接口
beego.NSInclude(&controllers.MainController{}), // 1. 使用NSInclude包含使用注解方式的路由
beego.NSInclude(&controllers.BookController{}),
beego.NSNamespace("/info", // 自定义固定方式的路由
beego.NSGet("/version", func(ctx *context.Context) {
ctx.Output.Body([]byte("1.0.0"))
}
)
),
)
}

参考学习

Beego Framework

CATALOG
  1. 1. Beego整体框架
  2. 2. Beego路由
    1. 2.1. 基本GET、POST路由
    2. 2.2. 固定路由
    3. 2.3. 正则路由
    4. 2.4. 自动路由
    5. 2.5. 注解路由(1.3 新增)
    6. 2.6. namespace
  3. 3. 参考学习