语言无好坏,框架无大小,尽在开发者对软件工程三要素过程、方法、工具的理解,需求就是问题,问题的解决,需要人去思考分析问题,需要人去设计解决问题的过程步骤,需要人去思考每个过程步骤环节有哪些解决方法方案,采用哪个方法会更优,每个方法方案可以使用什么工具来提高执行效率,从而在高效率、低成本、可维护下解决问题。

beego有的,gin也能实现。

虽然本文大部分时间都是介绍beego的模块,但如果是团队,有能力的团队,特别是并指望用go实现页面渲染的mvc架构的,只把go用于中间层,比如复杂业务逻辑的实现部分提供接口,建议采用gin框架。

目录

gin

gin很简洁高效,就像日本的丰田、本田、日产等,这些品牌值高,三大件高效可靠,但这些汽车的内饰、智能方面不足,也因为如此,gin支持各种第三方模块,gin是一个基地,高楼大厦第三方模块来搭建。

其他抽象程度较高的语言,比如java、php、c++、python等层级更高的语言,都有一些业内常用普及的一些框架,甚至称为企业级框架,而框架是为了减少开发者/公司团队在业务实现以外不必要的精力关心,把更多精力放在业务实现进阶和后期维护上,但重框架不好的地方在于学习成本较高,当然如果框架在语言市场上占有率很高的话,对于团队来说更换人员的成本不会太高,但如果框架相对来说小众的话,更换人员的成本就会比较高。

而golang诞生的一个原因就是为了避免依赖太重的框架,beego相对gin来说,属于定制较深,或说封装层级较高的框架,很多人都说beego已经不大像golang语言了,可能就是门面的封装,一方面让开发者更容易入手web开发,另一方面封装使得开发者没有太多机会接触原生golang,其实大部分语言都会走向这个方向,毕竟低门槛才会引来更多的开发者。

gin对于开发者来说,没有太重的封装,保持更多golang的味道,也保持高效与定制能力。适合工具项目,适合对语言了解程度较深的开发者或团队。

  • 当某个接口性能遭到较大的挑战,考虑用Gin重写
  • 如果项目的规模不大,业务相对简单,适用Gin

gin没有太多可以说的,一切简单到1小时就能看完的文档:

Documentation | Gin Web Framework

gin框架 · Go语言中文文档

beego

beego功能丰富,就像国产的长城、吉利、长安等,虽然三大件不如gin,但在使用友好方面、符合国内时代场景,特别是web场景。beego自己买地自己建楼自己买材料自己设计自己装修,剩下的软装开发者你自己来,甚至提供工具上门。

如果是做web或api项目,在国内讲究快速实现快速验证快速推出原则,建议使用beego。beego里有的模块或功能,不能说其他框架没有,只是beego直接内置了或指定了或建议了,避免开发者陷入选择或自己设计维护的困境。

注意:beego官方文档,不少地方都丢失了细节,略显仓促的文档,有时需要中文英文文档相互对比着看。

beego框架

  • 架构图

    https://beego.me/docs/images/architecture.png https://beego.me/docs/images/architecture.png

  • 执行逻辑

    https://beego.me/docs/images/flow.png

  • 典型mvc目录结构

    ├── conf
    │   └── app.conf
    ├── controllers
    │   ├── admin
    │   └── default.go
    ├── main.go
    ├── models
    │   └── models.go
    ├── static
    │   ├── css
    │   ├── ico
    │   ├── img
    │   └── js
    └── views
        ├── admin
        └── index.tpl
    
  • 安装

    #安装
    go get github.com/beego/beego/v2@latest
    
    #升级
    go get -u github.com/beego/beego/v2
    

beego 安装升级 - beego: 简约 & 强大并存的 Go 应用框架

bee工具

bee提供了一些命令,支持开发快速搭建项目

go get -u github.com/beego/bee/v2
Usage:

    bee command [arguments]

The commands are:

    version     show the bee & beego version
    migrate     run database migrations
    api         create an api application base on beego framework
    bale        packs non-Go files to Go source files    
    new         create an application base on beego framework
    run         run the app which can hot compile
    pack        compress an beego project
    fix         Fixes your application by making it compatible with newer versions of Beego
    dlv         Start a debugging session using Delve
    dockerize   Generates a Dockerfile for your Beego application
    generate    Source code generator
    hprose      Creates an RPC application based on Hprose and Beego frameworks
    pack        Compresses a Beego application into a single file
    rs          Run customized scripts
    run         Run the application by starting a local development server
    server      serving static content over HTTP on port
    
Use bee help [command] for more information about a command.
    

Bee 工具使用

配置

提供了一套用于组织配置的机制,配置中心化,避免配置散乱耦合。

提供了环境配置

