浅析GO语言中的beego框架

beego是一个快速开发Go应用的http框架,作者是SegmentFault 用户,go 语言方面技术大牛。beego可以用来快速开发API、Web、后端服务等各种应用,是一个 RESTFul的框架,主要设计灵感来源于 tornado、sinatra、 flask这三个框架,但是结合了Go本身的一些特性(interface、struct继承等)而设计的一个框架。

架构

beego是基于八大独立的模块之上构建的,是一个高度 解耦的框架。当初设计beego的时候就是考虑功能模块化,用户即使不适用beego的http逻辑,也是可以在使用这些独立模块,例如你可以使用cache模块来做你的缓存逻辑,使用日志模块来记录你的操作信息,使用 config模块来解析你各种格式的文件,所以不仅仅在beego开发中,你的socket游戏开发中也是很有用的模块,这也是beego为什么受欢迎的一个原因。大家如果玩过乐高的话,应该知道很多高级的东西都是一块一块的积木搭建出来的,而设计beego的时候,这些模块就是积木,高级机器人就是beego。至于这些模块的功能以及如何使用会在后面的文档会逐一介绍。

执行逻辑

既然beego是基于这些模块构建的,那么他的执行逻辑是怎么样的呢?beego是一个典型的MVC架构,他的执行逻辑如下图所示:

项目结构

一般的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是入口文件。

选择 Go 语言

断断续续看了 Go 几个星期了,讲真的真是喜欢的不得了。认真学过之后,你会觉得非常的优雅,写东西很舒服。学习 Go 我觉得很有必要的是,Go 中自带的数据结构很少,类似于 List 或者 Tree 之类的,最好尝试一下如何去设计一些常用的数据结构。话说回来,Go 的出身始终是一门后端语言。我非常后悔用 Flask 或者 Django 来作为我的后端入门框架或者选择。封装的太好了,往往对于一个入门新手来说学习不到什么。

而 Go 就不一样了,它天生被设计是一门后端语言。也就是说,你将会学习到非常多的后端知识。看看下面这一张图,当时我看着就有一种很过瘾的感觉,因为这些知识你都知道,但是作为一个后端开发者你没有去了解过,这是非常大的失误。并不是想去用学习好 Go 去弥补没有学习好 C++ 的遗憾,只是新生事物,多尝试尝试总是极好的,哪怕只是浅尝辄止。Go 作为一门新的语言,其语言设计的特性,背后 Google 爸爸的撑腰以及现在 Docker 技术发展,前景应该还是不错的。所以如果你是编程新手或者是想入门后端的开发者,我强烈建议你选择 Go 语言。

语言学到最后,框架总是少不了的。虽然不能完全依赖框架,但是还是可以学习一下框架的设计思想。对于 Beego 框架的评价总是各种各样,这也要看自己的选择了。之所以选择 Beego 框架来入门,主要是因为其详细的文档以及教程示例非常多。

Go Web 初探

先看一下最基本的 Go 中的 web 服务,只用到了 Go 中的 net/http 这个包:

  1. package main
  2. import (
  3. 'fmt'
  4. 'net/http'
  5. 'strings'
  6. 'log'
  7. )
  8. func sayhelloName(w http.ResponseWriter, r *http.Request) {
  9. r.ParseForm() //解析参数,默认是不会解析的
  10. fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息
  11. fmt.Println('path', r.URL.Path)
  12. fmt.Println('scheme', r.URL.Scheme)
  13. fmt.Println(r.Form['url_long'])
  14. for k, v := range r.Form {
  15. fmt.Println('key:', k)
  16. fmt.Println('val:', strings.Join(v, ''))
  17. }
  18. fmt.Fprintf(w, 'Hello astaxie!') //这个写入到w的是输出到客户端的
  19. }
  20. func main() {
  21. http.HandleFunc('/', sayhelloName) //设置访问的路由
  22. err := http.ListenAndServe(':9090', nil) //设置监听的端口
  23. if err != nil {
  24. log.Fatal('ListenAndServe: ', err)
  25. }
  26. }

执行 go run web.go根据提示在浏览器地址栏打开 URL ,如下图所示:

安装 Go 以及 Beego

