Skip to content

Beego

框架介绍

  • 快速开发
  • MVC架构
  • 文档齐全,社区活跃

架构及原理

  • cache
    1. 文件
    2. 内存
    3. memcache
    4. redis
  • config
    1. ini
    2. json
    3. xml
    4. yaml
  • context
    1. request
    2. response
  • httplibs
    1. 支持 GET POST PUT DELETE HEAD
    2. 支持 https
    3. 支持超时设置
    4. 支持文件上传
  • logs
    1. 多种输出引擎
    2. 异步输出
  • orm
  • session
  • toolbox

Beego项目运行基本流程

  • bee new:新建项目结构

    1. 使用bee创建名为elastic的项目
      MacintoshdeMacBook-Pro-139:beego elasticnotes$ bee new elastic
      2023/02/22 18:12:00.346 [D]  init global config instance failed. If you do not use this, just ignore it.  open conf/app.conf: no such file or directory
      2023/02/22 18:12:00 INFO      0001 Generate new project support go modules.
      2023/02/22 18:12:00 INFO      0002 Creating application...
          create   /Users/elasticnotes/Desktop/beego/elastic/go.mod
          create   /Users/elasticnotes/Desktop/beego/elastic/
          create   /Users/elasticnotes/Desktop/beego/elastic/conf/
          create   /Users/elasticnotes/Desktop/beego/elastic/controllers/
          create   /Users/elasticnotes/Desktop/beego/elastic/models/
          create   /Users/elasticnotes/Desktop/beego/elastic/routers/
          create   /Users/elasticnotes/Desktop/beego/elastic/tests/
          create   /Users/elasticnotes/Desktop/beego/elastic/static/
          create   /Users/elasticnotes/Desktop/beego/elastic/static/js/
          create   /Users/elasticnotes/Desktop/beego/elastic/static/css/
          create   /Users/elasticnotes/Desktop/beego/elastic/static/img/
          create   /Users/elasticnotes/Desktop/beego/elastic/views/
          create   /Users/elasticnotes/Desktop/beego/elastic/conf/app.conf
          create   /Users/elasticnotes/Desktop/beego/elastic/controllers/default.go
          create   /Users/elasticnotes/Desktop/beego/elastic/views/index.tpl
          create   /Users/elasticnotes/Desktop/beego/elastic/routers/router.go
          create   /Users/elasticnotes/Desktop/beego/elastic/tests/default_test.go
          create   /Users/elasticnotes/Desktop/beego/elastic/main.go
      2023/02/22 18:12:00 SUCCESS   0003 New application successfully created!
      MacintoshdeMacBook-Pro-139:beego elasticnotes$ ls
      
  • bee run:自动编译部署

    1. 启动elastic项目

      MacintoshdeMacBook-Pro-139:elastic elasticnotes$ bee run
      ______
      | ___ \
      | |_/ /  ___   ___
      | ___ \ / _ \ / _ \
      | |_/ /|  __/|  __/
      \____/  \___| \___| v2.0.4
      2023/02/22 18:14:22 WARN      0001 Running application outside of GOPATH
      2023/02/22 18:14:22 INFO      0002 Using 'elastic' as 'appname'
      2023/02/22 18:14:22 INFO      0003 Initializing watcher...
      github.com/beego/beego/v2
      google.golang.org/protobuf/internal/flags
      google.golang.org/protobuf/internal/set
      google.golang.org/protobuf/internal/fieldnum
      google.golang.org/protobuf/internal/genname
      golang.org/x/sys/internal/unsafeheader
      golang.org/x/mod/semver
      golang.org/x/xerrors/internal
      github.com/shiena/ansicolor
      github.com/beorn7/perks/quantile
      github.com/cespare/xxhash/v2
      google.golang.org/protobuf/internal/pragma
      github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
      golang.org/x/sys/unix
      github.com/pkg/errors
      github.com/mitchellh/mapstructure
      github.com/beego/beego/v2/core/utils
      github.com/beego/beego/v2/core/logs
      github.com/beego/beego/v2/core/admin
      github.com/beego/beego/v2/server/web/session
      gopkg.in/yaml.v2
      github.com/beego/beego/v2/core/config
      github.com/beego/beego/v2/server/web/grace
      github.com/hashicorp/golang-lru
      google.golang.org/protobuf/internal/detrand
      google.golang.org/protobuf/internal/version
      google.golang.org/protobuf/internal/errors
      github.com/prometheus/common/model
      google.golang.org/protobuf/encoding/protowire
      github.com/prometheus/procfs/internal/fs
      google.golang.org/protobuf/reflect/protoreflect
      github.com/prometheus/procfs/internal/util
      github.com/prometheus/procfs
      google.golang.org/protobuf/reflect/protoregistry
      google.golang.org/protobuf/internal/strs
      google.golang.org/protobuf/internal/encoding/text
      google.golang.org/protobuf/internal/encoding/messageset
      google.golang.org/protobuf/internal/mapsort
      google.golang.org/protobuf/internal/fieldsort
      google.golang.org/protobuf/runtime/protoiface
      google.golang.org/protobuf/proto
      google.golang.org/protobuf/internal/descfmt
      google.golang.org/protobuf/internal/descopts
      google.golang.org/protobuf/internal/encoding/defval
      golang.org/x/crypto/acme
      google.golang.org/protobuf/encoding/prototext
      github.com/beego/beego/v2/server/web/context
      google.golang.org/protobuf/internal/filedesc
      golang.org/x/text/transform
      golang.org/x/text/unicode/bidi
      golang.org/x/text/unicode/norm
      github.com/beego/beego/v2/server/web/context/param
      golang.org/x/tools/go/internal/gcimporter
      golang.org/x/text/secure/bidirule
      golang.org/x/tools/internal/event/label
      golang.org/x/tools/internal/event/keys
      golang.org/x/tools/internal/event/core
      golang.org/x/tools/internal/event
      golang.org/x/tools/internal/gocommand
      golang.org/x/tools/go/internal/packagesdriver
      golang.org/x/tools/internal/packagesinternal
      golang.org/x/tools/internal/typesinternal
      google.golang.org/protobuf/internal/encoding/tag
      golang.org/x/xerrors
      google.golang.org/protobuf/internal/impl
      golang.org/x/net/idna
      golang.org/x/tools/go/gcexportdata
      golang.org/x/tools/go/packages
      golang.org/x/crypto/acme/autocert
      google.golang.org/protobuf/internal/filetype
      google.golang.org/protobuf/runtime/protoimpl
      google.golang.org/protobuf/types/known/timestamppb
      google.golang.org/protobuf/types/known/durationpb
      google.golang.org/protobuf/types/known/anypb
      github.com/golang/protobuf/proto
      github.com/golang/protobuf/ptypes/any
      github.com/golang/protobuf/ptypes/duration
      github.com/golang/protobuf/ptypes/timestamp
      github.com/prometheus/client_model/go
      github.com/matttproud/golang_protobuf_extensions/pbutil
      github.com/golang/protobuf/ptypes
      github.com/prometheus/client_golang/prometheus/internal
      github.com/prometheus/common/expfmt
      github.com/prometheus/client_golang/prometheus
      github.com/prometheus/client_golang/prometheus/promhttp
      github.com/beego/beego/v2/server/web
      elastic/controllers
      elastic/routers
      elastic
      2023/02/22 18:14:47 SUCCESS   0004 Built Successfully!
      2023/02/22 18:14:47 INFO      0005 Restarting 'elastic'...
      2023/02/22 18:14:47 SUCCESS   0006 './elastic' is running...
      2023/02/22 18:14:49.236 [I] [parser.go:413]  generate router from comments
      
      2023/02/22 18:14:49.237 [I] [server.go:241]  http server Running on http://:8080
      
      2023/02/22 18:15:06.706 [D] [router.go:955]  |            ::1| 200 |  17.756882ms|   match| GET      /     r:/
      
      2023/02/22 18:15:06.778 [D] [router.go:955]  |            ::1| 200 |  22.617361ms|   match| GET      /static/js/reload.min.js
      

    2. 浏览器访问 localhost 展示如下图片

      Image title
      启动成功示例

  • bee generate:自动生成代码

    1. 连接数据库,自动创建model
      MacintoshdeMacBook-Pro-139:elastic elasticnotes$ bee generate scaffold user -fields="id:int64,name:string,gender:int,age:int" -driver=mysql -conn="elastic:@tcp IP /elastic"
      ______
      | ___ \
      | |_/ /  ___   ___
      | ___ \ / _ \ / _ \
      | |_/ /|  __/|  __/
      \____/  \___| \___| v2.0.4
      2023/02/22 19:03:37 INFO      0001 Do you want to create a 'user' model? [Yes|No] 
      yes
      2023/02/22 19:03:46 INFO      0002 Using 'User' as model name
      2023/02/22 19:03:46 INFO      0003 Using 'models' as package name
          create   /Users/elasticnotes/Desktop/beego/elastic/models/user.go
      2023/02/22 19:03:46 INFO      0004 Do you want to create a 'user' controller? [Yes|No] 
      yes
      2023/02/22 19:03:50 INFO      0005 Using 'User' as controller name
      2023/02/22 19:03:50 INFO      0006 Using 'controllers' as package name
      2023/02/22 19:03:50 INFO      0007 Using matching model 'User'
          create   /Users/elasticnotes/Desktop/beego/elastic/controllers/user.go
      2023/02/22 19:03:50 INFO      0008 Do you want to create views for this 'user' resource? [Yes|No] 
      yes
      2023/02/22 19:03:52 INFO      0009 Generating view...
          create   /Users/elasticnotes/Desktop/beego/elastic/views/user/index.tpl
          create   /Users/elasticnotes/Desktop/beego/elastic/views/user/show.tpl
          create   /Users/elasticnotes/Desktop/beego/elastic/views/user/create.tpl
          create   /Users/elasticnotes/Desktop/beego/elastic/views/user/edit.tpl
      2023/02/22 19:03:52 INFO      0010 Do you want to create a 'user' migration and schema for this resource? [Yes|No] 
      yes
          create   /Users/elasticnotes/Desktop/beego/elastic/database/migrations/20230222_190353_user.go
      2023/02/22 19:03:53 INFO      0011 Do you want to migrate the database? [Yes|No] 
      yes
      
    2. 当前目录结构(高亮的为自动生成的)
      MacintoshdeMacBook-Pro-139:elastic elasticnotes$ tree -L 4
      .
      ├── conf
         └── app.conf
      ├── controllers
         ├── default.go
         └── user.go
      ├── database
         └── migrations
             └── 20230222_190353_user.go
      ├── elastic
      ├── go.mod
      ├── go.sum
      ├── lastupdate.tmp
      ├── main.go
      ├── models
         └── user.go
      ├── routers
         └── router.go
      ├── static
         ├── css
         ├── img
         └── js
             └── reload.min.js
      ├── tests
         └── default_test.go
      └── views
          ├── index.tpl
          └── user
              ├── create.tpl
              ├── edit.tpl
              ├── index.tpl
              └── show.tpl
      
      13 directories, 18 files
      
    3. 自动生成的代码 !!! 自动生成的代码

      package controllers
      
      import (
          "elastic/models"
          "encoding/json"
          "errors"
          beego "github.com/beego/beego/v2/server/web"
          "strconv"
          "strings"
      )
      
      // UserController operations for User
      type UserController struct {
          beego.Controller
      }
      
      // URLMapping ...
      func (c *UserController) URLMapping() {
          c.Mapping("Post", c.Post)
          c.Mapping("GetOne", c.GetOne)
          c.Mapping("GetAll", c.GetAll)
          c.Mapping("Put", c.Put)
          c.Mapping("Delete", c.Delete)
      }
      
      // Post ...
      // @Title Post
      // @Description create User
      // @Param   body        body    models.User true        "body for User content"
      // @Success 201 {int} models.User
      // @Failure 403 body is empty
      // @router / [post]
      func (c *UserController) Post() {
          var v models.User
          json.Unmarshal(c.Ctx.Input.RequestBody, &v)
          if _, err := models.AddUser(&v); err == nil {
              c.Ctx.Output.SetStatus(201)
              c.Data["json"] = v
          } else {
              c.Data["json"] = err.Error()
          }
          c.ServeJSON()
      }
      
      // GetOne ...
      // @Title Get One
      // @Description get User by id
      // @Param   id      path    string  true        "The key for staticblock"
      // @Success 200 {object} models.User
      // @Failure 403 :id is empty
      // @router /:id [get]
      func (c *UserController) GetOne() {
          idStr := c.Ctx.Input.Param(":id")
          id, _ := strconv.ParseInt(idStr, 0, 64)
          v, err := models.GetUserById(id)
          if err != nil {
              c.Data["json"] = err.Error()
          } else {
              c.Data["json"] = v
          }
          c.ServeJSON()
      }
      
      // GetAll ...
      // @Title Get All
      // @Description get User
      // @Param   query   query   string  false   "Filter. e.g. col1:v1,col2:v2 ..."
      // @Param   fields  query   string  false   "Fields returned. e.g. col1,col2 ..."
      // @Param   sortby  query   string  false   "Sorted-by fields. e.g. col1,col2 ..."
      // @Param   order   query   string  false   "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
      // @Param   limit   query   string  false   "Limit the size of result set. Must be an integer"
      // @Param   offset  query   string  false   "Start position of result set. Must be an integer"
      // @Success 200 {object} models.User
      // @Failure 403
      // @router / [get]
      func (c *UserController) GetAll() {
          var fields []string
          var sortby []string
          var order []string
          var query = make(map[string]string)
          var limit int64 = 10
          var offset int64
      
          // fields: col1,col2,entity.col3
          if v := c.GetString("fields"); v != "" {
              fields = strings.Split(v, ",")
          }
          // limit: 10 (default is 10)
          if v, err := c.GetInt64("limit"); err == nil {
              limit = v
          }
          // offset: 0 (default is 0)
          if v, err := c.GetInt64("offset"); err == nil {
              offset = v
          }
          // sortby: col1,col2
          if v := c.GetString("sortby"); v != "" {
              sortby = strings.Split(v, ",")
          }
          // order: desc,asc
          if v := c.GetString("order"); v != "" {
              order = strings.Split(v, ",")
          }
          // query: k:v,k:v
          if v := c.GetString("query"); v != "" {
              for _, cond := range strings.Split(v, ",") {
                  kv := strings.SplitN(cond, ":", 2)
                  if len(kv) != 2 {
                      c.Data["json"] = errors.New("Error: invalid query key/value pair")
                      c.ServeJSON()
                      return
                  }
                  k, v := kv[0], kv[1]
                  query[k] = v
              }
          }
      
          l, err := models.GetAllUser(query, fields, sortby, order, offset, limit)
          if err != nil {
              c.Data["json"] = err.Error()
          } else {
              c.Data["json"] = l
          }
          c.ServeJSON()
      }
      
      // Put ...
      // @Title Put
      // @Description update the User
      // @Param   id      path    string  true        "The id you want to update"
      // @Param   body        body    models.User true        "body for User content"
      // @Success 200 {object} models.User
      // @Failure 403 :id is not int
      // @router /:id [put]
      func (c *UserController) Put() {
          idStr := c.Ctx.Input.Param(":id")
          id, _ := strconv.ParseInt(idStr, 0, 64)
          v := models.User{Id: id}
          json.Unmarshal(c.Ctx.Input.RequestBody, &v)
          if err := models.UpdateUserById(&v); err == nil {
              c.Data["json"] = "OK"
          } else {
              c.Data["json"] = err.Error()
          }
          c.ServeJSON()
      }
      
      // Delete ...
      // @Title Delete
      // @Description delete the User
      // @Param   id      path    string  true        "The id you want to delete"
      // @Success 200 {string} delete success!
      // @Failure 403 id is empty
      // @router /:id [delete]
      func (c *UserController) Delete() {
          idStr := c.Ctx.Input.Param(":id")
          id, _ := strconv.ParseInt(idStr, 0, 64)
          if err := models.DeleteUser(id); err == nil {
              c.Data["json"] = "OK"
          } else {
              c.Data["json"] = err.Error()
          }
          c.ServeJSON()
      }
      
      package main
      
      import (
          "github.com/beego/beego/v2/client/orm/migration"
      )
      
      // DO NOT MODIFY
      type User_20230222_190353 struct {
          migration.Migration
      }
      
      // DO NOT MODIFY
      func init() {
          m := &User_20230222_190353{}
          m.Created = "20230222_190353"
      
          migration.Register("User_20230222_190353", m)
      }
      
      // Run the migrations
      func (m *User_20230222_190353) Up() {
          // use m.SQL("CREATE TABLE ...") to make schema update
          m.SQL("CREATE TABLE user(`id` int(11) DEFAULT NULL,`name` varchar(128) NOT NULL,`gender` int(11) DEFAULT NULL,`age` int(11) DEFAULT NULL)")
      }
      
      // Reverse the migrations
      func (m *User_20230222_190353) Down() {
          // use m.SQL("DROP TABLE ...") to reverse schema update
          m.SQL("DROP TABLE `user`")
      }
      
      package models
      
      import (
          "errors"
          "fmt"
          "reflect"
          "strings"
      
          "github.com/beego/beego/v2/client/orm"
      )
      
      type User struct {
          Id     int64
          Name   string `orm:"size(128)"`
          Gender int
          Age    int
      }
      
      func init() {
          orm.RegisterModel(new(User))
      }
      
      // AddUser insert a new User into database and returns
      // last inserted Id on success.
      func AddUser(m *User) (id int64, err error) {
          o := orm.NewOrm()
          id, err = o.Insert(m)
          return
      }
      
      // GetUserById retrieves User by Id. Returns error if
      // Id doesn't exist
      func GetUserById(id int64) (v *User, err error) {
          o := orm.NewOrm()
          v = &User{Id: id}
          if err = o.QueryTable(new(User)).Filter("Id", id).RelatedSel().One(v); err == nil {
              return v, nil
          }
          return nil, err
      }
      
      // GetAllUser retrieves all User matches certain condition. Returns empty list if
      // no records exist
      func GetAllUser(query map[string]string, fields []string, sortby []string, order []string,
          offset int64, limit int64) (ml []interface{}, err error) {
          o := orm.NewOrm()
          qs := o.QueryTable(new(User))
          // query k=v
          for k, v := range query {
              // rewrite dot-notation to Object__Attribute
              k = strings.Replace(k, ".", "__", -1)
              qs = qs.Filter(k, v)
          }
          // order by:
          var sortFields []string
          if len(sortby) != 0 {
              if len(sortby) == len(order) {
                  // 1) for each sort field, there is an associated order
                  for i, v := range sortby {
                      orderby := ""
                      if order[i] == "desc" {
                          orderby = "-" + v
                      } else if order[i] == "asc" {
                          orderby = v
                      } else {
                          return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
                      }
                      sortFields = append(sortFields, orderby)
                  }
                  qs = qs.OrderBy(sortFields...)
              } else if len(sortby) != len(order) && len(order) == 1 {
                  // 2) there is exactly one order, all the sorted fields will be sorted by this order
                  for _, v := range sortby {
                      orderby := ""
                      if order[0] == "desc" {
                          orderby = "-" + v
                      } else if order[0] == "asc" {
                          orderby = v
                      } else {
                          return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
                      }
                      sortFields = append(sortFields, orderby)
                  }
              } else if len(sortby) != len(order) && len(order) != 1 {
                  return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
              }
          } else {
              if len(order) != 0 {
                  return nil, errors.New("Error: unused 'order' fields")
              }
          }
      
          var l []User
          qs = qs.OrderBy(sortFields...).RelatedSel()
          if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
              if len(fields) == 0 {
                  for _, v := range l {
                      ml = append(ml, v)
                  }
              } else {
                  // trim unused fields
                  for _, v := range l {
                      m := make(map[string]interface{})
                      val := reflect.ValueOf(v)
                      for _, fname := range fields {
                          m[fname] = val.FieldByName(fname).Interface()
                      }
                      ml = append(ml, m)
                  }
              }
              return ml, nil
          }
          return nil, err
      }
      
      // UpdateUser updates User by Id and returns error if
      // the record to be updated doesn't exist
      func UpdateUserById(m *User) (err error) {
          o := orm.NewOrm()
          v := User{Id: m.Id}
          // ascertain id exists in the database
          if err = o.Read(&v); err == nil {
              var num int64
              if num, err = o.Update(m); err == nil {
                  fmt.Println("Number of records updated in database:", num)
              }
          }
          return
      }
      
      // DeleteUser deletes User by Id and returns error if
      // the record to be deleted doesn't exist
      func DeleteUser(id int64) (err error) {
          o := orm.NewOrm()
          v := User{Id: id}
          // ascertain id exists in the database
          if err = o.Read(&v); err == nil {
              var num int64
              if num, err = o.Delete(&User{Id: id}); err == nil {
                  fmt.Println("Number of records deleted in database:", num)
              }
          }
          return
      }
      
      /Users/elasticnotes/Desktop/beego/elastic/views/user/all.tpl