配置机制,减少开发者对配置组织的考虑,比如不用去考虑环境配置等问题,把更多精力用于业务逻辑实现。

  • 自定义配置

    conf/mini.conf

    [shehui]
        app_id = wxf0f13956e2d18xxx
        app_secret = app_secretxxxx
        name = shehui
        key = shehui
        version = 1
    

    在conf/app.conf包含新增的mini.conf自定义配置文件

    appname = pdd-mini-go
    httpport = 8080
    runmode = dev
    autorender = false
    copyrequestbody = true
    EnableDocs = true
    sqlconn = 
      
    inlcude mini.conf
    
  • 读取配置

    appname, _ := beego.AppConfig.String("appname")
    minname, _ := beego.AppConfig.String("shehui::name")
    
  • json配置读取

    参考:golang读取json配置文件

配置 - beego

路由

丰富的路由设置,默认支持RESTful,有常规的get、post等路由设置,有自定义路由,有autorouter,支持正则路由,支持注解路由,支持表达式路由,支持命名空间,没有你想要的他没有的路由。

  • RESTful式的路由

    RESTful式注意的地方就是只指定到控制器,剩下的方法由http metho方法名决定。

    • 固定路由
    • 正则路由
    • 自定义方法
  • 自动匹配控制器与方法名

  • 注解路由

  • 命名空间

    命名空间的方式需要配合注解路由实现

    ns := beego.NewNamespace("/v1",
        beego.NSNamespace("/object",
            beego.NSInclude(
                &controllers.ObjectController{},
            ),
        ),
        beego.NSNamespace("/user",
            beego.NSInclude(
                &controllers.UserController{},
            ),
        ),
    )
    beego.AddNamespace(ns)
    
    ns2 := beego.NewNamespace("/shehui",
        beego.NSNamespace("/index",
            beego.NSInclude(
                &controllers.IndexController{},
            ),
        ),
    )
    beego.AddNamespace(ns2)
    

    controllers/index.go中定义的Login方法,增加注解路由:

    // @router /login [post]
    func (this *IndexController) Login() {
    }
    

    controllers/user.go中定义相关方法,并注解路由:

    // @router /:uid [get]
    func (u *UserController) Get() {
    }
    // @router / [get]
    func (u *UserController) GetAll() {
          
    }
    // @router / [post]
    func (u *UserController) Post() {
    }
    

    比如:通过post访问/shehui/index/login将路由到index控制器的Login方法;通过get访问/v1/user/123将路由到user控制器中的Get方法,通过get访问/v1/user/将路由到user控制器的GetAll方法,通过post访问/v1/user/将路由到user控制器的Post方法。

路由 - beego

