专注app软件定制开发Beego框架学习

1、介绍

beego专注app软件定制开发是一个使用来开发WEB引用的GoWeb框架,专注app软件定制开发该框架起始于2012年,专注app软件定制开发由一位中国的程序员编专注app软件定制开发写并进行公开,专注app软件定制开发其目的就是为大家提供专注app软件定制开发一个高效率的web专注app软件定制开发应用开发框架。

1)特性

(1)简单化:支持,MVC模型;可以使用bee专注app软件定制开发工具来提高开发效率,专注app软件定制开发比如监控代码修改进行热编译,专注app软件定制开发自动化测试代码,专注app软件定制开发以及自动化打包部署等丰富的开发调试功能。

(2)智能化:beego封装了路由模块,支持智能路由,智能监控,并可以监控内存消耗,CPU使用以及goroutine的运行状况,方便开发者对线上应用进行监控分析。

(3)模块化:beego根据功能对代码进行节耦封装,形成了Session,Cache,Log,配置解析,性能监控,上下文操作,ORM等独立的模块,方便开发者进行使用。

(4)高性能:beego采用Go原生的http请求,goroutine的并发效率应付大流量的Web应用和API应用。

2)安装

go get .com/astaxie/beego (下载安装)

git config --global http.sslVerify false (提示https不支持时使用)

go get -u github.com/astaxie/beego (升级)

创建一个beego项目

  1. package main
  2. import "github.com/astaxie/beego"
  3. func main() {
  4. beego.Info("第一个beego案例")
  5. beego.Run("localhost:8080")
  6. }

go build -o hello hello.go

./hello

访问浏览器http://localhost:8080

3)bee工具

协助Beego框架开发项目时进行创建项目,运行项目,热部署等相关的项目管理的工具。安装完之后,bee 可执行文件默认存放在 $GOPATH/bin 里面,所以您需要把 $GOPATH/bin 添加到您的环境变量中

go get github.com/beego/bee (bee工具安装)

bee new <项目名>  创建一个新的项目

bee api <项目名>  开发 API 应用

bee run 命令是监控 beego 的项目

bee pack 用来打包

beego项目结构:

 2、beego程序流程分析

Go语言执行的时候是main包下面的init函数、main函数依次执行。因此,先找到main.go文件。

首先,import导入了两个包,一个是routers,一个是beego。而在routers包前面,可以看到有一个“_”,这表明是引入routers包,并执行init方法。 然后到routers包下看到init方法:

router函数的功能是映射 URL 到 controller,第一个参数是 URL (用户请求的地址),这里注册的是 /,也就是访问的不带任何参数的 URL,第二个参数是对应的 Controller,即将把请求分发到那个控制器来执行相应的逻辑。

现在去这里设置的MainController中去看一下有什么方法:

 MainController结构体及函数声明在default.go文件中。而这里就看到一个Get方法,方法中有三行代码。

一个get请求到了后台以后,什么请求参数都没有,就会被“/”拦截,执行到MainController中的代码,因为是get请求,所以这里自动找到Get函数并进行执行。

在get函数里面,有三句代码,前两句c.Data[]= ""表示设置返回的数据字段及内容,最后一句c.TplName表示设置处理该请求指向某个模板文件,这里指向了index.tpl。


解释:模板文件在views下面,通常的页面都是使用静态的html+css+js等这些静态代码来进行页面的布局,页面效果控制等,而把页面的数据使用变量表示,这样,在进行页面展示的时候,就能够自动的填充页面里面的变量的值;这些静态的代码文件统称为模板文件。每个模板文件就是像一个模板一样,样式效果都固定,只是根据数据不一样进行渲染和展示。


