beego---ORM相关操作
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/beebeego源码大家都了解,就是框架的源码。
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,显示如下:

解决bee问题的
https://blog.csdn.net/lilian129/article/details/128416866?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169596966316800197053200%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=169596966316800197053200&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-128416866-null-null.142^v94^control&utm_term=Failed%20to%20build%20the%20application%3A%20main.go%3A5%3A2%3A%20missing%20go.sum%20entry%20for%20module%20providing%20package%20github.com%2Fbeego%2Fbeego%2Fv2%2Fserver%2Fweb%20%28imported%20by%20projectName%29%3B%20to%20add%3A%20%20%20%20%20%20%20%20%20go%20get%20projectName&spm=1018.2226.3001.4187
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文件当视图文件。
示例
package controllersimport (beego "github.com/beego/beego/v2/server/web"
)type MainController struct {beego.Controller
}func (c *MainController) Get() {c.Data["Website"] = "beego.vip" //传递数据给视图c.Data["Email"] = "astaxie@gmail.com" //传递数据给视图c.Data["data"] = "china"//c.TplName = "index.tpl" //指定视图文件c.TplName = "test.html"
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
hello world{{.data}}
</body>
</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"] = "xxxxxx"c.TplName = "test.html" //渲染
}
操作
先在浏览器输入网址,然后点击页面上的按钮,看一下页面的变化,有没有出现xxxxxx几个字
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" -
连接数据库,用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()//随手关闭数据库是个好习惯 -
执行数据库操作,这一步分为两种情况,一种是增删改,一种是查询,因为增删改不返回数据,只返回执行结果,查询要返回数据,所以这两块的操作函数不一样。
创建表
创建表的方法也是Exec(),参数是SQL语句,返回值是结果集和错误信息:
res ,err:= conn.Exec("create table user(name VARCHAR(40),pwd VARCHAR(40))") beego.Info("create table result=",res,err)
-
示例
package modelsimport ("database/sql""github.com/beego/beego/v2/core/logs"_ "github.com/go-sql-driver/mysql"
)func init() {//操作数据库代码//第一个参数是数据库驱动,第二个参数是链接数据库字符串 //root:root@tcp(127.0.0.1:3306)charset=utf8conn, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test?charset=utf8")if err != nil {logs.Info("连接错误", err)logs.Error("连接错误", err)return}//创建表// You have an error in your SQL syntax; check the manual that corresponds to your MySQL// server version for the right syntax to use near 'password VARCHAR)'//_, err1 := conn.Exec("create table user(name VARCHAR,password VARCHAR);") //写法错误,//if err1 != nil {// logs.Info("创建失败", err1)// logs.Error("创建失败", err1)// return//}conn.Exec("create table user(name VARCHAR(40),password VARCHAR(40))") //必须定义VARCHAR(40)这样定义//关闭数据库defer conn.Close()//增加删除改查
}