Controller

  • mvc架构

    beego默认用于mvc架构项目,适合web或api项目,延续其他语言大多框架的mvc文件结构组织方式,减少从其他语言转过来的开发者学习门槛,特别是php开发者。

  • 控制器

    beego的控制器实现了很多常用的方法,也确定了这些方法名,避免每个开发者的各自取名定义,让开发规范进一步规范化,通过规模化生产个性化的输出。

    实现的接口方法,比如Prepare、Get、Finish、Render、IsAjax等

    控制器函数 - beego

  • 为web提供了XSRF过滤方案

    轻松解决跨站请求伪造安全问题。

    XSRF 过滤 - beego: 简约 & 强大并存的 Go 应用框架

  • 请求数据处理

    控制器也实现了获取请求数据的方法,比如Controller.GetString("name")GetIntGetFloat等方法,也可以通过Controller.Input().Get("id")获取。

    也可以定义一个结构体,并解析到结构体,同时通过结构体标签tag还支持对数据的验证,比如是否必须、是否为空、是否xx类型等,类似过滤中间件

    也帮开发者封装了获取Request Body中的内容,目前很多场景都是需要从body中获取携带的请求json或xml数据。

    同时在控制器里也可以控制文件上传的相关配置,比如上传大小,还可以获取上传文件的相关信息,用于判断过滤。前面说了控制实现了很多接口方法,其中就有SaveToFile()可以用于保存上传的文件。

    这些对web开发者来说省去了很多烦恼,更关注于业务逻辑的设计与实现。

    请求数据处理 - beego: 简约 & 强大并存的 Go 应用框架

  • session控制

    简化session的开启、存储引擎、设置、获取、删除操作

    session 控制 - beego: 简约 & 强大并存的 Go 应用框架

  • 过滤器

    beego 支持自定义过滤中间件,例如安全验证,强制跳转等。

    web.InsertFilter(pattern string, pos int, filter FilterFunc, opts ...FilterOpt)
    

    看下过滤器函数的定义,就可以感受到中间件可以实现各种有趣的功能。

    同时在新版本也支持了类责任链的设计模式filterChain

    过滤器 - beego: 简约 & 强大并存的 Go 应用框架

  • flash

    flash 用于在两个逻辑间传递临时数据,flash 中存放的所有数据会在紧接着的下一个逻辑中调用后清除。一般用于传递提示和错误消息。它适合 Post/Redirect/Get 模式。

    具体场景,比如早期web页面的渲染,成功或错误跳转页面的渲染,需要上一个逻辑提供成功或错误的相关信息,此时就需要一个临时信息存储,供给下一个逻辑页面渲染;再比如访问一个需要权限访问的页面,此时通过flash临时保存当前访问页面地址,并跳转到登录页面,登录逻辑成功后,会通过flash取得目标地址,再跳转到这个目标地址上。

    flash 数据 - beego: 简约 & 强大并存的 Go 应用框架

  • URL构建

    web项目跳转或生成url目标地址通过需要一个标准的函数或方法提供URL构建,保证可以统一调整及协同。

    URL构建有几个好处:

    • 有个统一的地方调整URL,债有主
    • URL构建更统一处理不安全的字符等
    • 代码更优雅,编码更快捷

    甚至可以在模板文件中使用URL构建

    URL构建 - beego: 简约 & 强大并存的 Go 应用框架

  • 支持多种格式的数据输出

    支持XML、JSON、JSONP、YAML这些流行的常用的数据输出格式

    比如JSON 数据直接输出:

    func (this *AddController) Get() {
        mystruct := { ... }
        this.Data["json"] = &mystruct
        this.ServeJSON()
    }
    

    调用 ServeJSON 之后,会设置 content-type 为 application/json,然后同时把数据进行 JSON 序列化输出。

    大大简化了web应用层编码负担,不是难度,毕竟不需要自己再去设计与维护这些格式输出,只需要去设计封装要输出的数据结构。

    当然数据结构的输出,还是存在很多意想不到的槛,比如结构体中的大小写、类型对应json格式的问题。

  • 数据验证

    数据验证,常用实现逻辑是:

    • 定义数据验证规则
    • 执行数据验证
    • 返回错误信息或继续执行

    在beego中,有两种定义验证规则方式,一种是通过数据验证模块方法:

    u := User{"man", 40}
    valid := validation.Validation{}
    valid.Required(u.Name, "name")
    valid.MaxSize(u.Name, 15, "nameMax")
    valid.Range(u.Age, 0, 18, "age")
    

    这种方式,看起来代码有点繁琐。

    还有一种通过结构体的标签tag来定义验证规则:

    // 验证函数写在 "valid" tag 的标签里
    // 各个函数之间用分号 ";" 分隔,分号后面可以有空格
    // 参数用括号 "()" 括起来,多个参数之间用逗号 "," 分开,逗号后面可以有空格
    // 正则函数(Match)的匹配模式用两斜杠 "/" 括起来
    // 各个函数的结果的 key 值为字段名.验证函数名
    type user struct {
        Id     int
        Name   string `valid:"Required;Match(/^Bee.*/)"` // Name 不能为空并且以 Bee 开头
        Age    int    `valid:"Range(1, 140)"` // 1 <= Age <= 140,超出此范围即为不合法
        Email  string `valid:"Email; MaxSize(100)"` // Email 字段需要符合邮箱格式,并且最大长度不能大于 100 个字符
        Mobile string `valid:"Mobile"` // Mobile 必须为正确的手机号
        IP     string `valid:"IP"` // IP 必须为一个正确的 IPv4 地址
    }
    

    对于通过结构体标签定义验证规则,执行验证:

    func main() {
        valid := validation.Validation{}
        u := user{Name: "Beego", Age: 2, Email: "dev@web.me"}
        b, err := valid.Valid(&u)
        if err != nil {
            // handle error
        }
        if !b {
            // validation does not pass
            // blabla...
            for _, err := range valid.Errors {
                log.Println(err.Key, err.Message)
            }
        }
    }
    

    更多结构体标签可用的验证函数详见官方文档:

    表单数据验证 - beego: 简约 & 强大并存的 Go 应用框架

  • 错误处理

    这里的错误处理,我们把他理解成web的错误处理会更好,就是为了开发者更快捷的返回404、500等类似错误页面而提供的错误处理机制。

    内置了错误处理方法与模板,同时也允许开发者自定义错误处理方法与模板。

    错误处理 - beego: 简约 & 强大并存的 Go 应用框架

Model

beego自带了一个ORM框架,但仍处于开发阶段,参考了Django的ORM和SQLAlchemy。

也可以考虑第三方的orm,比如xorm、GORM等

  • 基础的CRUD也都有

    CRUD 操作 - beego: 简约 & 强大并存的 Go 应用框架

  • 高级查询

    php框架里也都有ORM的高级查询,这些高级查询其实都是定义了规则,开发者遵循规则去设置查询条件,调用相关方法,就是很需要记忆。

  • 支持原生sql

    在一些怪异或复杂的查询语句,可以考虑原生的sql执行

  • 有语义的构造查询

    QueryBuilder 在功能上与 ORM 重合, 但是各有利弊。ORM 更适用于简单的 CRUD 操作,而 QueryBuilder 则更适用于复杂的查询,例如查询中包含子查询和多重联结。

    个人很喜欢任何框架的查询构造器,因为可以像个厨师做自己想做的菜。

    构造查询 - beego: 简约 & 强大并存的 Go 应用框架

    // 构建查询对象
    qb.Select("user.name",
        "profile.age").
        From("user").
        InnerJoin("profile").On("user.id_user = profile.fk_user").
        Where("age > ?").
        OrderBy("name").Desc().
        Limit(10).Offset(0)
    
    // 导出 SQL 语句
    sql := qb.String()
    
    // 执行 SQL 语句
    o := orm.NewOrm()
    o.Raw(sql, 20).QueryRows(&users)
    
  • 支持事务处理

    事务处理 - beego: 简约 & 强大并存的 Go 应用框架

    闭包方式事务处理,可以做到自动提交与回滚,普通方式需要开发者手动提交与判断回滚,还要注意关键对象:TxOrm执行的sql才会被认为是在同一个事务中。

  • 模型定义

    复杂的模型定义不是必须的,此功能用作数据库数据转换和自动建表

    orm模型,相当于将表信息模型化。

    模型定义 - beego: 简约 & 强大并存的 Go 应用框架