init方法分析完毕后,程序会继续往下执行,就到了main函数,在main函数中执行:beego.Run()代码。分析一下Run代码的逻辑,在Run方法内部,主要做了几件事:

  • 解析配置文件,也就是我们的app.conf文件,比如端口,应用名称等信息。
  • 检查是否开启session,如果开启session,就会初始化一个session对象。
  • 是否编译模板,beego框架会在项目启动的时候根据配置把views目录下的所有模板进行预编译,然后存放在map中,这样可以有效的提高模板运行的效率,不需要进行多次编译。
  • 监听服务端口。根据app.conf文件中的端口配置,启动监听。

3、架构

1)控制层

(1)控制器:controllers

该目录是存放控制器文件的目录,所谓控制器就是控制应用调用哪些业务逻辑,由controllers处理完http请求以后,并负责返回给前端调用者。

beego.Controller 实现了接口 beego.ControllerInterface,该接口存在Init(ct *context.Context, childName string, app interface{})、Prepare()、Get()、Post()等等函数

(2)路由器:routers

所谓路由就是分发的意思,当前端浏览器进行一个http请求达到后台web项目时,必须要让程序能够根据浏览器的请求url进行不同的业务处理,从接收到前端请求到判断执行具体的业务逻辑的过程的工作,就由routers来实现。

在beego框架中,支持四种路由设置,他们分别是:**基础路由**,**固定路由**,**正则路由**和**自动路由**。

基础路由

直接通过beego.Get,beego.POST,beego.Head,beego.Delete等方法来进行路由的映射,常见的http请求方法操作有:GET,HEAD,PUT,POST,DELETE,OPTIONS等。

  1. GET路由
  2. beego.GET("",func)
  3. beego.Get("/",func(ctx *context.Context){
  4. ctx.Output.Body([]byte("hello world")) })
  5. POST路由:
  6. beego.POST("",func)

固定路由

固定路由也就是全匹配的路由

  1. beego.Router("/", &controllers.MainController{})
  2. beego.Router("/admin", &admin.UserController{})
  3. beego.Router("/admin/addpkg", &admin.AddController{})

正则路由

beego.Router("/api/?:id", &controllers.RController{})

默认匹配 //例如对于URL"/api/123"可以匹配成功,此时变量":id"值为"123"

beego.Router("/api/:id", &controllers.RController{})

默认匹配 //例如对于URL"/api/123"可以匹配成功,此时变量":id"值为"123",但URL"/api/"匹配失败

beego.Router("/api/:id([0-9]+)", &controllers.RController{})

自定义正则匹配 //例如对于URL"/api/123"可以匹配成功,此时变量":id"值为"123"

beego.Router("/user/:username([\\w]+)", &controllers.RController{})

正则字符串匹配 //例如对于URL"/user/astaxie"可以匹配成功,此时变量":username"值为"astaxie"

beego.Router("/download/*.*", &controllers.RController{})

*匹配方式 //例如对于URL"/download/file/api.xml"可以匹配成功,此时变量":path"值为"file/api", ":ext"值为"xml"

beego.Router("/download/ceshi/*", &controllers.RController{})

*全匹配方式 //例如对于URL"/download/ceshi/file/api.json"可以匹配成功,此时变量":splat"值为"file/api.json"

beego.Router("/:id:int", &controllers.RController{})

int 类型设置方式,匹配 :id为int 类型,框架帮你实现了正则 ([0-9]+)

beego.Router("/:hi:string", &controllers.RController{})

string 类型设置方式,匹配 :hi 为 string 类型。框架帮你实现了正则 ([\w]+)

beego.Router("/cms_:id([0-9]+).html", &controllers.CmsController{})

带有前缀的自定义正则 //匹配 :id 为正则类型。匹配 cms_123.html 这样的 url :id = 123

自定义路由

beego.Router("/api/list",&RestController{},"*:ListFood")

beego.Router("/api/create",&RestController{},"post:CreateFood")

beego.Router("/api/update",&RestController{},"put:UpdateFood")

beego.Router("/api/delete",&RestController{},"delete:DeleteFood")

(3)参数配置