基本的你得有个 Go 语言的环境,安装什么的就不讲了。只是最后配置其环境变量许多人都容易弄错,包括我自己也是。其实多次也能够配置好,只是每次重新启动就提示上次的配置无效,也不知道是怎么回事。讲一下安装 Beego 框架

  1. export GOBIN='/usr/local/go/bin'
  2. export GOPATH='/Users/allenwu/GoProjects'
  3. export PATH='$PATH:$GOBIN:$GOPATH/bin'

在终端输入如上所示代码,其中 allenwu 替换成你自己的 username,并且在根目录下创建 GoProjects 文件夹,作为下一步工作目录。配置好之后,输入如下命令确保保存成功:

source ~/.zshrc

最后当然要测试一下环境变量是否配置成功,在 shell 中输入 go env若如下所示即表明成功(着重注意一下的就是 gopath 是不是为空):

配置环境没问题之后,就是安装 go 和 bee 工具了:

  1. $ go get github.com/astaxie/beego
  2. $ go get github.com/beego/bee

检查安装是否成功,启动一个 Hello world级别的 App:

  1. $ cd $GOPATH/src
  2. $ bee new hello
  3. $ cd hello
  4. $ bee run hello

会提示你在浏览器输入地址,然后就能知道是否安装成功啦。

体验 Beego 框架

如下图所示即为 Beego 官网所提供的 Beego 框架概览,一眼就能明白其 MVC 模式的构造,结构也是非常清晰的。

安装好 Beego 框架之后,官方给了三个 samples,我们选择其中一个来进行入门体验一下。如下实例选择的是 todo App。我们将 clone 下来的 todo App 放置到指定目录下,用 sublimeText3 打开这个示例项目,强烈建议你打开侧边栏设置选项:

了解完基本的结构之后,我们启动这个 App。我们采用 Beego 提供的工具 bee 来启动。进入到最终的指定文件夹 todo 之后,执行 bee run 命令:

可以看到打印出一个 Bee 的 Logo,表示启动成功了,稍等一下就会继续提示你在浏览器中输入指定 IP 地址和端口号,也就是如下所示:

官方讲这个小 App 结合了 Angular ,体验还是挺不错的。接下来我们来简单分析一下示例 App 的代码结构。首先入口程序是 Main.go,这是想都不用想的,一个程序员的直觉:

  1. package main
  2. import (
  3. 'github.com/astaxie/beego'
  4. // 注释一
  5. 'samples/todo/controllers'
  6. )
  7. func main() {
  8. // 注释二
  9. beego.Router('/', &controllers.MainController{})
  10. beego.Router('/task/', &controllers.TaskController{}, 'get:ListTasks;post:NewTask')
  11. beego.Router('/task/:id:int', &controllers.TaskController{}, 'get:GetTask;put:UpdateTask')
  12. // 注释三
  13. beego.Run()
  14. }

我们第一感觉还是看到 Main() 函数,看到了 Router() 函数,有一些 web 开发或者开发经验的应该都知道这是路由机制。对应的是 url 与 Controller。在 MVC 框架中 Controller 是一个很重要的概念了。我们自然下一步骤就是去往 Controller 中看看:

  1. package controllers
  2. import (
  3. 'github.com/astaxie/beego'
  4. )
  5. // 注释一
  6. type MainController struct {
  7. beego.Controller
  8. }
  9. // 注释二
  10. func (this *MainController) Get() {
  11. // 注释三
  12. this.TplName = 'index.html'
  13. this.Render()
  14. }

在看完 Go 的基本语法之后,看到注释一应该也能明白一个一二三四了,我们声明了一个控制器 MainController,这个控制器里面内嵌了 beego.Controller,这就是 Go 的嵌入方式,也就是 MainController 自动拥有了所有 beego.Controller 的方法。而 beego.Controller 拥有很多方法,其中包括 InitPreparePostGetDeleteHead等 方法。我们可以通过重写的方式来实现这些方法,而我们上面的代码就是重写了 Get 方法。

在注释三处,我们看到了 index.html,应该明白了 Get 方法去获取对应名称的 HTML 文件,并进行渲染。到这里我们很简单的讲述了一下 MVC 中的 V 和 C,发现没,Model 竟然不知道从哪去讲。还请回头看看 Main.go 中的注释二处:

  1. beego.Router('/task/', &controllers.TaskController{}, 'get:ListTasks;post:NewTask')