View

  • 模板语法

    beego 中使用的模板语法,与 go 模板语法基本相同。

    支持pipeline管道传递:

    {{. | FuncA | FuncB | FuncC}}
    

    支持条件判断、嵌套循环、遍历

    支持定义模板、调用模板

    提供了一些常用的基础函数:and、not、call、or、eq、ne、lt、gt、ge、le等

    模板语法指南 - beego: 简约 & 强大并存的 Go 应用框架

  • 模板处理

    • 缓存

      所有的模板会在 beego 应用启动的时候全部编译然后缓存在 map 里面。

      开发模式下每次都会重新编译。

    • 模板目录

      默认模板目录是views,开发者可以通过beego。ViewsPath配置调整。

    • 自动渲染

      beego内部处理controller与view之间的文件映射关系,可以达到自动渲染的效果。

      autorender = false
      

      api项目不需要自动渲染

    • 模板标签

      默认使用{{}}作为左右标签,但由于一些前端框架也会使用到这个标签,所以beego也支持修改模板标签

    • 模板数据赋值

      模板中的数据是通过在 Controller 中 this.Data 获取的,所以如果你想在模板中获取内容 {{.Content}} ,那么你需要在 Controller 中如下设置:

      this.Data[“Content”] = “value”

      支持golang的各种数据类型

    • 模板名称

      beego支持tpl与html两种后缀,也支持修改

      模板文件的寻找是从模板目录,比如views/开始寻找

      比如

      this.TplName = "admin/add.tpl"
      

      beego会自动渲染views/admin/add.tpl模板

    • Layout

      场景:类管理后台,有左侧导航菜单、顶部导航菜单等类似的系统,通常会需要一个Layout设计

      beego的view也是支持Layout设计的。

    • LayoutSection

      可以用来简化复杂的页面,复用页面模板

    • 表单渲染

      通过renderform函数可以将一个结构体渲染成表单html

    模板处理 - beego: 简约 & 强大并存的 Go 应用框架

  • 模板函数

    beego内置了一些模板函数:date、html2str、compare、renderform、urlfor等等

    也支持开发者自定义模板函数,但必须在web.run()调用之前定义:

    func hello(in string)(out string){
        out = in + "world"
        return
    }
    
    web.AddFuncMap("hi",hello) //定义模板函数
    

    使用自定义模板函数:

    定义之后你就可以在模板中这样使用了
    
    {{.Content | hi}}
    
    
  • 静态文件服务

    Go 语言内部其实已经提供了 http.ServeFile,通过这个函数可以实现静态文件的服务。beego 针对这个功能进行了一层封装,通过下面的方式进行静态文件注册:

    web.SetStaticPath("/static","public")
    

    第一个参数是路径,url 路径信息

    第二个参数是静态文件目录(相对应用所在的目录)

    beego 支持多个目录的静态文件注册,用户可以注册如下的静态文件目录:

    web.SetStaticPath("/images","images") 
    web.SetStaticPath("/css","css") 
    web.SetStaticPath("/js","js")
    

    设置了如上的静态目录之后,用户访问 /images/login/login.png,那么就会访问应用对应的目录下面的 images/login/login.png 文件。

    如果是访问 /static/img/logo.png,那么就访问 public/img/logo.png文件。

    默认情况下 beego 会判断目录下文件是否存在,不存在直接返回 404 页面,如果请求的是 index.html,那么由于 http.ServeFile 默认是会跳转的,不提供该页面的显示。因此 beego 可以设置 web.BConfig.WebConfig.DirectoryIndex=true 这样来使得显示 index.html 页面。而且开启该功能之后,用户访问目录就会显示该目录下所有的文件列表,也就是索引目录。

  • 模板分页

    一个列表页面有几个刚需功能:分页、排序、条件查询

    这三个功能放一起,那这个列表页面就不简单了。所以我们需要一个完整封装好的列表套路,支持我们快速实现列表页面的这些基础功能,在这个基础上进行调整,满足个性化需求,便能提高列表的开发与维护效率。

    模板分页处理 - beego: 简约 & 强大并存的 Go 应用框架

