• 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/bee
      
      • 1
      • 2

      beego源码大家都了解,就是框架的源码。

      Bee开发工具带有很多Bee命令。比如bee new创建项目,bee run运行项目等。

      用bee运行项目,项目自带热更新(是现在后台程序常用的一种技术,即在服务器运行期间,可以不停服替换静态资源。替换go文件时会自动重新编译。)

      安装完之后,bee可执行文件默认存放在$GOPATH/bin里面,所以需要把$GOPATH/bin添加到环境变量中才可以进行下一步

      $ cd ~
      $ vim .bashrc
      //在最后一行插入
      export PATH="$GOPATH/bin:$PATH"
      //然后保存退出
      $ source .bashrc
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      安装好之后,运行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
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

      **进入项目目录 **执行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
    
    • 1

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    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 controllers
    
    import (
    	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"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    hello world{{.data}}
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通过我们对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>
    
    • 1
    • 2
    • 3

    然后设置一个能接收后台传递过来的数据的标签

    <h1>hello {{.data}}</h1>
    
    • 1

    全部代码:

    <!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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    2.7.2后台代码修改

    后台代码

    先设置我们Get请求要传递的数据和要显示的视图页面

    func (c *MainController) Get() {
    	c.Data["data"] = "world"
    	c.TplName = "test.html"  //渲染
    }
    
    • 1
    • 2
    • 3
    • 4

    再设置我们post请求要传递的数据和要显示的视图页面

    func (c *MainController) Post() {
    	c.Data["data"] = "xxxxxx"
    	c.TplName = "test.html"  //渲染
    }
    
    • 1
    • 2
    • 3
    • 4

    操作

    先在浏览器输入网址,然后点击页面上的按钮,看一下页面的变化,有没有出现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{})
    
    • 1
    • 2
    • 3
    2.8.2高级路由设置

    一般在开发过程中,我们基本不使用beego提供的默认请求访问方法,都是自定义相应的方法。那我们来看一下如何来自定义请求方法。

    自定义请求方法需要用到Router的第三个参数。这个参数是用来给不同的请求指定不同的方法。具体有如下几种情况。

    • 一个请求访问一个方法(也是最常用的),请求和方法之间用 : 隔开,不同的请求用 ; 隔开:

      beego.Router("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
      
      • 1
    • 可以多个请求,访问一个方法 ,请求之间用,隔开,请求与方法之间用:隔开:

      beego.Router("/api",&RestController{},"get,post:ApiFunc")
      
      • 1
    • 所有的请求访问同一个方法,用*号代表所有的请求,和方法之间用:隔开:

      beego.Router("/api/list",&RestController{},"*:ListFood")
      
      • 1
    • 如果同时存在 * 和对应的 HTTP请求,那么优先执行 HTTP请求所对应的方法,例如同时注册了如下所示的路由:

      beego.Router("/simple",&SimpleController{},"*:AllFunc;post:PostFunc")
      
      • 1

      那么当遇到Post请求的时候,执行PostFunc而不是AllFunc。

      如果用了自定义方法之后,默认请求将不能访问。

    2.9Go操作MySQL数据库(复习)

    • 安装go操作MySQL的驱动

      go get -u -v github.com/go-sql-driver/mysql
      
      • 1
    • go简单操作MySQL数据库

      • 导包

        import "github.com/go-sql-driver/mysql"
        
        • 1
      • 连接数据库,用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()//随手关闭数据库是个好习惯
        
        • 1
        • 2
      • 执行数据库操作,这一步分为两种情况,一种是增删改,一种是查询,因为增删改不返回数据,只返回执行结果,查询要返回数据,所以这两块的操作函数不一样。

        创建表

        创建表的方法也是Exec(),参数是SQL语句,返回值是结果集和错误信息:

        res ,err:= conn.Exec("create table user(name VARCHAR(40),pwd VARCHAR(40))")
        beego.Info("create table result=",res,err)
        
        • 1
        • 2

    示例

    package models
    
    import (
    	"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=utf8
    	conn, 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()
    	//增加删除改查
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述
    增删改操作

    执行增删改操作语句的是Exec(),参数是SQL语句,返回值是结果集和错误信息,通过对结果集的判断,得到执行结果的信息。以插入数据为例代码如下:
    
    • 1
    res,_:=stmt.Exec("insert into user(name,pwd) values (?,?)","tony","tony")
    //count,_:=res.RowsAffected()
    //this.Ctx.WriteString(strconv.Itoa(int(count)))  
    
    • 1
    • 2
    • 3

    示例

    package models
    
    import (
    	"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=utf8
    	conn, 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")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    查询操作

    用的函数是Query(),参数是SQL语句,返回值是查询结果集和错误信息,然后循环结果集取出其中的数据。代码如下:

    data ,err :=conn.Query("SELECT name from user")
    	var userName string
    	if err == nil{
    		for data.Next(){
    			data.Scan(&userName)
    			beego.Info(userName)
    		}
    	}
       
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    示例

    package models
    
    import (
    	"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=utf8
    	conn, 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 string
    	for rows.Next() { //循环查询
    		rows.Scan(&name)
    		logs.Info(name)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    全部代码

        //连接数据库
        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 string
        	if err == nil{
        		for data.Next(){
        			data.Scan(&userName)
        			beego.Error(userName)
        		}
        	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.10 ORM框架

    Beego中内嵌了ORM框架,用来操作数据库。那么ORM框架是什么呢?ORM框架是Object-RelationShip-Mapping的缩写,中文叫对象关系映射,他们之间的关系,我们用图来表示:

    在这里插入图片描述

    2.10.1 ORM初始化
    • 首先要导包

      import "github.com/beego/beego/v2/client/orm"
      
      • 1
    • 然后要定义一个结构体

      type User struct{
          Id int
          Name string
          PassWord string
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

      思考:如果表名和字段名为小写会发生什么结果?

      注意观察数据库表中的字段和结构体中的字段是否一样?

    • 然后向数据库中注册表,这一步又分为三步:

      • 连接数据库

        用RegisterDataBase()函数
        第一个参数为数据库别名,也可以理解为数据库的key值,项目中必须有且只能有一个别名为default的连接
        第二个参数是数据库驱动,这里我们用的是MySQL数据库,所以以MySQL驱动为例
        第三个参数是连接字符串,和传统操作数据库连接字符串一样,格式为:用户名:密码@tcp(ip:port)/数据库名称?编码方式,代码如下:

        orm.RegisterDataBase("default","mysql","root:123456@tcp(127.0.0.1:3306)/class1?charset=utf8")
        
        • 1

        注意:ORM只能操作表,不能操作数据库,所以我们连接的数据库要提前在MySQL终端创建好。

      • 注册数据库表

        用orm.RegisterModel()函数,参数是结构体对象,如果有多个表,可以用 ,隔开,多new几个对象:

        orm.RegisterModel(new(User))
        
        • 1
      • 生成表

        用orm.RunSyncdb()函数,这个函数有三个参数,

        第一个参数是数据库的别名和连接数据库的第一个参数相对应。

        第二个参数是是否强制更新,一般我们写的都是false,如果写true的话,每次项目编译一次数据库就会被清空一次,fasle的话会在数据库发生重大改变(比如添加字段)的时候更新数据库。

        第三个参数是用来说,生成表过程是否可见,如果我们写成课件,那么生成表的时候执行的SQL语句就会在终端看到。反之看不见。代码如下:

        orm.RunSyncdb("default",false,true)
        
        • 1

    完整代码如下:

    package models
    
    import (
    	"github.com/beego/beego/v2/client/orm"
    	_ "github.com/go-sql-driver/mysql"
    )
    
    // 定义一个结构体
    type User struct {
    	Id       int //id默认为主键
    	Name     string
    	PassWord 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)
    
    	//操作表
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    因为这里我们把ORM初始化的代码放到了 models包的init()函数里面,所以如果我们想让他执行的话就需要在main.go里面加入这么一句代码:

    import _ "classOne/models"
    
    • 1
    2.10.2 简单的ORM增删改查操作

    在执行ORM的操作之前需要先把ORM包导入,但是GoLand会自动帮我们导包,也可以手动导包

    import "github.com/beego/beego/v2/client/orm"
    
    • 1

    插入

    • 先获取一个ORM对象,用orm.NewOrm()即可获得

      o := orm.NewOrm()
      
      • 1
    • 定义一个要插入数据库的结构体对象

      var user User
      
      • 1
    • 给定义的对象赋值

      user.Name = "chengpeng"
      user.Passwd = "chengpeng"
      
      • 1
      • 2

      这里不用给Id赋值,因为建表的时候我们没有指定主键,ORM默认会以变量名为Id,类型为int的字段当主键,至于如何指定主键,我们明天详细介绍。

    • 执行插入操作,o.Insert()插入,参数是结构体对象,返回值是插入的id和错误信息。

      id, err := o.Insert(&user)
      if err == nil {
          fmt.Println(id)
      }
      
      • 1
      • 2
      • 3
      • 4

    示例

    func (c *MainController) ShowGet() {
    	//获取ORM的对象
    	newOrm := orm.NewOrm()
    	//执行某个操作函数,增删改查
    	//赋值
    	var user models.User
    	user.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"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    路由写法

    在这里插入图片描述
    查询

    • 也是要先获得一个ORM对象

      o := orm.NewOrm()
      
      • 1
    • 定义一个要获取数据的结构体对象

      var user User
      
      • 1
    • 给结构体对象赋值,相当于给查询条件赋值

      user.Id= "chengpeng"
      
      • 1
    • 查询,用o.Read(),第一个参数是对象地址,第二个参数是指定查询字段,返回值只有错误信息。

      err := o.Read(&user,"Name")
      if err != nil{
      		beego.Info("查询数据错误",err)
      		return
      	}
      
      • 1
      • 2
      • 3
      • 4
      • 5

      如果查询字段是查询对象的主键的话,可以不用指定查询字段

    示例

    func (c *MainController) ShowGet() {
    	//获取ORM的对象
    	newOrm := orm.NewOrm()
    	//执行某个操作函数,增删改查
    
    	//查询
    	var user models.User
    
    	user.Id = 1
    
    	err := newOrm.Read(&user, "Id")
    	if err != nil {
    		logs.Error("查询失败", err)
    		return
    	}
    	//返回结果
    	logs.Info("结果:", user)
    	c.Data["data"] = "asdasda"
    	c.TplName = "test.html"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    更新

    • 一样的套路,先获得ORM对象

      o := orm.NewOrm()
      
      • 1
    • 定义一个要更新的结构体对象

      var user User
      
      • 1
    • 给结构体对象赋值,相当于给查询条件赋值

      user.Name = "chengpeng"
      
      • 1
    • 查询要更新的对象是否存在

      err := o.Read(&user)
      if err != nil{
      	beego.Info("查询数据错误",err)
      	return
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 如果查找到了要更新的对象,就给这个对象赋新值

      user.Passwd = "chengpeng"
      
      • 1
    • 执行更新操作,用o.Update()函数,参数是结构体对象指针,返回值是更新的条目数和错误信息

      count,err=o.Update(&user)
      if err != nil{
      	beego.Info("更新数据错误",err)
      	return
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5

    示例

    func (c *MainController) ShowGet() {
    	//获取ORM的对象
    	newOrm := orm.NewOrm()
    	//执行某个操作函数,增删改查
    
    	//更新操作
    	var user models.User
    
    	user.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"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    删除

    • 同样的,获取ORM对象,获取要删除的对象

      o := orm.NewOrm()
      var user User
      
      • 1
      • 2
    • 给删除对象赋值,删除的对象主键必须有值,如果主键没值,就查询一下。我们这里直接给主键赋值。

      user.Id = 1
      
      • 1
    • 执行删除操作,用的方法是o.Delete(),参数是删除的结构体对象,返回值是删除的条目数和错误信息

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

    示例

    func (c *MainController) ShowGet() {
    	//获取ORM的对象
    	newOrm := orm.NewOrm()
    	//执行某个操作函数,增删改查
    
    	//更新操作
    	var user models.User
    
    	user.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"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3.当天案例

    我们今天以注册和登陆作为我们今天的大练习,把今天讲到的内容都串起来。先注册,然后登陆。

    在开始具体的业务之前我们要做数据库设计,在正式开发中这一步是非常重要,也比较复杂的,但是今天我们只实现登陆和注册,就简单有个用户名和密码即可,model.go内容如下:

    package models
    
    import (
    	"github.com/beego/beego/v2/client/orm"
    	_ "github.com/go-sql-driver/mysql"
    )
    
    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.1注册

    确定注册请求路径,修改路由文件

    我们这里以/register作为注册的请求路径。所以这里我们需要修改router.go文件的内容。

    在router.go文件的init()函数中加下面这行代码:

    beego.Router("/register", &controllers.UserController{},"get:ShowRegister")
    
    • 1

    根据上面路由的指定,我们需要添加注册控制器

    在controllers文件夹下创建一个user.go,然后在这个文件里面定义一个结构体UserController当控制器。

    type UserController struct{
        beego.Controller
    }
    
    • 1
    • 2
    • 3

    注意这里面添加的beego.Controller,是为了继承自beego自带的控制器。

    添加显示注册页面函数

    添加函数的时候需要注意,这个函数必须是UserController的函数才可以,不然在路由里面调用不到。那如何把函数设置成UserController的成员函数呢?是在函数名前面加上括号,然后放上UserController的指针。这里我们先指定注册的视图。代码如下:

    func (c *UserController)ShowRegister(){
        c.TplName = "register.html"
    }
    
    • 1
    • 2
    • 3

    注意:这里如果函数名首字母小写,路由同意找不到函数,所以函数名首字母必须大写

    添加视图页面

    在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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    让项目运行起来,然后我们在浏览器里面输入相应的地址就能看见我们的注册页面了。

    显示完注册页面之后,接着我们来处理注册的post请求。因为action="/register",method="post",所以我们可以去router.go界面给post请求指定相应的方法。修改如下:

    beego.Router("/register", &controllers.UserController{},"get:ShowRegister;post:HandleRegister")
    
    • 1

    指定方法名之后我们就需要去控制器中实现他。
    注册业务处理

    • 首先在user.go中添加这个函数:

      func (this*UserController)HandleRegister(){
      }
      
      • 1
      • 2
    • 接着开始处理注册业务

      • 首先要获取数据。这里给大家介绍一类方法,这类方法将会在我们项目一中高频率的出现,因为他的作用太强大了。

        **this.GetString():**获取字符串类型值

        **this.GetInt():**获取整型值

        **this.GetFloat:**获取浮点型值

        **this.GetFile():**获取上传的文件

        **作用:**接收前端传递过来的数据,不管是get请求还是post请求,都能接收。

        **参数: ** 是传递数据的key值,一般情况下是form表单中标签的name属性值

        **返回值:**根据返回类型不同,返回值也不一样,最常用的GetString()只有一个返回值,如果没有取到值就返回空字符串,其他几个函数会返回一个错误类型。获取的值一般是标签里面的value属性值。至于比较特殊的,我们用到的时候给大家做介绍。

        知道了获取数据函数,我们就可以获取前端传递过来的数据啦。

      • 获取注册的用户名和密码

        userName := this.GetString("userName")
        passwd := this.GetString("passwd")
        
        • 1
        • 2
      • 对数据进行校验

        一般情况下,我们做服务器开发,从前端拿过来数据都要进行一系列的校验,然后才会用数据对数据库进行操作。不做校验的服务器很容易被黑掉。这里我们只做简单的判空校验。

        if userName == "" || passwd == ""{
            beego.Info("数据数据不完整,请重新输入!")
            this.TplName = "register.html"
            return
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5

        思考:如何把那句错误提示传递给视图?

      • 把数据插入数据库

        如果数据校验没有问题,那我们就需要把数据插入到数据库中。数据库插入操作前面刚讲过,这里就不一步一步的分开介绍了,代码如下:

        //获取orm对象
        	o := orm.NewOrm()
        	//获取要插入的数据对象
        	var user models.User
        	//给对象赋值
        	user.Name = userName
        	user.Passwd = passwd
        	//把数据插入到数据库
        	if _,err := o.Insert(&user);err != nil{
        		beego.Info("注册失败,请更换用户名再次注册!")
        		this.TplName = "register.html"
        		return
        	}
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13

        因为我们现在还没有其他界面,如果跳转成功就返回一句话注册成功,等我们实现了登陆界面之后再实现注册之后跳转登陆界面的操作。

        给浏览器返回一句化的代码如下:

        this.Ctx.WriteString("注册成功!")
        
        • 1

    user页面

    package controllers
    
    import (
    	"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 = userName
    	user.PassWord = pwd
    
    	//插入
    	_, err := newOrm.Insert(&user)
    	if err != nil {
    		logs.Error("插入失败", err)
    		return
    	}
    	//返回结果
    	//返回页面
    	this.Ctx.WriteString("注册成功")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    router–路由

    beego.Router("/register", &controllers.UserController{}, "get:ShowRegister;post:HandlePost")
    
    • 1

    前端页面

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.2登陆

    登陆和注册业务流程差不多,差别也就体现在一个是对数据的查询一个是数据的插入,讲义里面就不做详细分析,直接贴代码。

    路由文件修改

    添加下面一行代码:

    	beego.Router("/login", &controllers.UserController{},"get:ShowLogin;post:HandleLogin")
    
    • 1

    后台代码修改

    在控制器中添加展示登录页的函数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.User
    	user.Name = userName
    	//user.PassWord = pwd
    
    	err := 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("登录成功")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    添加视图文件

    登陆界面和注册界面很相似,拷贝过来简单修改一下即可,代码如下:

    <!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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这样我们的登陆和注册就算完成了,但是有一个问题,我们的登陆注册还是各干各的,没有关联起来,我们前面等登陆页面实现完之后,注册成功就跳转到登陆页面。现在我们来实现一下跳转。

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.3.2渲染

    渲染就是控制期把一些数据传递给视图,然后视图用这些输出组织成html界面。所以不会再给浏览器发请求,是服务器自己的行为,所以浏览器的地址栏不会改变,但是显示的页面可能会发生变化。用的函数是:this.TplName = "login.html"

    3.3.3两者之间的区别
    区别重定向渲染
    响应方式告诉浏览器相应是redirect,然后返回一个新的地址给浏览器,让浏览器重新发起请求直接给浏览器返回视图
    地址栏显示浏览器地址栏显示的是新的地址浏览器地址栏显示的还是原来的地址
    作用不能给视图传递数据,但是能够获取到加载页面时的数据能够给视图传递数据,但如果要获取加载页面时的数据,需要再次写相关代码
    使用场景页面跳转的时候页面加载或者是登陆注册失败的时候
  • 相关阅读:
    uniapp小程序单页面改变手机电量,头部通知的颜色效果demo(整理)
    服务器主机托管一站式托管服务有哪些?
    门窗软件项目---竖中梃类
    图片懒加载
    python设计模式12:状态模式
    【无标题】
    for、while、do While、for in、forEach、map、reduce、every、some、filter的使用
    Gson——在 Java 对象和 JSON 数据之间进行映射的 Java 类库
    测试用例设计方法之:入门试招,等价边界初探
    JVM-虚拟机栈
  • 原文地址:https://blog.csdn.net/qq_40432598/article/details/133402497