beego框架
1.课程规划
2.Beego框架快速入门
2.1beego框架了解
Beego作者:谢孟军
Beego框架是go语言开发的web后台框架。
**那什么是框架呢?**就是别人写好的代码,我们可以直接使用!这个代码是专门针对某一个开发方向定制的,例如:我们要做一个网站,利用 beego 框架就能非常快的完成网站的开发,如果没有框架,每一个细节都需要我们处理,开发速度会大大降低。
go语言的web框架:beego,gin,echo等等,那为什么我们选择beego呢?
第一,beego是中国人开发的,开发文档比较详细,beego官网网址: https://beego.me/ 。第二,现在公司里面用beego的也比较多,比如今日头条,百度云盘,腾讯,阿里等。
2.2MVC架构
Beego是MVC架构。MVC 是一种应用非常广泛的体系架构,几乎所有的编程语言都会使用到,而且所有的程序员在工作中都会遇到!用 MVC 的方式开发程序,可以让程序的结构更加合理和清晰。 我们画图说明
beego具体是如何内嵌MVC呢?我们搭起环境通过代码分析。
2.3环境搭建
这里默认大家已经搭建好了go语言的开发环境。
-
需要安装Beego源码和Bee开发工具//sudo apt-get install
$ go get -u -v github.com/astaxie/beego $ go get -u -v github.com/beego/bee
beego源码大家都了解,就是框架的源码。
Bee开发工具带有很多Bee命令。比如
bee new
创建项目,bee run
运行项目等。用bee运行项目,项目自带热更新(是现在后台程序常用的一种技术,即在服务器运行期间,可以不停服替换静态资源。替换go文件时会自动重新编译。)
安装完之后,bee可执行文件默认存放在
$GOPATH/bin
里面,所以需要把$GOPATH/bin
添加到环境变量中才可以进行下一步$ cd ~ $ vim .bashrc //在最后一行插入 export PATH="$GOPATH/bin:$PATH" //然后保存退出 $ source .bashrc
安装好之后,运行
bee new preojectName
来创建一个项目,注意:通过bee创建的项目代码都是在$GOPATH/src
目录下面的生成的项目目录结构如下:
quickstart |-- conf | `-- app.conf |-- controllers | `-- default.go |-- main.go |-- models |-- routers | `-- router.go |-- static | |-- css | |-- img | `-- js |-- tests | `-- default_test.go |-- views `-- index.tpl
**进入项目目录 **执行
bee run
命令,在浏览器输入网址:127.0.0.1:8080,显示如下:
2.4beego的项目结构分析
quickstart
|-- conf
| `-- app.conf
|-- controllers
| `-- default.go
|-- main.go
|-- models
|-- routers
| `-- router.go
|-- static
| |-- css
| |-- img
| `-- js
|-- tests
| `-- default_test.go
|-- views
`-- index.tpl
conf文件夹:放的是项目有关的配置文件
controllers:存放主要的业务代码
main.go:项目的入口文件
models:存放的是数据库有关内容
routers:存放路由文件,路由作用是根据不同的请求指定不同的控制器
static:存放静态资源,包括图片,html页面,css样式,js文件等
tests:测试文件
views:存放视图有关内容
后面我们重点需要操作的是MVC文件夹,routers文件夹。
2.5Beego快速体验
前面我们简单了解了 beego初始化的内容,那么就来个beego的快速体验吧!
根据上图所示的步骤,对自己创建的项目进行三步修改,然后在浏览器是否能看到修改之后的效果。
如果把你们前面做的静态网页放到views文件夹下呢?一个静态网站是不是就出现啦!有没有感受到beego开发网站的快捷!
代码分析
c.Data["Email"] = "astaxie@gmail.com"
是给视图传递数据,在视图界面里面需要用{{ }}
加上.
才能获取到,比如这行代码的意思就是,给视图传递,**Key为Email,value为astaxie@gmail.com **的数据。在视图中要通过{{.Email}}
就能获取到value值。
c.TplName = "index.tpl"
的作用是指定视图。这里面需要注意的是,默认指定的界面是tpl结尾,但是打开这个文件分析,发现还是一个html界面。所以我们也可以用html文件当视图文件。
通过我们对Beego的快速体验能够得出如下结论:
控制器(Controller)的作用
1.能够给视图传递数据
2.能够指定视图
视图(View)的作用
1.view本质就是个html。所以能在浏览器显示
2.能够接收控制器传递过来的数据
2.6Beego运行流程分析
-
浏览器发出请求
-
路由拿到请求,并给相应的请求指定相应的控制器
-
找到指定的控制器之后,控制器看是否需要查询数据库
-
如果需要查询数据库就找model取数据
-
如果不需要数据库,直接找view要视图
-
控制器拿到视图页面之后,把页面返回给浏览器
根据文字流程分析代码流程
-
从项目的入口main.go开始
-
找到router.go文件的Init函数
-
找到路由指定的控制器文件default.go的Get方法
-
然后找到指定视图的语法,整个项目就串起来啦。
2.7Post案例实现
刚才我们分析了beego项目的整个运行流程,最终是如何调到Get方法的呢?beego通过内部语法给不同的http请求指定了不同的方法,因为我们是从浏览器地址栏发送的请求,属于get请求,所以调用的是Get方法。为了检验老师说的对不对,我们可以实现一个post请求,看看效果。
2.7.1前端修改
前端代码如下:
修改我们刚才创建的新的视图,为了能够发送post请求,我们在视图中添加一个能发送post请求的控件form
<form method="post" action="/index">
<input type="submit">
</form>
然后设置一个能接收后台传递过来的数据的标签
<h1>hello {{.data}}</h1>
全部代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/index">
<input type="submit">
</form>
<h1>hello {{.data}}</h1>
</body>
</html>
2.7.2后台代码修改
后台代码
先设置我们Get请求要传递的数据和要显示的视图页面
func (c *MainController) Get() {
c.Data["data"] = "world"
c.TplName = "test.html" //渲染
}
再设置我们post请求要传递的数据和要显示的视图页面
func (c *MainController) Post() {
c.Data["data"] = "区块链一期最棒"
c.TplName = "test.html" //渲染
}
操作
先在浏览器输入网址,然后点击页面上的按钮,看一下页面的变化,有没有出现区块链二期最棒
几个字
2.8Beego中路由的快速体验
2.8.1路由的简单设置
路由的作用:根据不同的请求指定不同的控制器
路由函数:beego.Router("/path",&controller.MainController{})
函数参数:
先分析一下Url地址由哪几部分组成?
http://192.168.110.71:8080/index
http://地址:端口/资源路径
第一个参数:资源路径,也就是/
后面的内容
第二个参数:需要指定的控制器指针
了解上面的内容之后我们来看几个简单的例子:
beego.Router("/", &controllers.MainController{})
beego.Router("/index", &controllers.IndexController{})
beego.Router("/login", &controllers.LoginController{})
2.8.2高级路由设置
一般在开发过程中,我们基本不使用beego提供的默认请求访问方法,都是自定义相应的方法。那我们来看一下如何来自定义请求方法。
自定义请求方法需要用到Router的第三个参数。这个参数是用来给不同的请求指定不同的方法。具体有如下几种情况。
-
一个请求访问一个方法(也是最常用的),请求和方法之间用
:
隔开,不同的请求用;
隔开:beego.Router("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
-
可以多个请求,访问一个方法 ,请求之间用
,
隔开,请求与方法之间用:
隔开:beego.Router("/api",&RestController{},"get,post:ApiFunc")
-
所有的请求访问同一个方法,用
*
号代表所有的请求,和方法之间用:
隔开:beego.Router("/api/list",&RestController{},"*:ListFood")
-
如果同时存在 * 和对应的 HTTP请求,那么优先执行 HTTP请求所对应的方法,例如同时注册了如下所示的路由:
beego.Router("/simple",&SimpleController{},"*:AllFunc;post:PostFunc")
那么当遇到Post请求的时候,执行PostFunc而不是AllFunc。
如果用了自定义方法之后,默认请求将不能访问。
2.9Go语言操作MySQL数据库(复习)
-
安装go操作MySQL的驱动
go get -u -v github.com/go-sql-driver/mysql
-
go操作MySQL数据库
-
导包
import _ "github.com/go-sql-driver/mysql"
程序在操作数据库的时候只需要用到database/sql,而不需要直接使用数据库驱动,所以程序在导入数据库驱动的时候将这个包的名字设置成下划线。
-
连接数据库,用sql.Open()方法,open()方法的第一个参数是驱动名称,第二个参数是连接字符串,格式为:用户名:密码@tcp(ip:port)/数据库名称?编码方式,返回值是连接对象和错误信息,例如:
conn,err := sql.Open("mysql","root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") defer conn.Close()//随手关闭数据库是个好习惯
-
执行数据库操作。
数据库的主要方法有:
- Query 执行数据库的查询操作,例如一个Select语句,返回数据类型为*Rows
- QueryRow 执行数据库至多返回一条数据,返回数据类型为*Row
- Exec 执行数不返回任何rows的据库语句,例如delete操作
- PrePare 准备一个数据库query操作,返回一个*Stmt,用于后续query或Exec。这个Stmt可以被多次执行,或者并发执行
创建表
exec函数如下:
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
创建表的方法也是Exec(),参数是SQL语句,返回值是结果集和错误信息.
其中result包含的内容有:
type Result interface { LastInsertId() (int64, error) RowsAffected() (int64, error) }
RowsAffected() 函数,可以获得成功执行SQL后对数据库所影响的行数。
res ,err:= conn.Exec("create table user(name VARCHAR(40),pwd VARCHAR(40))") beego.Info("create table result=",res.,err)
增删改操作
执行增删改操作语句的是Exec(),参数是SQL语句,返回值是结果集和错误信息,通过对结果集的判断,得到执行结果的信息。以插入数据为例代码如下:
res,_:=stmt.Exec("insert user(name,pwd) values (?,?)","tony","tony") count,_:=res.RowsAffected() this.Ctx.WriteString(strconv.Itoa(int(count)))
查询操作
用的函数是Query()和QueryRow.
func (db *DB) QueryRow(query string, args ...interface{}) *Row func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
利用QueryRow实现单行查询,能确定该SQL语句的查询结果为一条记录。将结果中的字段值使用Scan()函数依次提取。
利用Query实现多行数据查询,返回值为查询结果集和错误信息。通过next和Scan函数一起将数据取出来
代码如下:
单行查询:
row:= conn.QueryRow(`select * from user where userName = "wyj"`) var name,pwd string row.Scan(&name,&pwd) beego.Info(name,"------",pwd)
多行查询:
data ,err :=conn.Query("SELECT name from user") var userName string if err == nil{ for data.Next(){ data.Scan(&userName) beego.Info(userName) } }
全部代码
//连接数据库 conn,err := sql.Open("mysql","root:123456@tcp(127.0.0.1:3306)/testtest?charset=utf8") if err != nil{ beego.Info("链接失败") } defer conn.Close() //建表 res ,err:= conn.Exec("create table user(userName VARCHAR(40),passwd VARCHAR(40))") beego.Info("create table result=",res,err) //插入数据 res,err =conn.Exec("insert user(userName,passwd) values(?,?)","itcast","heima") beego.Info(res,err) //单行查询 row:= conn.QueryRow(`select * from user where userName = "wyj"`) var name,pwd string row.Scan(&name,&pwd) beego.Info(name,"------",pwd) //多行查询 data ,err :=conn.Query("SELECT userName from user") var userName string if err == nil{ for data.Next(){ data.Scan(&userName) beego.Error(userName) } }
-
2.10 ORM框架
Beego中内嵌了ORM框架,用来操作数据库。那么ORM框架是什么呢?ORM框架是Object-RelationShip-Mapping的缩写,中文叫对象关系映射,他们之间的关系,我们用图来表示:
2.10.1 ORM初始化
-
首先要导包
import "github.com/astaxie/beego/orm"
-
然后要定义一个结构体
type User struct{ Id int Name string PassWord string }
思考:如果表名和字段名为小写会发生什么结果?
注意观察数据库表中的字段和结构体中的字段是否一样?
-
然后向数据库中注册表,这一步又分为三步:
-
连接数据库
用RegisterDataBase()函数,第一个参数为数据库别名,也可以理解为数据库的key值,项目中必须有且只能有一个别名为
default
的连接,第二个参数是数据库驱动,这里我们用的是MySQL数据库,所以以MySQL驱动为例,第三个参数是连接字符串,和传统操作数据库连接字符串一样,格式为:用户名:密码@tcp(ip:port)/数据库名称?编码方式,代码如下:orm.RegisterDataBase("default","mysql","root:123456@tcp(127.0.0.1:3306)/class1?charset=utf8")
注意:ORM只能操作表,不能操作数据库,所以我们连接的数据库要提前在MySQL终端创建好。
-
注册数据库表
用orm.RegisterModel()函数,参数是结构体对象,如果有多个表,可以用
,
隔开,多new几个对象:orm.RegisterModel(new(User))
-
生成表
用orm.RunSyncdb()函数,这个函数有三个参数,
第一个参数是数据库的别名和连接数据库的第一个参数相对应。
第二个参数是是否强制更新,一般我们写的都是false,如果写true的话,每次项目编译一次数据库就会被清空一次,fasle的话会在数据库发生重大改变(比如添加字段)的时候更新数据库。
第三个参数是用来说,生成表过程是否可见,如果我们写成课件,那么生成表的时候执行的SQL语句就会在终端看到。反之看不见。代码如下:
orm.RunSyncdb("default",false,true)
-
完整代码如下:
import "github.com/astaxie/beego/orm"
type User struct {
Id int
Name string
Passwd string
}
func init(){
//1.连接数据库
orm.RegisterDataBase("default","mysql","root:123456@tcp(127.0.0.1:3306)/test?charset=utf8")
//2.注册表
orm.RegisterModel(new(User))
//3.生成表
//1.数据库别名
//2.是否强制更新
//3.创建表过程是否可见
orm.RunSyncdb("default",false,true)
}
因为这里我们把ORM初始化的代码放到了 models包的init()函数里面,所以如果我们想让他执行的话就需要在main.go里面加入这么一句代码:
import _ "classOne/models"
2.10.2 简单的ORM增删改查操作
在执行ORM的操作之前需要先把ORM包导入,但是GoLand会自动帮我们导包,也可以手动导包
import "github.com/astaxie/beego/orm"
插入
-
先获取一个ORM对象,用orm.NewOrm()即可获得
o := orm.NewOrm()
-
定义一个要插入数据库的结构体对象
var user User
-
给定义的对象赋值
user.Name = "itcast" user.Passwd = "heima"
这里不用给Id赋值,因为建表的时候我们没有指定主键,ORM默认会以变量名为Id,类型为int的字段当主键,至于如何指定主键,我们明天详细介绍。
-
执行插入操作,o.Insert()插入,参数是结构体对象,返回值是插入的id和错误信息。
id, err := o.Insert(&user) if err == nil { fmt.Println(id) }
查询
-
也是要先获得一个ORM对象
o := orm.NewOrm()
-
定义一个要获取数据的结构体对象
var user User
-
给结构体对象赋值,相当于给查询条件赋值
user.Name = "itcast"
-
查询,用o.Read(),第一个参数是对象地址,第二个参数是指定查询字段,返回值只有错误信息。
err := o.Read(&user,"Name") if err != nil{ beego.Info("查询数据错误",err) return }
如果查询字段是查询对象的主键的话,可以不用指定查询字段
更新
-
一样的套路,先获得ORM对象
o := orm.NewOrm()
-
定义一个要更新的结构体对象
var user User
-
给结构体对象赋值,相当于给查询条件赋值
user.Name = "itcast"
-
查询要更新的对象是否存在
err := o.Read(&user) if err != nil{ beego.Info("查询数据错误",err) return }
-
如果查找到了要更新的对象,就给这个对象赋新值
user.Passwd = "itheima"
-
执行更新操作,用o.Update()函数,参数是结构体对象指针,返回值是更新的条目数和错误信息
count,err=o.Update(&user) if err != nil{ beego.Info("更新数据错误",err) return }
删除
-
同样的,获取ORM对象,获取要删除的对象
o := orm.NewOrm() var user User
-
给删除对象赋值,删除的对象主键必须有值,如果主键没值,就查询一下。我们这里直接给主键赋值。
user.Id = 1
-
执行删除操作,用的方法是o.Delete(),参数是删除的结构体对象,返回值是删除的条目数和错误信息
num, err := o.Delete(&User{Id: 1}) if err == nil { fmt.Println(num) }