应用部署

  • 独立部署

    golang本身支持tcp、http服务,自身启动应用即可监听http请求。

    比如linux:

    nohup ./beepkg &
    

    windows下,制作bat文件,并设置开机启动即可。

  • nginx

    Golang自身可以作为一个独立的 HTTP 服务器,但是有些时候为了一些服务器的周边工作,例如访问日志、cc 攻击、静态服务、负载均衡等,nginx 已经做的很成熟了,Golang只要专注于业务逻辑和功能就好,所以通过 nginx配置代理就可以实现多应用同时部署,如下就是典型的两个应用共享 80 端口,通过不同的域名访问,反向代理到不同的应用。

    server {
        listen       80;
        server_name  .a.com;
    
        charset utf-8;
        access_log  /home/a.com.access.log;
    
        location /(css|js|fonts|img)/ {
            access_log off;
            expires 1d;
    
            root "/path/to/app_a/static";
            try_files $uri @backend;
        }
    
        location / {
            try_files /_not_exists_ @backend;
        }
    
        location @backend {
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host            $http_host;
    
            proxy_pass http://127.0.0.1:8080;
        }
    }
    
    server {
        listen       80;
        server_name  .b.com;
    
        charset utf-8;
        access_log  /home/b.com.access.log  main;
    
        location /(css|js|fonts|img)/ {
            access_log off;
            expires 1d;
    
            root "/path/to/app_b/static";
            try_files $uri @backend;
        }
    
        location / {
            try_files /_not_exists_ @backend;
        }
    
        location @backend {
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host            $http_host;
    
            proxy_pass http://127.0.0.1:8081;
        }
    }
    
  • apahce

    用apache的原因和nginx是相似的,我们更建议使用nginx。

    apache 部署 - beego: 简约 & 强大并存的 Go 应用框架

  • supervisord

    supervisor 部署 - beego: 简约 & 强大并存的 Go 应用框架

热升级

热升级和热编译是不同的概念,热编译是通过监控文件的变化重新编译,然后重启进程,例如 bee run 就是这样的工具。

了解 nginx 的同学都知道,nginx 是支持热升级的,可以用老进程服务先前链接的链接,使用新进程服务新的链接,即在不停止服务的情况下完成系统的升级与运行参数修改

在web服务中热升级是很有必要的,我们的目标就是为了不终止web服务,但在分布式高并发场景下,web服务可能会出问题,这些属于高可用的范畴,我们可以通过其他其他策略来弥补。

grace模块为beego提供了一个热重启的模块。

grace 模块 - beego: 简约 & 强大并存的 Go 应用框架

进程内监控

这个中文文档翻译的不够准确,也显得生硬不接地气,英文live monitor,我们可以理解为对项目的实时监控。

  • 开启监控

    beego的实时项目监控默认是关闭的,需要同配置开启:

    #开启监控
    EnableAdmin = true
    # 修改监控实时查看监听地址
    AdminAddr = "localhost"
    AdminPort = 8088
    

    如需要,可以通过反向代理,使得外网可以访问项目实时监控。

  • 监控内容

    • Request statistics

      请求统计信息

    • Performance profiling

      可以查看性能相关信息,有助于性能调优

    • Health Check

      手动注册相应的健康检查逻辑,就可以通过http://localhost:8088/healthcheck 获取当前执行的健康检查状态

      关于如何添加相应的健康检查逻辑,详见admin模块

    • Tasks

      开发者需要添加task,才能执行相应的任务检查和手动触发任务

      检查任务状态 URL:http://localhost:8088/task

      手工执行任务 URL:http://localhost:8088/task?taskname=任务名

      如何添加task,详见task模块。v1.x版本admin和task模块都归属在toolbox模块下,v2.x开始做了分离。

    • Config Status

      应用开发完毕之后,我们可能需要知道在运行的进程到底是怎么样的配置,beego 的监控模块提供了这一功能。

      显示所有的配置信息: http://localhost:8088/listconf?command=conf

      显示所有的路由配置信息: http://localhost:8088/listconf?command=router

      显示所有的过滤设置信息: http://localhost:8088/listconf?command=filter

进程内监控 - beego: 简约 & 强大并存的 Go 应用框架

API自动化文档

自动化文档对于团队开发是一把好用的利器,有助于编码规范,有助于内部协同,适合敏捷开发理念:

Working software over comprehensive documentation

软件能够运行 优于 详尽的文档

那现在我们能运行,还顺带有了详尽的api文档,不需要额外更换场景去编写文档,费时费力。