增删改操作
执行增删改操作语句的是Exec(),参数是SQL语句,返回值是结果集和错误信息,通过对结果集的判断,得到执行结果的信息。以插入数据为例代码如下:
res,_:=stmt.Exec("insert into user(name,pwd) values (?,?)","tony","tony")
//count,_:=res.RowsAffected()
//this.Ctx.WriteString(strconv.Itoa(int(count)))
示例
package modelsimport ("database/sql""github.com/beego/beego/v2/core/logs"_ "github.com/go-sql-driver/mysql"
)func init() {//操作数据库代码//第一个参数是数据库驱动,第二个参数是链接数据库字符串 //root:root@tcp(127.0.0.1:3306)charset=utf8conn, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test?charset=utf8")if err != nil {logs.Info("连接错误", err)logs.Error("连接错误", err)return}//关闭数据库defer conn.Close()//增加 ?占位符conn.Exec("insert into user(name,password) values (?,?)", "chengpeng", "aini")
}
查询操作
用的函数是Query(),参数是SQL语句,返回值是查询结果集和错误信息,然后循环结果集取出其中的数据。代码如下:
data ,err :=conn.Query("SELECT name from user")var userName stringif err == nil{for data.Next(){data.Scan(&userName)beego.Info(userName)}}
示例
package modelsimport ("database/sql""github.com/beego/beego/v2/core/logs"_ "github.com/go-sql-driver/mysql"
)func init() {//操作数据库代码//第一个参数是数据库驱动,第二个参数是链接数据库字符串 //root:root@tcp(127.0.0.1:3306)charset=utf8conn, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test?charset=utf8")if err != nil {logs.Info("连接错误", err)logs.Error("连接错误", err)return}//关闭数据库defer conn.Close()rows, err := conn.Query("select name from user")if err != nil {return}var name stringfor rows.Next() { //循环查询rows.Scan(&name)logs.Info(name)}
}
全部代码
//连接数据库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)//查询数据data ,err :=conn.Query("SELECT userName from user")var userName stringif 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/beego/beego/v2/client/orm" -
然后要定义一个结构体
type User struct{Id intName stringPassWord 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)
-
完整代码如下:
package modelsimport ("github.com/beego/beego/v2/client/orm"_ "github.com/go-sql-driver/mysql"
)// 定义一个结构体
type User struct {Id int //id默认为主键Name stringPassWord string//在ORM里面__是有特殊含义的//Pass_Word
}func init() {//ORM操作数据库//获取连接对象orm.RegisterDataBase("default", "mysql", "root:root@tcp(127.0.0.1:3306)/test?charset=utf8")//创建表//注册表 new是分配内存orm.RegisterModel(new(User))//生成表//第一个参数是数据库别名//第二个参数是是否强制更新 false表变化很大,就会强制更新,true每次启动项目,就会drop掉,强制更新//第三个参数是否可见执行过程orm.RunSyncdb("default", false, true)//操作表
}
因为这里我们把ORM初始化的代码放到了 models包的init()函数里面,所以如果我们想让他执行的话就需要在main.go里面加入这么一句代码:
import _ "classOne/models"
2.10.2 简单的ORM增删改查操作
在执行ORM的操作之前需要先把ORM包导入,但是GoLand会自动帮我们导包,也可以手动导包
import "github.com/beego/beego/v2/client/orm"
插入
-
先获取一个ORM对象,用orm.NewOrm()即可获得
o := orm.NewOrm() -
定义一个要插入数据库的结构体对象
var user User -
给定义的对象赋值
user.Name = "chengpeng" user.Passwd = "chengpeng"这里不用给Id赋值,因为建表的时候我们没有指定主键,ORM默认会以变量名为Id,类型为int的字段当主键,至于如何指定主键,我们明天详细介绍。
-
执行插入操作,o.Insert()插入,参数是结构体对象,返回值是插入的id和错误信息。
id, err := o.Insert(&user) if err == nil {fmt.Println(id) }
示例
func (c *MainController) ShowGet() {//获取ORM的对象newOrm := orm.NewOrm()//执行某个操作函数,增删改查//赋值var user models.Useruser.Name = "chengpeng"user.PassWord = "ziyeaiaiai"//插入操作count, err := newOrm.Insert(&user)if err != nil {logs.Error("插入失败")return}//插入多少条logs.Info("chengpeng:::", count)//返回结果c.Data["data"] = "asdasda"c.TplName = "test.html"
}
路由写法