beego 默认会解析当前应用下的 conf/app.conf 文件。 通过这个文件你可以初始化很多 beego 的默认参数:

  1. appname = beepkg
  2. httpaddr = "127.0.0.1"
  3. httpport = 9090
  4. runmode ="dev"
  5. autorender = false
  6. recoverpanic = false
  7. viewspath = "myview"

你也可以在配置文件中配置应用需要用的一些配置信息,例如下面所示的数据库信息:

  1. mysqluser = "root"
  2. mysqlpass = "rootpass"
  3. mysqlurls = "127.0.0.1"
  4. mysqldb = "beego"

那么你就可以通过如下的方式获取设置的配置信息:

  1. beego.AppConfig.String("mysqluser")
  2. beego.AppConfig.String("mysqlpass")
  3. beego.AppConfig.String("mysqlurls")
  4. beego.AppConfig.String("mysqldb")

runmode 参数

  1. runmode ="dev"
  2. [dev]
  3. httpport = 8080
  4. [prod]
  5. httpport = 8088
  6. [test]
  7. httpport = 8888

include参数

include "app2.conf"

(4)XSRF

防御CSRF安全问题

在应用配置文件中加上 enablexsrf 设定:

  1. enablexsrf = true
  2. xsrfkey = 61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o
  3. xsrfexpire = 3600

或者直接在 main 入口处这样设置:

  1. beego.EnableXSRF = true
  2. beego.XSRFKEY = "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o"
  3. beego.XSRFExpire = 3600 //过期时间,默认1小时

如果开启了 XSRF,那么 beego 的 Web 应用将对所有用户设置一个 _xsrf 的 cookie 值(默认过期 1 小时),如果 POST PUT DELET 请求中没有这个 cookie 值,那么这个请求会被直接拒绝。

在 Controller 中这样设置数据:

  1. func (this *HomeController) Get(){
  2. this.Data["xsrfdata"]=template.HTML(this.XSRFFormHTML()
  3. ) }

然后在模板中这样设置:

  1. <form action="/new_message" method="post">
  2. {{ .xsrfdata }}
  3. <input type="text" name="message"/> <input type="submit" value="Post"/>
  4. </form>

(5)数据处理

通过如下方式获取数据:

  • GetString(key string) string
  • GetStrings(key string) []string
  • GetInt(key string) (int64, error)
  • GetBool(key string) (bool, error)
  • GetFloat(key string) (float64, error)

解析struct,把表单里的内容赋值到一个 struct 里:

定义 struct:

  1. type user struct {
  2. Id int `form:"-"`
  3. Name interface{} `form:"username"`
  4. Age int `form:"age"`
  5. Email string
  6. }

表单:

  1. <form id="user">
  2. 名字:<input name="username" type="text" />
  3. 年龄:<input name="age" type="text" />
  4. 邮箱:<input name="Email" type="text" />
  5. <input type="submit" value="提交" />
  6. </form>

Controller 里解析:

  1. func (this *MainController) Post() {
  2. u := user{}
  3. if err := this.ParseForm(&u);
  4. err != nil { //handle error }
  5. }

获取 Request Body 里的 JSON 或 XML 的数据

在配置文件里设置 copyrequestbody = true

  1. func (this *ObjectController) Post() {
  2. var ob models.Object
  3. var err error
  4. if err = json.Unmarshal(this.Ctx.Input.RequestBody, &ob); err == nil {
  5. objectid := models.AddOne(ob)
  6. this.Data["json"] = "{\"ObjectId\":\"" + objectid + "\"}"
  7. } else {
  8. this.Data["json"] = err.Error()
  9. }
  10. this.ServeJSON()
  11. }

(6)session控制

beego 中使用 session 相当方便,只要在 main 入口函数中设置如下:

beego.BConfig.WebConfig.Session.SessionOn = true

或者通过配置文件配置如下:

sessionon = true

session 有几个方便的方法:

    • SetSession(name string, value interface{})
    • GetSession(name string) interface{}
    • DelSession(name string)
    • SessionRegenerateID()
    • DestroySession()

(7)过滤器

beego.InsertFilter(pattern string, position int, filter FilterFunc, params ...bool)

pattern 路由规则,可以根据一定的规则进行路由,如果你全匹配可以用 *

position 执行 Filter 的地方,五个固定参数如下,分别表示不同的执行过程

  • BeforeStatic 静态地址之前
  • BeforeRouter 寻找路由之前
  • BeforeExec 找到路由之后,开始执行相应的 Controller 之前
  • AfterExec 执行完 Controller 逻辑之后执行的过滤器
  • FinishRouter 执行完逻辑之后执行的过滤器

filter filter 函数 type FilterFunc func(*context.Context)

2)model层