当然自动化文档对编码有一点的要求:

  • 在router.go全局设置

    比如官方API项目模板:

    // @APIVersion 1.0.0
    // @Title beego Test API
    // @Description beego has a very cool tools to autogenerate documents for your API
    // @Contact astaxie@gmail.com
    // @TermsOfServiceUrl http://beego.me/
    // @License Apache 2.0
    // @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html
    

    全局的注释如上所示,是显示给全局应用的设置信息.

  • 路由解析要求

    如果需要支持自动化文档,那么路由解析只能通过命名空间namespace的方式进行路由解析。

    其他写法函数不会自动解析,即 namespace+Include 的写法,而且只支持二级解析,一级版本号,二级分别表示应用模块。

    ns := beego.NewNamespace("/v1",
        beego.NSNamespace("/object",
            beego.NSInclude(
                &controllers.ObjectController{},
            ),
        ),
        beego.NSNamespace("/user",
            beego.NSInclude(
                &controllers.UserController{},
            ),
        ),
    )
    beego.AddNamespace(ns)
    
  • 应用注释要求

    看一个官方模板中的UserController中的Get方法注释:

    // @Title Get
    // @Description get user by uid
    // @Param	uid		path 	string	true		"The key for staticblock"
    // @Success 200 {object} models.User
    // @Failure 403 :uid is empty
    // @router /:uid [get]
    func (u *UserController) Get() {
        uid := u.GetString(":uid")
        if uid != "" {
            user, err := models.GetUser(uid)
            if err != nil {
                u.Data["json"] = err.Error()
            } else {
                u.Data["json"] = user
            }
        }
        u.ServeJSON()
    }
    

    详细含义参见官方文档API 自动化文档 - beego: 简约 & 强大并存的 Go 应用框架

  • 自动生成文档

    • 开启应用内文档开关,在配置文件中设置:EnableDocs = true,

    • 执行自动生成文档命令

      bee run -gendoc=true -downdoc=true
      

      让 API 应用跑起来,-gendoc=true 表示每次自动化的 build 文档,-downdoc=true 就会自动的下载 swagger 文档查看器

    • 查看

      访问API应用:http://localhost:8080/swagger/

API 自动化文档 - beego: 简约 & 强大并存的 Go 应用框架

cache模块

beego的cache模块只为了满足简单的数据缓存效果,支持Set、Get、Delete、Incr、Decr、IsExist、GetMulti、Put、ClearAll、SatrtAndGC方法

支持4种驱动引擎:memory、file、memcache、redis

目前项目呼声较高的一般是redis,毕竟redis除了数据缓存外,还支持多种数据结构,比如队列、hash、链表、订阅及事务。

一般建议使用第三方开源的redis库: github.com/garyburd/redigo/redis,当然beego缓存模块中redis也是基于redigo。go操作Redis · Go语言中文文档

cache 模块 - beego: 简约 & 强大并存的 Go 应用框架

logs模块

Go内置的log库功能有限,例如无法满足记录不同级别日志的情况,我们在实际的项目中根据自己的需要选择使用第三方的日志库,如logrus、zap等。

beego也提供了这样的日志模块,支持多种引擎日志写入。

  • 范例

    logs一般使用全局通用,也就是单例,但也可以存在多个实例

    package main
    
    import (
        "github.com/beego/beego/v2/core/logs"
    )
    
    func main() {    
        //an official log.Logger 一个实例
        l := logs.GetLogger()
        l.Println("this is a message of http")
        //an official log.Logger with prefix ORM 另一个实例
        logs.GetLogger("ORM").Println("this is a message of orm")
    
        //全局logs
        logs.Debug("my book is bought in the year of ", 2016)
        logs.Info("this %s cat is %v years old", "yellow", 3)
        logs.Warn("json is a type of kv like", map[string]int{"key": 2016})
        logs.Error(1024, "is a very", "good game")
        logs.Critical("oh,crash")
    
    
        //还可以这样实例化一个log
        log := logs.NewLogger()
        log.SetLogger(logs.AdapterConsole)
        log.Debug("this is a debug message")
    }
    
    
  • 支持异步

    You can set logger to asynchronous logging to improve performance:

    logs.Async()
    

    Add a parameter to set the length of buffer channel

    logs.Async(1e3)
    
  • 引擎配置

    • console 命令行输出,默认输出到os.Stdout

        logs.SetLogger(logs.AdapterConsole, `{"level":1,"color":true}`)
      

      主要的参数如下说明:

      • level 输出的日志级别
      • color 是否开启打印日志彩色打印(需环境支持彩色输出)
    • file

      设置的例子如下所示:

      logs.SetLogger(logs.AdapterFile, `{"filename":"test.log"}`)
      

      主要的参数如下说明:

      • filename 保存的文件名
      • maxlines 每个文件保存的最大行数,默认值 1000000
      • maxsize 每个文件保存的最大尺寸,默认值是 1 « 28, //256 MB
      • daily 是否按照每天 logrotate,默认是 true
      • maxdays 文件最多保存多少天,默认保存 7 天
      • rotate 是否开启 logrotate,默认是 true
      • level 日志保存的时候的级别,默认是 Trace 级别
      • perm 日志文件权限
    • multifile

      设置的例子如下所示:

      logs.SetLogger(logs.AdapterMultiFile, `{"filename":"test.log","separate":["emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"]}`)
      

      主要的参数如下说明(除 separate 外,均与file相同):

      • filename 保存的文件名
      • maxlines 每个文件保存的最大行数,默认值 1000000
      • maxsize 每个文件保存的最大尺寸,默认值是 1 « 28, //256 MB
      • daily 是否按照每天 logrotate,默认是 true
      • maxdays 文件最多保存多少天,默认保存 7 天
      • rotate 是否开启 logrotate,默认是 true
      • level 日志保存的时候的级别,默认是 Trace 级别
      • perm 日志文件权限
      • separate 需要单独写入文件的日志级别,设置后命名类似 test.error.log

    更多引擎配置详见官方文档,还支持conn网络存储、smtp邮箱发送、Elasticsearch、Slack

  • 日志格式

    支持自定日志格式,详见官方文档