查询
-
也是要先获得一个ORM对象
o := orm.NewOrm() -
定义一个要获取数据的结构体对象
var user User -
给结构体对象赋值,相当于给查询条件赋值
user.Id= "chengpeng" -
查询,用o.Read(),第一个参数是对象地址,第二个参数是指定查询字段,返回值只有错误信息。
err := o.Read(&user,"Name") if err != nil{beego.Info("查询数据错误",err)return}如果查询字段是查询对象的主键的话,可以不用指定查询字段
示例
func (c *MainController) ShowGet() {//获取ORM的对象newOrm := orm.NewOrm()//执行某个操作函数,增删改查//查询var user models.Useruser.Id = 1err := newOrm.Read(&user, "Id")if err != nil {logs.Error("查询失败", err)return}//返回结果logs.Info("结果:", user)c.Data["data"] = "asdasda"c.TplName = "test.html"
}
更新
-
一样的套路,先获得ORM对象
o := orm.NewOrm() -
定义一个要更新的结构体对象
var user User -
给结构体对象赋值,相当于给查询条件赋值
user.Name = "chengpeng" -
查询要更新的对象是否存在
err := o.Read(&user) if err != nil{beego.Info("查询数据错误",err)return } -
如果查找到了要更新的对象,就给这个对象赋新值
user.Passwd = "chengpeng" -
执行更新操作,用o.Update()函数,参数是结构体对象指针,返回值是更新的条目数和错误信息
count,err=o.Update(&user) if err != nil{beego.Info("更新数据错误",err)return }
示例
func (c *MainController) ShowGet() {//获取ORM的对象newOrm := orm.NewOrm()//执行某个操作函数,增删改查//更新操作var user models.Useruser.Id = 1//先查询是否存在err := newOrm.Read(&user, "Id")if err != nil {logs.Error("要更新的数据不存在", err)return}user.Name = "chengpeng2"count, err := newOrm.Update(&user)if err != nil {logs.Error("更新失败", err)return}//返回结果logs.Info("结果:", count)c.Data["data"] = "asdasda"c.TplName = "test.html"
}
删除
-
同样的,获取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) }
示例
func (c *MainController) ShowGet() {//获取ORM的对象newOrm := orm.NewOrm()//执行某个操作函数,增删改查//更新操作var user models.Useruser.Id = 1//如果不查询直接删除,删除对象的主键要有值count, err := newOrm.Delete(&user, "Id")if err != nil {logs.Error("删除失败", err)return}//返回结果logs.Info("结果:", count)c.Data["data"] = "asdasda"c.TplName = "test.html"
}
3.当天案例
我们今天以注册和登陆作为我们今天的大练习,把今天讲到的内容都串起来。先注册,然后登陆。
在开始具体的业务之前我们要做数据库设计,在正式开发中这一步是非常重要,也比较复杂的,但是今天我们只实现登陆和注册,就简单有个用户名和密码即可,model.go内容如下:
package modelsimport ("github.com/beego/beego/v2/client/orm"_ "github.com/go-sql-driver/mysql"
)type User struct {Id intName stringPasswd 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)
}
3.1注册
确定注册请求路径,修改路由文件
我们这里以/register作为注册的请求路径。所以这里我们需要修改router.go文件的内容。
在router.go文件的init()函数中加下面这行代码:
beego.Router("/register", &controllers.UserController{},"get:ShowRegister")
根据上面路由的指定,我们需要添加注册控制器
在controllers文件夹下创建一个user.go,然后在这个文件里面定义一个结构体UserController当控制器。
type UserController struct{beego.Controller
}
注意这里面添加的
beego.Controller,是为了继承自beego自带的控制器。
添加显示注册页面函数
添加函数的时候需要注意,这个函数必须是UserController的函数才可以,不然在路由里面调用不到。那如何把函数设置成UserController的成员函数呢?是在函数名前面加上括号,然后放上UserController的指针。这里我们先指定注册的视图。代码如下:
func (c *UserController)ShowRegister(){c.TplName = "register.html"
}
注意:这里如果函数名首字母小写,路由同意找不到函数,所以函数名首字母必须大写
添加视图页面
在views文件夹下面创建一个名字为register.html的文件。然后实现成类似界面:

