概述
通过学习如何使用 Go 语言来实现一个完整的框架设计,从而了解如何开发 Web 应用,如何搭建自己的目录结构,如何实现路由,如何实现 MVC 模式等各方面的开发内容。
项目规划
在学习使用 beego 框架之前,需要了解其项目配置、执行逻辑、项目结构、项目架构。
GOPATH 配置
Mac 系统配置 GOPATH:
-
打开终端,打开目录:
cd ~
-
查看是否有 .bash_profile 文件:
ls -all
-
有则跳过此步,没有则:
1)创建:touch .bash_profile
2)编辑:vi .bash_profile
3)自定义 GOPATH 和 GOBIN 位置:export GOROOT=/usr/local/go export GOPATH=$HOME/Workspace/go export PATH=$PATH:${GOPATH//://bin:}/bin
-
编译:
source .bash_profile
-
查看 Go 环境变量:
go env
项目设置
必须保证 go(GOPATH="/Users/play/Workspace/go") 这个代码目录下面有三个目录 pkg、bin、src,新建项目的源码放在 src 目录下面,在此目录叫做 beeblog。
beego 的执行逻辑
beego 框架是基于 模型 - 视图 - 控制器 这一设计模式的。MVC 是一种将应用程序的逻辑层和表现层进行分离的结构方式。在实践中,由于表现层从 Go 中分离了出来,所以它允许你的网页中只包含很少的脚本。
-
模型 (Model) 代表数据结构。通常来说,模型类将包含取出、插入、更新数据库资料等这些功能。
-
视图 (View) 是展示给用户的信息的结构及样式。一个视图通常是一个网页,但是在 Go 中,一个视图也可以是一个页面片段,如页头、页尾。它还可以是一个 RSS 页面,或其它类型的“页面”,Go 实现的 template 包已经很好的实现了 View 层中的部分功能。
-
控制器 (Controller) 是模型、视图以及其他任何处理 HTTP 请求所必须的资源之间的中介,并生成网页。
下图显示了项目设计中框架的数据流是如何贯穿整个系统:

- main.go 作为应用入口,初始化一些运行博客所需要的基本资源,配置信息,监听端口。
- 路由功能检查 HTTP 请求,根据 URL 以及 method 来确定谁(控制层)来处理请求的转发资源。
- 如果缓存文件存在,它将绕过通常的流程执行,被直接发送给浏览器。
- 安全检测:应用程序控制器调用之前,HTTP 请求和任一用户提交的数据将被过滤。
- 控制器装载模型、核心库、辅助函数,以及任何处理特定请求所需的其它资源,控制器主要负责处理业务逻辑。
- 输出视图层中渲染好的即将发送到 Web 浏览器中的内容。如果开启缓存,视图首先被缓存,将用于以后的常规请求。
beego 项目结构
一般的 beego 项目的目录如下所示:
├── conf
│ └── app.conf
├── controllers
│ ├── admin
│ └── default.go
├── main.go
├── models
│ └── models.go
├── static
│ ├── css
│ ├── ico
│ ├── img
│ └── js
└── views
├── admin
└── index.tpl
从上面的目录结构我们可以看出来 M(models 目录)、V(views 目录)和 C(controllers 目录)的结构, main.go 是入口文件。
beego 的架构
beego 的整体设计架构如下所示:

beego 是基于八大独立的模块构建的,是一个高度解耦的框架。当初设计 beego 的时候就是考虑功能模块化,用户即使不使用 beego 的 HTTP 逻辑,也依旧可以使用这些独立模块,例如:你可以使用 cache 模块来做你的缓存逻辑;使用日志模块来记录你的操作信息;使用 config 模块来解析你各种格式的文件。所以 beego 不仅可以用于 HTTP 类的应用开发,在你的 socket 游戏开发中也是很有用的模块。大家如果玩过乐高的话,应该知道很多高级的东西都是一块一块的积木搭建出来的,而设计 beego 的时候,这些模块就是积木,高级机器人就是 beego。
路由器设计
路由器用于检查 HTTP 请求,根据 URL 以及 method 来确定谁(控制层)来处理请求的转发资源。
HTTP 路由
HTTP 路由组件负责将 HTTP 请求交到对应的函数处理(或者是一个 struct 的方法),路由在框架中相当于一个事件处理器,而这个事件包括:
- 用户请求的路径 (path),例如:
/user/123,/article/123
,和参数信息,例如:?id=11
- HTTP 的请求方法 (method),例如:GET、POST、PUT、DELETE、PATCH 等
路由器就是根据用户请求的事件信息转发到相应的处理函数(控制层)。
默认的路由实现
默认使用 Go 的 http 包来设计和实现路由,以一个例子来说明:
func fooHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}
http.HandleFunc("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
log.Fatal(http.ListenAndServe(":8080", nil))
上面的例子调用了 http 默认的 DefaultServeMux 来添加路由,需要提供两个参数,第一个参数是希望用户访问此资源的 URL 路径(保存在 r.URL.Path),第二参数是即将要执行的函数,以提供用户访问的资源。路由的思路主要集中在两点:
- 添加路由信息
- 根据用户请求转发到要执行的函数
Go 默认的路由添加是通过函数 http.Handle 和 http.HandleFunc 等来添加,底层都是调用了 DefaultServeMux.Handle(pattern string, handler Handler),这个函数会把路由信息存储在一个 map 信息中 map[string]muxEntry,这就解决了上面说的第一点。
Go 监听端口,然后接收到 tcp 连接会扔给 Handler 来处理,上面的例子默认 nil 即为 http.DefaultServeMux,通过 DefaultServeMux.ServeHTTP 函数来进行调度,遍历之前存储的 map 路由信息,和用户访问的 URL 进行匹配,以查询对应注册的处理函数,这样就实现了上面所说的第二点。
beego 框架路由实现
目前几乎所有的 Web 应用路由实现都是基于 http 默认的路由器,但是 Go 自带的路由器有几个限制:
- 不支持参数设定,例如 /user/:uid 这种泛类型匹配
- 无法很好的支持 REST 模式,无法限制访问的方法,例如上面的例子中,用户访问 /foo,可以用 GET、POST、DELETE、HEAD 等方式访问
- 一般网站的路由规则太多了,编写繁琐。
beego 框架的路由器基于上面的几点限制考虑设计了一种 REST 方式的路由实现,路由设计也是基于上面 Go 默认设计的两点来考虑:存储路由和转发路由
存储路由
针对前面所说的限制点,首先要解决参数支持就需要用到正则,第二和第三点通过一种变通的方法来解决,REST 的方法对应到 struct 的方法中去,然后路由到 struct 而不是函数,这样在转发路由的时候就可以根据 method 来执行不同的方法。
根据上面的思路,设计了两个数据类型 ControllerInfo 和 ControllerRegister ( routers 是一个 slice 用来保存用户添加的路由信息,以及 beego 框架的应用信息)
// 源码:https://github.com/astaxie/beego/blob/develop/router.go
// ControllerInfo holds information about the controller.
type ControllerInfo struct {
pattern string
controllerType reflect.Type
methods map[string]string
handler http.Handler
runFunction FilterFunc
routerType int
initialize func() ControllerInterface
methodParams []*param.MethodParam
}
// ControllerRegister containers registered router rules, controller handlers and filters.
type ControllerRegister struct {
routers map[string]*Tree
enablePolicy bool
policies map[string]*Tree
enableFilter bool
filters [FinishRouter + 1][]*FilterRouter
pool sync.Pool
}
转发路由
转发路由是基于 ControllerRegistor 里的路由信息来进行转发的,详细的实现查看文件 router.go 的 ServeHTTP 方法:
// https://github.com/astaxie/beego/blob/develop/router.go
func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
...
使用入门
具体使用方法: beego.me/docs/quicks…
Controller 设计
设计一个基于 REST 风格的 MVC 框架中的 controller,最大限度地简化 Web 应用的开发。
Controller 作用
MVC 设计模式是目前 Web 应用开发中最常见的架构模式,通过分离 Model(模型)、View(视图)和 Controller(控制器),可以更容易实现易于扩展的用户界面 (UI)。Model 指后台返回的数据;View 指需要渲染的页面,通常是模板页面,渲染后的内容通常是 HTML;Controller 指 Web 开发人员编写的处理不同 URL 的控制器,controller 在整个的 MVC 框架中起到了一个核心的作用,负责处理业务逻辑,因此控制器是整个框架中必不可少的一部分,Model 和 View 对于有些业务需求是可以不写的,例如没有数据处理的逻辑处理,没有页面输出的 302 调整之类的就不需要 Model 和 View,但是 controller 这一环节是必不可少的。
beego 的 REST 设计
前面了解到路由实现了注册 struct 的功能,而 struct 中实现了 REST 方式,现在需要设计一个用于逻辑处理 controller 的基类,这里主要设计了两个类型,一个 struct、一个 interface
// 源码地址: https://github.com/astaxie/beego/blob/develop/controller.go
// Controller defines some basic http request handler operations, such as
// http context, template and view, session and xsrf.
type Controller struct {
// context data
Ctx *context.Context
Data map[interface{}]interface{}
// route controller info
controllerName string
actionName string
methodMapping map[string]func() //method:routertree
AppController interface{}
// template data
TplName string
ViewPath string
Layout string
LayoutSections map[string]string // the key is the section name and the value is the template name
TplPrefix string
TplExt string
EnableRender bool
// xsrf data
_xsrfToken string
XSRFExpire int
EnableXSRF bool
// session
CruSession session.Store
}
// ControllerInterface is an interface to uniform all controller handler.
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()
}
应用指南
beego 框架中完成了 controller 基类的设计,在应用具体使用方法看查看:beego.me/docs/mvc/co…
Model 设计
Web 应用中用的一个重要环节就是数据库操作,而 model 层的设计目的就用来做这些操作。
Model 作用
如果应用足够简单,那么 Controller 可以处理一切的逻辑,如果逻辑里面存在着可以复用的东西,那么就抽取出来变成一个模块。因此 Model 就是逐步抽象的过程,一般使用 Model 处理一些数据读取。
beego 的 Model 设计
beego ORM 是一个强大的 Go 语言 ORM 框架。它的设计灵感主要来自 Django ORM 和 SQLAlchemy。已支持数据库驱动包括:MySQL、PostgreSQL、Sqlite3。
安装 ORM:
go get github.com/astaxie/beego/orm
应用指南
beego ORM 的使用方法:beego.me/docs/mvc/mo…
View 设计
在 MVC 的设计模式中,View 负责展现结果。至于 View 层的处理,在很多动态语言里面都是通过在静态 HTML 中插入动态语言生成的数据,例如 JSP、PHP 中通过插入来实现的。在 Go 语言中,使用 template 包来进行模板处理,实现 View 展示。
View 作用
View 可以实现 web 展示和用户交互功能,在视图中其实没有真正的处理发生,它只是作为一种输出数据并允许用户操纵的方式。
beego 的 View 设计
beego 中使用的模板语法,与 go 模板语法基本相同。
应用指南
beego 的模板语法指南:beego.me/docs/mvc/vi…