logs 模块 - beego: 简约 & 强大并存的 Go 应用框架

httplib客户端请求

Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现。

而beego提供httplib 库主要用来模拟客户端发送 HTTP 请求,类似于 Curl 工具,支持 JQuery 类似的链式操作。使用起来相当的方便。

客户端发送HTTP请求,想用哪个,看开发者对哪种写法更加顺手。

Http · Go语言中文文档

httplib 模块 - beego: 简约 & 强大并存的 Go 应用框架

context模块

context上下文模块主要是针对 HTTP 请求中,request 和 response 的进一步封装,他包括用户的输入和输出,用户的输入即为 request,context 模块中提供了 Input 对象进行解析,用户的输出即为 response,context 模块中提供了 Output 对象进行输出。

控制器对象都带有Ctx这个上下文对象:

func (this *MainController) Post() {
    jsoninfo := this.GetString("jsoninfo")
    if jsoninfo == "" {
        this.Ctx.WriteString("jsoninfo is empty")
        // this.Ctx.Input.RequestBody
        return
    }
}

上下文涉及到的方法可以参考:context 模块 - beego: 简约 & 强大并存的 Go 应用框架 - input-对象

请求数据处理 - beego: 简约 & 强大并存的 Go 应用框架

task模块

task可以支持我们实现秒级别的定时任务,用于定时汇报进程或goroutine的内存信息,定时触发GC,定时清理一些日志数据等

范例:

  • 初始化task

    
    tk1 := task.NewTask("tk1", "0 12 * * * *", func(ctx context.Context) error { fmt.Println("tk1"); return nil })
      
    //  0 0,10,20,30,40,50 * * * *            每隔 10 分 执行
    //  0 */10 * * * *                     每隔 10 分 执行
    //  0 * 1 * * *                       从 1:0 到 1:59 每隔 1 分钟 执行
    //  0 0 1 * * *                       1:00 执行
    //  0 0 */1 * * *                      毎时 0 分 每隔 1 小时 执行
    //  0 0 * * * *                       毎时 0 分 每隔 1 小时 执行
    //  0 2 8-20/3 * * *                   8:02,11:02,14:02,17:02,20:02 执行
    //  0 30 5 1,15 * *                    1 日 和 15 日的 5:30 执行
    
    

    函数原型:

    NewTask(tname string, spec string, f TaskFunc) *Task

    • tname 任务名称
    • spec 定时任务格式,与linux的crontab规则定义是类似的,区别在于这里支持最小单位是秒,而crontab是分钟
    • f 执行的函数 func() error
  • 测试task是否正常

    可以通过如下的代码运行 TaskFunc,和 定时规则spec 无关,用于检测写的函数是否如预期所希望的这样:

    err := tk.Run()
    if err != nil {
        t.Fatal(err)
    }
    
  • 加入全局计划任务列表

    task.AddTask("tk1", tk1)
    
  • 开始执行全局任务

    task.StartTask()
    defer task.StopTask()
    

task会被列入beego的实时项目监控中任务列表中。详见进程内监控

task 模块 - beego: 简约 & 强大并存的 Go 应用框架

utils模块

我们经常需要打印一些参数进行调试,但是默认的参数打印总是不是很完美,也没办法定位代码行之类的,主要包括了两个函数:

  • Display() 直接打印结果到 console
  • GetDisplayString() 返回打印的字符串

两个函数的功能一模一样,第一个是直接打印到 console,第二个是返回字符串,方便用户存储到日志或者其他存储。

这两个函数和php的print_r结构很相似

$a = ["a","B"];
print_r($a);//直接输出
echo print_r($a,true);//true表示返回输出,由echo输出

task 模块 - beego: 简约 & 强大并存的 Go 应用框架

admin模块

在 v2.x 里面,我们将原本的toolbox拆分为两块,一块是admin,即治理模块;另外一块是task。

go get github.com/beego/beego/v2/core/admin