数据库查询操作,同时提供了 ORM 框架

(1)models.go

  1. package main
  2. import (
  3. "github.com/astaxie/beego/orm"
  4. )
  5. type User struct {
  6. Id int
  7. Name string
  8. Profile *Profile `orm:"rel(one)"` // 设置一对一的关系
  9. Post []*Post `orm:"reverse(many)"` // 设置一对多的反向关系
  10. }
  11. type Profile struct {
  12. Id int
  13. Age int16
  14. User *User `orm:"reverse(one)"` // 设置一对一反向关系(可选)
  15. }
  16. type Post struct {
  17. Id int
  18. Title string
  19. User *User `orm:"rel(fk)"` //设置一对多关系
  20. Tags []*Tag `orm:"rel(m2m)"`
  21. }
  22. type Tag struct {
  23. Id int
  24. Name string
  25. Posts []*Post `orm:"reverse(many)"` //设置多对多反向关系
  26. }
  27. func init() {
  28. // 需要在init中注册定义的model
  29. orm.RegisterModel(new(User), new(Post), new(Profile), new(Tag))
  30. }

打印数据库语句

  1. func main() {
  2. orm.Debug = true
  3. var w io.Writer
  4. ...
  5. // 设置为你的 io.Writer
  6. ...
  7. orm.DebugLog = orm.NewLog(w)

日志格式:

[ORM] - 时间 - [Queries/数据库名] - [执行操作/执行时间] - [SQL语句] - 使用标点 `,` 分隔的参数列表 - 打印遇到的错误

(2)数据库配置

  1. import _ "github.com/go-sql-driver/mysql"
  2. func init() {
  3. driverName := beego.AppConfig.String("driverName")
  4. //注册数据库驱动
  5. orm.RegisterDriver(driverName, orm.DRMySQL)
  6. //数据库连接
  7. user := beego.AppConfig.String("mysqluser")
  8. pwd := beego.AppConfig.String("mysqlpwd")
  9. host := beego.AppConfig.String("host")
  10. port := beego.AppConfig.String("port")
  11. dbname := beego.AppConfig.String("dbname")
  12. //dbConn := "root:yu271400@tcp(127.0.0.1:3306)/cmsproject?charset=utf8"
  13. dbConn := user + ":" + pwd + "@tcp(" + host + ":" + port + ")/" + dbname + "?charset=utf8"
  14. err := orm.RegisterDataBase("default", driverName, dbConn)
  15. if err != nil {
  16. util.LogError("连接数据库出错")
  17. return
  18. }
  19. util.LogInfo("连接数据库成功")
  20. }

(3)注册模型

  1. import "github.com/astaxie/beego/orm"
  2. type User struct { Id int Name string } func init(){
  3. orm.RegisterModel(new(User))
  4. }

RegisterModel 也可以同时注册多个 model

orm.RegisterModel(new(User), new(Profile), new(Post))

用表名前缀

orm.RegisterModelWithPrefix("prefix_", new(User))

(4)ORM接口

QueryTable

传入表名,或者 Model 对象,返回一个 QuerySeter

  1. o := orm.NewOrm()
  2. var qs orm.QuerySeter
  3. qs = o.QueryTable("user") // 如果表没有定义过,会立刻 panic

Using

切换为其他数据库

  1. orm.RegisterDataBase("db1", "mysql", "root:root@/orm_db2?charset=utf8") orm.RegisterDataBase("db2", "sqlite3", "data.db")
  2. o1 := orm.NewOrm()
  3. o1.Using("db1")
  4. o2 := orm.NewOrm()
  5. o2.Using("db2") // 切换为其他数据库以后 这个 Ormer 对象的其下的 api 调用都将使用这个数据库

Raw

Raw 函数,原生 SQL查询

  1. o := orm.NewOrm()
  2. var r orm.RawSeter
  3. r = o.Raw("UPDATE user SET name = ? WHERE name = ?", "testing", "slene")
  4. ids := []int{1, 2, 3}
  5. p.Raw("SELECT name FROM user WHERE id IN (?, ?, ?)", ids)

返回result对象

  1. res, err := o.Raw("UPDATE user SET name = ?", "your").Exec()
  2. if err == nil {
  3. num, _ := res.RowsAffected()
  4. fmt.Println("mysql row affected nums: ", num)
  5. }

Prepare

用于一次 prepare 多次 exec,以提高批量执行的速度。 

  1. p, err := o.Raw("UPDATE user SET name = ? WHERE name = ?").Prepare()
  2. res, err := p.Exec("testing", "slene")
  3. res, err = p.Exec("testing", "astaxie")
  4. p.Close() // 别忘记关闭 statement

RowsToStruct

查询结果匹配到 struct 里

  1. type Options struct { Total int Found int }
  2. res := new(Options)
  3. nums, err := o.Raw("SELECT name, value FROM options_table").RowsToStruct(res, "name", "value")
  4. fmt.Println(res.Total)
  5. fmt.Println(res.Found)

RowToMap

查询结果匹配到 map 里

  1. res := make(orm.Params)
  2. nums, err := o.Raw("SELECT name, value FROM options_table").RowsToMap(&res, "name", "value")

Values

返回结果集的 key => value 值

  1. var maps []orm.Params
  2. num, err := o.Raw("SELECT user_name FROM user WHERE status = ?", 1).Values(&maps)
  3. if err == nil && num > 0 {
  4. fmt.Println(maps[0]["user_name"])
  5. }

(5)GURD

Read

  1. o := orm.NewOrm()
  2. user := User{Id: 1}
  3. err := o.Read(&user)
  4. if err == orm.ErrNoRows {
  5. fmt.Println("查询不到")
  6. } else if err == orm.ErrMissPK {
  7. fmt.Println("找不到主键")
  8. } else {
  9. fmt.Println(user.Id, user.Name)
  10. }
  11. Read 默认通过查询主键赋值,可以使用指定的字段进行查询:
  12. user := User{Name: "slene"}
  13. err = o.Read(&user, "Name")

Insert

  1. o := orm.NewOrm()
  2. var user User
  3. user.Name = "slene"
  4. user.IsActive = true
  5. id, err := o.Insert(&user)
  6. if err == nil {
  7. fmt.Println(id)
  8. }

InsertMulti

  1. users := []User{
  2. {Name: "slene"},
  3. {Name: "astaxie"},
  4. {Name: "unknown"},
  5. ...
  6. }
  7. successNums, err := o.InsertMulti(100, users)

Update

  1. o := orm.NewOrm()
  2. user := User{Id: 1}
  3. if o.Read(&user) == nil {
  4. user.Name = "MyName"
  5. if num, err := o.Update(&user); err == nil {
  6. fmt.Println(num)
  7. }
  8. }
  9. Update 默认更新所有的字段,可以更新指定的字段:
  10. // 只更新 Name
  11. o.Update(&user, "Name")

Delete

  1. o := orm.NewOrm()
  2. if num, err := o.Delete(&User{Id: 1}); err == nil {
  3. fmt.Println(num)
  4. }

3)VIEW层

模板语法

go 统一使用了 {{ 和 }} 作为左右标签

使用 . 来访问当前位置的上下文

使用 $ 来引用当前模板根级的上下文

使用 $var 来访问创建的变量

学习链接:

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发