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

Powered By Valine
v1.5.2
CATALOG
  1. 1. Beego整体框架
  2. 2. Beego路由
  3. 3. 参考学习