admin模块中的几个功能:健康检查、性能调试、访问统计、计划任务。

  • 健康检查

    健康检查是用于当你应用于产品环境中进程,检查当前的状态是否正常,例如你要检查当前数据库是否可用,如下例子所示:

    type DatabaseCheck struct {
    }
    
    func (dc *DatabaseCheck) Check() error {
        if dc.isConnected() {
            return nil
        } else {
            return errors.New("can't connect database")
        }
    }
    

    然后就可以通过如下方式增加检测项:

    admin.AddHealthCheck("database",&DatabaseCheck{})
    

    加入之后,我们就可以往管理端口 /healthcheck 发送GET请求:

    $ curl http://localhost:8088/healthcheck    
    * database: OK
    

    如果检测显示是正确的,那么输出 OK,如果检测出错,显示出错的信息。也可以通过浏览器在admin治理后台页面上查看。

  • statistics

    在 v2.x 里面,我们实际上并不建议直接使用admin来收集这种统计信息。只有在你的应用是单机应用,并且只部署少量实例的时候,可以考虑使用这种方式。

    我们推荐的是使用专门的中间件来完成统计的功能,例如opentracing和prometheus。

    我们在 web, httplib, orm 上都提供了对应的Filter来接入这种中间件。

  • profile

    对于运行中的进程的性能监控是我们进行程序调优和查找问题的最佳方法,例如 GC、goroutine 等基础信息。profile 提供了方便的入口方便用户来调试程序,他主要是通过入口函数 ProcessInput 来进行处理各类请求,主要包括以下几种调试:

    • lookup goroutine

      打印出来当前全部的 goroutine 执行的情况,非常方便查找各个 goroutine 在做的事情

    • lookup heap

      用来打印当前 heap 的信息

    • lookup threadcreate

      查看创建线程的信息

    • lookup block

      查看 block 信息:

    • start cpuprof

      开始记录 cpuprof 信息,生产一个文件 cpu-pid.pprof,开始记录当前进程的 CPU 处理信息

    • stop cpuprof

      关闭记录信息

    • get memprof

      开启记录 memprof,生产一个文件 mem-pid.memprof

    • gc summary

      查看 GC 信息

config模块

beego提供了一个用来解析配置文件的库,支持解析ini、json、xml、yaml格式配置文件。

config 模块 - beego: 简约 & 强大并存的 Go 应用框架

国际化

i18n 模块主要用于实现站点或应用的国际化功能,实现多语言界面与反馈,增强用户体验。

  • 国际化流程

    官方文档看都云里雾里的,大概知道怎么回事,但就是蒙蒙的,但基本思路和大部分原因的getText国家化方案是类似的:

    • 语言文件包。local_zh-CN.ini等。
    • 项目启动初始化注册本地化语言包。就是说预加载当前语言包,预先加载所有语言包。
    • 识别或初始化控制器语言。就是说默认使用什么语言或用户指定了什么语言。
    • 调用语言国际化方法输出对应文本内容:this.Tr(format string,args ...interface{}),即可自动进行语言处理。
  • 模板中使用

    我们可以把i18n.Tr方法注册到模板函数中,这样我们就key在模板函数中使用Tr方法了:

    beego.AddFuncMap("i18n", i18n.Tr)
    

    注册完成之后,便可配合 Lang 变量在模板中进行语言处理:

    {{i18n .Lang "hi%d" 12}}
    
  • 支持分组

    分组相当于语言包的命名空间,使得不同模块或应用可以使用相同语言key值,但可能不同的语言value值。比如:

    about = About
    
    [about]
    about = About Us
    

    获取首页的 about:

    {{i18n .Lang "about"}}
    

    获取关于页面的 about:

    {{i18n .Lang "about.about"}}
    
  • .符号歧义处理

    比如,我们定义了个about.,按正常情况,我们会这么获取:

    {{i18n .Lang "about."}}
    

    但这样会引起语言处理失败,所以我们需要键名前缀加上额外的.符号:

    {{i18n .Lang ".about."}}
    
  • 快速复制新语言包

    i18n 模块提供命令行工具 beei18n 来帮助简化开发中的一些步骤。您可以通过以下方式安装:

    go get github.com/beego/i18n/beei18n
    

    命令 sync 允许您使用已经创建好的一个本地化文件为模板,创建或同步其它的本地化文件:

    beei18n sync srouce_file.ini other1.ini other2.ini
    

    该命令可以同时操作 1 个或多个文件。

i18n 模块 - beego: 简约 & 强大并存的 Go 应用框架

更多

插件库 · Go语言中文文档

Go高级 · Go语言中文文档

微服务 · Go语言中文文档

小结

beego有的,gin也能实现。

语言无好坏,框架无大小,尽在开发者对软件工程三要素过程、方法、工具的理解,需求就是问题,问题的解决,需要人去思考分析问题,需要人去设计解决问题的过程步骤,需要人去思考每个过程步骤环节有哪些解决方法方案,采用哪个方法会更优,每个方法方案可以使用什么工具来提高执行效率,从而在高效率、低成本、可维护下解决问题。

虽然本文大部分时间都是介绍beego的模块,但如果是团队,有能力的团队,特别是并指望用go实现页面渲染的mvc架构的,只把go用于中间层,比如复杂业务逻辑的实现部分提供接口,建议采用gin框架。毕竟对于新手或第一次想考虑迁移到golang语境的项目,beego的文档实在不友好,大部分情况下需要翻墙、文档内容不详、看起来不再维护的项目或是老态龙钟的项目,beego想做到laravel、thinkphp等php框架的开发者友好度,还是有很长的路。