我们做后台的不关注样式,明天直接拿现成的样式来用即可,我们重在实现功能。
form标签里面需要添加两个属性,一个是action,一个是method,action其实就是请求路径,这里处理的还是注册业务,所以我们还用register请求,action = "/register",因为是上传数据,所以我们把method设置为post,即method="post",代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>注册页面</title>
</head>
<body><div style="position:absolute;left:50%; top:50%;"><form action="/register" method="post">用户名:<input type="text" name="userName"><p> </p>密码:<input type="password" name="passwd"><p> </p><input type="submit" value="注册"></form>
</div>
</body>
</html>
让项目运行起来,然后我们在浏览器里面输入相应的地址就能看见我们的注册页面了。
显示完注册页面之后,接着我们来处理注册的post请求。因为action="/register",method="post",所以我们可以去router.go界面给post请求指定相应的方法。修改如下:
beego.Router("/register", &controllers.UserController{},"get:ShowRegister;post:HandleRegister")
指定方法名之后我们就需要去控制器中实现他。
注册业务处理
-
首先在user.go中添加这个函数:
func (this*UserController)HandleRegister(){ } -
接着开始处理注册业务
-
首先要获取数据。这里给大家介绍一类方法,这类方法将会在我们项目一中高频率的出现,因为他的作用太强大了。
**this.GetString():**获取字符串类型值
**this.GetInt():**获取整型值
**this.GetFloat:**获取浮点型值
…
**this.GetFile():**获取上传的文件
**作用:**接收前端传递过来的数据,不管是get请求还是post请求,都能接收。
**参数: ** 是传递数据的key值,一般情况下是form表单中标签的name属性值
**返回值:**根据返回类型不同,返回值也不一样,最常用的GetString()只有一个返回值,如果没有取到值就返回空字符串,其他几个函数会返回一个错误类型。获取的值一般是标签里面的value属性值。至于比较特殊的,我们用到的时候给大家做介绍。
知道了获取数据函数,我们就可以获取前端传递过来的数据啦。
-
获取注册的用户名和密码
userName := this.GetString("userName") passwd := this.GetString("passwd") -
对数据进行校验
一般情况下,我们做服务器开发,从前端拿过来数据都要进行一系列的校验,然后才会用数据对数据库进行操作。不做校验的服务器很容易被黑掉。这里我们只做简单的判空校验。
if userName == "" || passwd == ""{beego.Info("数据数据不完整,请重新输入!")this.TplName = "register.html"return }思考:如何把那句错误提示传递给视图?
-
把数据插入数据库
如果数据校验没有问题,那我们就需要把数据插入到数据库中。数据库插入操作前面刚讲过,这里就不一步一步的分开介绍了,代码如下:
//获取orm对象o := orm.NewOrm()//获取要插入的数据对象var user models.User//给对象赋值user.Name = userNameuser.Passwd = passwd//把数据插入到数据库if _,err := o.Insert(&user);err != nil{beego.Info("注册失败,请更换用户名再次注册!")this.TplName = "register.html"return}因为我们现在还没有其他界面,如果跳转成功就返回一句话
注册成功,等我们实现了登陆界面之后再实现注册之后跳转登陆界面的操作。给浏览器返回一句化的代码如下:
this.Ctx.WriteString("注册成功!")
-
user页面
package controllersimport ("github.com/beego/beego/v2/client/orm""github.com/beego/beego/v2/core/logs"beego "github.com/beego/beego/v2/server/web""projectName/models"
)type UserController struct {//继承beego.Controller
}// 显示注册页面
func (this *UserController) ShowRegister() {this.TplName = "register.html"
}func (this *UserController) HandlePost() {//获取数据userName := this.GetString("userName")pwd := this.GetString("password")//校验数据//logs.Info(userName, pwd)if userName == "" || pwd == "" {this.Data["errmsg"] = "注册数据不完整,请重新注册!"logs.Info("注册数据不完整,请重新注册!")this.TplName = "register.html"return}//操作数据//获取ORM对象newOrm := orm.NewOrm()//获取插入对象var user models.User//给插入对象赋值user.Name = userNameuser.PassWord = pwd//插入_, err := newOrm.Insert(&user)if err != nil {logs.Error("插入失败", err)return}//返回结果//返回页面this.Ctx.WriteString("注册成功")
}
router–路由
beego.Router("/register", &controllers.UserController{}, "get:ShowRegister;post:HandlePost")
前端页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>注册页面</title>
</head>
<body><form method="post" action="/register">用户名:<input type="text" name="userName">密码:<input type="password" name="password"><input type="submit" value="注册"></form>
{{.errmsg}}
</body>
</html>
3.2登陆
登陆和注册业务流程差不多,差别也就体现在一个是对数据的查询一个是数据的插入,讲义里面就不做详细分析,直接贴代码。
路由文件修改
添加下面一行代码:
beego.Router("/login", &controllers.UserController{},"get:ShowLogin;post:HandleLogin")
后台代码修改
在控制器中添加展示登录页的函数ShowLogin和处理登陆数据的函数HandleLogin。完整代码如下:
// 展示登录页面
func (this *UserController) ShowLogin() {this.TplName = "login.html"
}func (this *UserController) HandleLogin() {//获取数据userName := this.GetString("userName")pwd := this.GetString("password")//校验数据if userName == "" || pwd == "" {this.Data["errmsg"] = "登录失败,密码或用户错误!"logs.Info("密码或用户错误,请重新输入!")this.TplName = "login.html"return}//操作数据//获取ORM对象newOrm := orm.NewOrm()var user models.Useruser.Name = userName//user.PassWord = pwderr := newOrm.Read(&user, "Name")if err != nil {this.Data["errmsg"] = "用户不存在!"this.TplName = "login.html"return}if user.PassWord != pwd {this.Data["errmsg"] = "密码错误!"this.TplName = "login.html"return}//返回页面this.Ctx.WriteString("登录成功")
}
添加视图文件
登陆界面和注册界面很相似,拷贝过来简单修改一下即可,代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登陆页面</title>
</head>
<body><div style="position:absolute;left:50%; top:50%;"><form action="/login" method="post">用户名:<input type="text" name="userName"><p> </p>密码:<input type="password" name="passwd"><p> </p><input type="submit" value="登陆"></form>
</div>
</body>
</html>
这样我们的登陆和注册就算完成了,但是有一个问题,我们的登陆注册还是各干各的,没有关联起来,我们前面等登陆页面实现完之后,注册成功就跳转到登陆页面。现在我们来实现一下跳转。
3.3页面之间的跳转
beego里面页面跳转的方式有两种,一种是重定向,一种是渲染,都能够在浏览器上显示新的页面
3.3.1重定向
//这里的this不是this指针
重定向用到的方法是this.Redirect()函数,有两个参数,第一个参数是请求路径,第二个参数是http状态码。
请求路径就不说了,就是和超链接一样的路径。
我们重点介绍一下状态码:
状态码一共分为五类:
1xx : 服务端已经接收到了客户端请求,客户端应当继续发送请求 。常见的请求:100
2xx :请求已成功 (已实现)常见的请求:200
3xx :请求的资源转换路径了,请求被跳转。常见的请求:300,302
4xx :客户端请求失败。常见的请求:404
5xx :服务器端错误。常见的请求:500
状态码详解:http://tool.oschina.net/commons?type=5
重定向的工作流程是:
1:当服务端向客户端响应 redirect后,并没有提供任何view数据进行渲染,仅仅是告诉浏览器响应为 redirect,以及重定向的目标地址2:浏览器收到服务端 redirect 过来的响应,会再次发起一个 http 请求3:由于是浏览器再次发起了一个新的 http 请求,所以浏览器地址栏中的 url 会发生变化4:浏览中最终得到的页面是最后这个 重定向的url 请求后的页面5:所以redirect("/register",302) 相当于你在浏览器中手动输入 localhost/register
3.3.2渲染
渲染就是控制期把一些数据传递给视图,然后视图用这些输出组织成html界面。所以不会再给浏览器发请求,是服务器自己的行为,所以浏览器的地址栏不会改变,但是显示的页面可能会发生变化。用的函数是:this.TplName = "login.html"
3.3.3两者之间的区别
| 区别 | 重定向 | 渲染 |
|---|---|---|
| 响应方式 | 告诉浏览器相应是redirect,然后返回一个新的地址给浏览器,让浏览器重新发起请求 | 直接给浏览器返回视图 |
| 地址栏显示 | 浏览器地址栏显示的是新的地址 | 浏览器地址栏显示的还是原来的地址 |
| 作用 | 不能给视图传递数据,但是能够获取到加载页面时的数据 | 能够给视图传递数据,但如果要获取加载页面时的数据,需要再次写相关代码 |
| 使用场景 | 页面跳转的时候 | 页面加载或者是登陆注册失败的时候 |
相关文章:
beego---ORM相关操作
Beego框架是go语言开发的web框架。 **那什么是框架呢?**就是别人写好的代码,我们可以直接使用!这个代码是专门针对某一个开发方向定制的,例如:我们要做一个网站,利用 beego 框架就能非常快的完成网站的开发…...
【网络原理】初始网络,了解概念
文章目录 1. 网络通信1.1 局域网LAN1.2 广域网WAN 2. 基础概念2.1 IP2.2 端口号 3. 认识协议4. 五元组5. 协议分层5.1 分层的作用5.2 OSI七层模型5.3 TCP/IP五层(四层)模型 6. 封装和分用 1. 网络通信 计算机与计算机之间是互相独立,是独立模…...
对象存储,从单机到分布式的演进
关于数据存储的相关知识,请大家关注“数据存储张”,各大平台同名。 通过《什么是云存储?从对象存储说起》我们对对象存储的历史、概念和基本使用有了一个大概的认识。而且我们以Minio为例,通过单机部署的模式实际操作了一下对象存储的GUI,感受了一下对象存储的用法。 在上…...
结构型设计模式——桥接模式
摘要 桥接模式(Bridge pattern): 使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变。 一、桥接模式的意图 将抽象与实现分离开来,使它们可以独立变化。 二、桥接模式的类图 Abstraction: 定义抽象类的接口Implementor: 定义实现类接口 …...
keepalived的vip实现nginx节点的主备
nginx wget http://nginx.org/download/nginx-1.18.0.tar.gz tar zxvf nginx-1.18.0.tar.gzyum install -y gcc gcc-c pcre pcre-devel zlib zlib-devel openssl openssl-devel libnl3-develcd nginx-1.18.0 mkdir -p /usr/local/nginx #需要使用https,在编译时启用…...
C++之std::atomic解决多线程7个问题(二百四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
tailwindcss 如何在 uniapp 中使用
直接使用https://tailwindcss.com/docs/guides/vite这篇官方教程的写法是跑不通的,摸索以后整理了一下,最关键的是第6步 npm install -D tailwindcss postcss autoprefixernpx tailwindcss init -p在 tailwind.config.js 中写入 export default {conten…...
oracle-使用PLSQL工具自行修改用户密码
1、使用PLSQL工具,输入用户名和原密码登录,如下图 2、登录后,在会话下拉菜单中找到”Change password..” 3、在跳出的窗口中配置新密码,修改完成后单击”确认”,后退出PLSQL 4、重新打开PLSQL,使用新密码登…...
自动驾驶技术:现状与未来
自动驾驶技术:现状与未来 文章目录 引言自动驾驶技术的现状自动驾驶技术的挑战自动驾驶技术的未来结论结论 2023星火培训【专项营】Apollo开发者社区布道师倾力打造,包含PnC、新感知等的全新专项课程上线了。理论与实践相结合,全新的PnC培训不…...
C++ 类构造函数 析构函数
类的构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。 下面的实例有助于更好地…...
C++标准模板(STL)- 输入/输出操纵符-(std::get_time,std::put_time)
操纵符是令代码能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。 不以参数调用的操纵符(例如 std::cout << std::boolalpha; 或 std::cin >> std::hex; )实现为接受到流的引用为其唯一参数的函数。 basic_ostream::…...
蓝桥等考Python组别九级004
第一部分:选择题 1、Python L9 (15分) 运行下面程序,可以输出几行“*”?( ) for i in range(3): for j in range(4): print(*, end = ) print() 2345正确答案:B 2、Python L9...
gitee 远程仓库操作基础(二)
(1)clone远端仓库,本地建立分支推送 (基于远程仓库版本库 本地建立分支开发新功能) git clone gitgitee.com:xxxxx/alsa_test.git git remote add origin gitgitee.com:xxxxx/alsa_test.git进入clone过后路径代码,查看本地分支,发现该项目远程仓库有很多分支 基于…...
Scala第四章节
Scala第四章节 scala总目录 章节目标 掌握分支结构的格式和用法掌握for循环和while循环的格式和用法掌握控制跳转语句的用法掌握循环案例理解do.while循环的格式和用法 1. 流程控制结构 1.1 概述 在实际开发中, 我们要编写成千上万行代码, 代码的顺序不同, 执行结果肯定也…...
【C++入门指南】类和对象(上)
【C杂货店】类和对象(上) 一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1 访问限定符4.2 封装 五、类的作用域六、类的实例化七、类对象模型7.1 类对象的存储规则7.2 例题7.3结构体内存对齐规则 八、this指针8.2 t…...
web:[极客大挑战 2019]PHP
题目 点进页面显示如下 根据页面提示,这个网站有备份文件,备份文件一般是bak文件格式,用dirsearch扫描 访问之后下载了一个文件 里面都是一些代码 在index.php中发现了一个类的文件,一个get传参,然后将传进的值进行反序…...
Firefox 开发团队对 Vue 3 进行优化效果显著
Mozilla 官方博客近日发表文章《Faster Vue.js Execution in Firefox》,介绍了 Firefox 开发团队对 Vue 3 进行的优化。 文章写道,在使用 Speedometer 3 对 Firefox 进行基准测试时,他们发现 Vue.js test 的测试结果从 Vue 2 升级到 Vue 3 后…...
【Verilog 教程】6.5 Verilog避免Latch
关键词:触发器,锁存器 Latch 的含义 锁存器(Latch),是电平触发的存储单元,数据存储的动作取决于输入时钟(或者使能)信号的电平值。仅当锁存器处于使能状态时,输出才会随着…...
怒刷LeetCode的第21天(Java版)
目录 第一题 题目来源 题目内容 解决方法 方法一:哈希表 方法二:计数器数组 第二题 题目来源 题目内容 解决方法 方法一:分治法 方法二:快速幂 迭代 方法三:快速幂 递归 第三题 题目来源 题目内容 …...
Armv9 Cortex-A720的L2 memory system 和 L2 Cache
9 L2 memory system Cortex-A720核心的L2内存系统通过CPU bridge连接core与DynamIQ Shared Unit-120,其中包括私有的L2缓存。 L2缓存是统一的,每个Cortex-A720核心在一个集群中都有私有的L2缓存。 L2内存系统包括使用虚拟地址(VA)和程序计数器(PC)的数据预取引擎。不同…...
兜兜转转又回到大浪浪的S05,遥看当年黑丝在,今朝尽染满头霜。
偶然翻看CSDN头像,恍然惊觉已是十五载光阴。2011年拍照于此设头像。初来S05,一路辗转S01,兜兜转转,历经浮沉,如今终究重回最初的S05。这十几年来,方寸代码天地,见证了我的所有成长与蜕变。一路行…...
SAP ABAP SOAUTH2 配置原理与 OAuth2 四要素落地解析
1. 为什么 SAP ABAP 系统里填个 OAuth2 参数总像在解谜题? 刚接手一个对接钉钉开放平台的 ABAP 项目时,我盯着事务码 SOAUTH2 的配置界面足足看了二十分钟——Client ID、Client Secret、Authorization Endpoint、Token Endpoint、Redirect URI……每个…...
平均 CPU 利用率指标为何该摒弃?多个案例揭示真相!
1. 作者信息与文章背景Jeremy Theocharis 是《平凡即卓越》作者、UMH 联合创始人兼首席技术官。文章基于其在 2026 年 4 月云原生亚琛聚会上的演讲,探讨为何应摒弃平均 CPU 利用率指标。2. 应用程序问题引出我们应用程序中的一个 Go 函数在生产环境总是被取消执行。…...
Flutter动画系统完全指南:构建流畅用户体验
引言 Flutter提供了强大而灵活的动画系统,允许开发者创建流畅、高性能的动画效果。本文将深入探讨Flutter动画系统的核心概念、使用模式和最佳实践。 一、Flutter动画基础 1.1 动画类型 动画类型说明适用场景补间动画从起始值到结束值的平滑过渡简单属性动画物理动画…...
红队实战信息收集:从域名枚举到攻击链路建模
1. 这不是教科书里的“信息收集”,而是红队进现场前真正要干的活 你拿到一个目标域名,比如 example.com,老板说:“先摸清家底,别急着打。” 这时候,90%的人会立刻打开终端敲 nmap -sV example.com &…...
MSTP+VRRP+链路聚合简单配置
实验需求:1.存在两个用户业务网,分布为VLAN 10和VLAN 20,需要SW1作为VLAN 10根桥和VRRP-master设备2.SW2作为VLAN 20根桥和VRRP-master设备3.网段自行规划,全网可达配置思路:两条实例:需要在 MSTP 域中配置…...
asnumpy - 让昇腾NPU和NumPy无缝对接
刚学深度学习那会,最顺手的是 NumPy。各种矩阵运算、广播机制、索引操作,闭着眼睛都能写。 后来跑昇腾NPU,发现 NumPy 代码没法直接跑——torch.tensor 和 np.ndarray 不能混用,数据要手动转来转去,烦死了。 直到我发…...
Temu 运营进阶之路 工具选型与凌风体系分析
TEMU商家体量持续扩张,平台规则与收费体系愈发复杂,纯人工运营耗时费力,核算误差、合规疏漏问题频发。市面上运营工具繁杂,商家难以甄别适配工具。本文以行业实操角度,客观拆解凌风工具箱的适配能力与实用价值…...
深度实战:如何利用7zip引擎实现加密压缩包密码暴力破解
深度实战:如何利用7zip引擎实现加密压缩包密码暴力破解 【免费下载链接】ArchivePasswordTestTool 利用7zip测试压缩包的功能 对加密压缩包进行自动化测试密码 项目地址: https://gitcode.com/gh_mirrors/ar/ArchivePasswordTestTool 在数字资产管理中&#…...
NotebookLM显著性判断失效真相:92%用户忽略的3个统计学前提及实时校验脚本
更多请点击: https://codechina.net 第一章:NotebookLM显著性判断失效的典型现象与影响评估 NotebookLM 在处理多源异构文档时,其内置的“显著性判断”模块(Significance Scorer)常因语义稀疏、上下文截断或引用锚点偏…...