上述路由引导我们进入了 TaskController 这个控制器来了,我们分析一下下面这个文件:

  1. package controllers
  2. import (
  3. 'encoding/json'
  4. 'strconv'
  5. 'github.com/astaxie/beego'
  6. 'samples/todo/models'
  7. )
  8. type TaskController struct {
  9. beego.Controller
  10. }
  11. // Example:
  12. //
  13. // req: GET /task/
  14. // res: 200 {'Tasks': [
  15. // {'ID': 1, 'Title': 'Learn Go', 'Done': false},
  16. // {'ID': 2, 'Title': 'Buy bread', 'Done': true}
  17. // ]}
  18. func (this *TaskController) ListTasks() {
  19. res := struct{ Tasks []*models.Task }{models.DefaultTaskList.All()}
  20. this.Data['json'] = res
  21. this.ServeJSON()
  22. }

很明显我们看到了 models 关键字,并且调用了其中的 Task ,我们选择进入 Task.go 文件看看:

  1. package models
  2. import (
  3. 'fmt'
  4. )
  5. var DefaultTaskList *TaskManager
  6. // Task Model
  7. type Task struct {
  8. ID int64 // Unique identifier
  9. Title string // Description
  10. Done bool // Is this task done?
  11. }
  12. // NewTask creates a new task given a title, that can't be empty.
  13. func NewTask(title string) (*Task, error) {
  14. if title == '' {
  15. return nil, fmt.Errorf('empty title')
  16. }
  17. return &Task{0, title, false}, nil
  18. }
  19. // TaskManager manages a list of tasks in memory.
  20. // 注释一
  21. type TaskManager struct {
  22. tasks []*Task
  23. lastID int64
  24. }
  25. // NewTaskManager returns an empty TaskManager.
  26. func NewTaskManager() *TaskManager {
  27. return &TaskManager{}
  28. }
  29. // Save saves the given Task in the TaskManager.
  30. func (m *TaskManager) Save(task *Task) error {
  31. if task.ID == 0 {
  32. m.lastID++
  33. task.ID = m.lastID
  34. m.tasks = append(m.tasks, cloneTask(task))
  35. return nil
  36. }
  37. for i, t := range m.tasks {
  38. if t.ID == task.ID {
  39. m.tasks[i] = cloneTask(task)
  40. return nil
  41. }
  42. }
  43. return fmt.Errorf('unknown task')
  44. }
  45. // cloneTask creates and returns a deep copy of the given Task.
  46. func cloneTask(t *Task) *Task {
  47. c := *t
  48. return &c
  49. }
  50. // All returns the list of all the Tasks in the TaskManager.
  51. func (m *TaskManager) All() []*Task {
  52. return m.tasks
  53. }
  54. // Find returns the Task with the given id in the TaskManager and a boolean
  55. // indicating if the id was found.
  56. func (m *TaskManager) Find(ID int64) (*Task, bool) {
  57. for _, t := range m.tasks {
  58. if t.ID == ID {
  59. return t, true
  60. }
  61. }
  62. return nil, false
  63. }
  64. func init() {
  65. DefaultTaskList = NewTaskManager()
  66. }

如上所示的 task Model 主要就是定义了 task 这个实体该有的成员变量。以及一个 taskManager 来管理这些 task,其整体结构在理解了 Go 语言的一些基本的机制之后还是比较简单的。

在之前的整个实例结构中,我们还看到了如下所示的静态文件,它们的作用就很明显啦:

  1. ├── static
  2. │ ├── css
  3. │ ├── img
  4. │ └── js

好了,以上就是 Go 的一个框架 Beego 的入门实例了,其实很简单。我也只是简单的写一下入门的东西。后续研究一下 Go 的自动化 API 构建。往后继续学习 Go 和 Docker 的结合应用吧。

【参考文章】

1、Go中国技术社区 - golang https://gocn.io/
2、首页 - beego: 简约 & 强大并存的 Go 应用框架 https://beego.me/
3、beego:从入门到放弃 -  http://blog.csdn.net/github_37320188/article/details/79107380
(0)

相关推荐