Beego框架学习笔记04--Beego与多对多关系表数据操作 - Go语言中文社区

Beego框架学习笔记04--Beego与多对多关系表数据操作


1.Beego Orm Read方法注意事项

使用orm根据指定字段去数据库中检索信息的时候,Read方法的第一个参数应当是【承载信息对象的指针】而不是承载信息对象。

...
o := orm.NewOrm()
var articleType models.ArticleType
articleType.TypeName = c.GetString("select")
//千万注意别写成o.Read(articleType, "TypeName")
o.Read(&articleType, "TypeName")

2.Beego Orm 多表查询的“惰性”

beego框架中orm工具的多表查询性质采用“惰性查询”。所谓的惰性查询就是:多表查询的时候如果不主动给定指令,就只能在当前表内进行查询操作,而不会自动去其他关联的表中进行查询操作。例如:

/*
  正常情况下
  去表中查询内容的时候直接使用.All()方法就能够完成检索。
  但是如果这个表与某个表形成了多对一的关系时,这个表中会自动被加入一个对应字段
  那么orm字段由于惰性查询的性质,就不会自动去查找另一个表中对应的信息。
*/
qs := o.QueryTable(“表1”);
qs.All(&查询表1结果容器)

/*
    因此针对这种情况beego框架的orm插件提供了一个关系索引函数relateSel()
    它能够在一对多关系表的查询操作中,用来指定查询时自动检索关联表中的信息
    例如下面的代码,假设表1中存在一个指向表2的外键
    那么relatedSel()函数由于参数设置了表2的名称,因此会在qs句柄执行的时候告知qs句柄
    去表2中自动检索与表1对应的信息。
*/
qs := o.QueryTable(“表1”);
qs.RelatedSel(“表2”).All(&查询表1结果容器)

3.Beego处理session和cookie

session和cookie都是在一定时间内信息的存储方式。这里指的cookie和前端的cookie指的是一个东西,但是session和前端中的sessionStorage却并不是相同的内容,尽管两者的性质也类似。http协议是一个无状态协议,因此请求之间无法进行数据交互。而为了使得请求之间可以进行数据传递提出了session和cookie的技术。需要特殊说明的一点是:Cookie不支持中文,所以如果存储中文需要base64.StdEncoding.EncodeToString()方法转换字符串再存储。ps:decodeString解密

  session cookie
存储位置 服务器端 客户端
安全性
生命周期 过期或主动删除后失效 过期或手动删除后失效
适用环境 登录状态等高安全系数数据 用户名等低安全系数数据

其实,当我写完区别的时候还是想补充一下的。我个人觉得session和cookie本质上来讲就是一个东西。只不过session是cookie在服务端进行数据持久化的一种手段而已。参考说明:https://rubyeye.iteye.com/blog/196117

(1)cookie相关操作

在服务器设置cookie:

*controlloer.Ctx.setCookie(“key”,”value”,”expire”)//0是永久 负数是立即删除 cookie不存在delete操作

在服务器读取cookie并回传页面:

value := *controller.Ctx.getCookie(“key”)
if value!=“”{
    *controller.Data[“指定字段”]
}
//然后在前端页面{{指定字段}}

(2)session相关操作

在服务器设置session:

*controller.setSession(“key”,value)//不需要expire

在服务器读取session:

*controller.getSession(“key”)//key是interface{}接口类型

在服务器删除session:

*controller.delSession(“key”)

特别的需要注意使用session功能的时候,需要在go的配置文件中添加sessionon=true语句以便开启session功能。这是因为beego默认session功能是关闭的,而这一操作还需要手动bee run重新编译加载,因为beego对于.go文件意外的文件修改保存不会触发热更新。

4.Beego orm对于“多对多”数据表的插入操作

其实不管什么一对一还是多对多,数据表的插入操作其实永远都是字段内容的添加赋值,这一点永远都不会改变。区别就在于添加内容的方式而已。在beego框架中对于多对多性质的数据表内容插入不再使用orm对象,而是使用m2m对象来执行操作。通常对于普通数据表添加内容来说,如果想要对字段添加内容直接【表1对象.表2字段 = xxx】就行(例如:stuInfo.Name = "frank"),但是如果表1和表2是多对多的关系就另当别论了。这是因为如果是多对多的数据表关系,那么在表中都会添加一个用以表示对应关系的“约束”。而约束通常被赋值都是指针或者指针切片内容。那么就需要用到m2m来完成对字段的数据绑定。


首先使用orm对象的queryM2M()方法获取到m2m对象,参数1是表对象指针,参数2是表对象中对应约束的字段名称。

m2m := o.QueryM2M(&表1对象, “表1对象中的表2对应字段名”)

又因为表1对象中的字段应当被赋值的内容并不应该真的只是一个表示表2内容字符串之类的东西,不然直接按照上面【表1对象.表2字段 = xxx】的内容添加就好了,其应当是一个表2对象的指针。那么这个表2对象的信息就势必先获取(对象先被拿出来才能取地址),所以去表2中先获取对应的表2对象。

var 表2对象 models.表2
表2.已知字段 = c.GetSession("session").(string)//通过session获取到一个已知值,不是必要的,随便啥地方都行,只要有个值就行
o.Read(&表2对象,”已知字段”)

通过这种方式能够通过一条已知字段从表2中获取到已知字段信息对应的表2对象结构,然后通过m2m对象来完成对“表1对象中的表2对应字段名”值的添加。注意这里千万不要盲目【表1对象.约束字段名 = &表2对象】,这样和最开始的操作没有任何分别。要使用m2m对象的Add方法来完成字段信息的赋值。但是尽管m2m.add()方法要添加的是一个对象的指针,但是添加的时候不用写&符号,而是直接将检索到的表2对象传入即可。

m2m.Add(表2对象)

此时因为我们并不清楚这边表1中的表2字段原本是否有值,所以在我们自己添加了值之后需要再获取m2m多对多信息一次。保证当下表1对象中的表2字段是最新的信息。当然如果你只要存储,而不需要读取就不用在读取了。

5.Beego orm对于“多对多”数据表的信息读取操作

需要知道对于多对多性质的数据表内容读取,其实不但要读取当前数据表的信息,还需要读取与当前数据表建立联系的表的数据。所以单纯的通过orm的queryTable().All()是不足够的。所以beego提供了orm一个名为LoadRelated()的方法,提供用来关联数据表的数据查询,本方法会将查询结果都存入参数1对应的参数2字段中。

//orm对象.LoadRelated(&表1对象,”表1对象中的表2对应字段名”)
//方法会直接将结果放在stuInfo的Stu字段中
o.LoadRelated(&stuInfo,"Stu")

但是这种操作是不能够保证信息是否重复的,因为loadRelated的运行机制就是有多少取得多少。而为了去除检索内容也就是参数1对应的参数2字段的值中重复的内容,beego提供了另外的一个名为Filter过滤器的函数,与过滤器函数返回值qs句柄的去重方法distinct。这就提供了另外的一种读取思路:先去表2中寻找被Filter过滤器筛选过的对象,然后通过distinct去重,最终反向赋值给表1对象的字段。

/*
原本orm的LoadRelated()方法查询的时候的查询机制是:
    查询表1,直接查看表1中的表2字段。里面有什么都拿出来

而反向查找的时候的查询机制是:
    先查表2,查看表2中的表1字段内容,这个字段对应的内容是一个对象指针切片
    然后再查看切片中的主键字段值与当前文章的id值是否相同,筛选出所有表2中与当前文章有关的对象
    返回的是一个qs具柄
    最后使用这个qs具柄,调用distinct方法去重,再将结果放在容器中返回。

之所以这样麻烦就是为了利用qs高级句柄来调用distinct方法,而第一种查询无法使用高级句柄的distinct方法
*/
//其实就相当于mysql语句的:select * from 表2 where distinct(表2中的表1字段类型__表1已知值对应字段) 
orm.QueryTable("表2名").Filter("表2中的表1字段__表2中的表1字段类型__表1已知值对应字段",已知字段值).Distinct().All(&表2对象容器)
stuInfo.Stu = 表2对象容器

6.Beego 视图循环

Beego提供了两种视图循环,就像Vue的v-for或者AngularJS的ng-repeat那样在html可以直接写出循环结构。

//循环加载后台通过字段Stu传来的切片信息,每个option加载每个切片的StuName值
{{range .Stu}}
    <option>{{.StuName}}</option>
{{end}}

//循环加载后台通过字段Stu传来的切片信息,使用$index获取下标,使用$tempStuInfo存储临时内容
{{range $index $tempStuInfo := .Stu}}
    <option>序号:{{$index}},名字:{{$tempStuInfo.StuName}}</option>
{{end}}

第一种循环内部,想要使用循环的成员内容使用.StuName这种方式是没问题的。但是如果想要在循环的时候不但使用循环的成员内容,还要使用后台传来的数据,那就需要使用$.StuIndex这种方式。

//循环加载后台通过字段Stu传来的内容,并在循环的时候比对每次循环临时对象的StuIndex字段和后台传来的StuIndex字段是否相同
{{range .Stu}}
    //如果相同就把这个option标记为默认选中
    <option
        {{if compare $.StuIndex .StuIndex}}
            selected="true"
        {{else}}
    //一个{{if}}结束对应的{{end}}
    {{end}}>
        {{.StuName}}
    </option>
//一个range循环结束的{{end}}
{{end}}

7.路由过滤器

在应用使用的过程中总是要考量究竟是用户在使用软件还是有黑客或者爬虫在发出攻击,因此校验用户的登录状态就显得势在必行。而应用中发生请求的位置茫茫多,在每一个请求发起之前都进行session验证不是不可以,只不过这个工程量和后期维护显得望穿秋水。而Beego框架和传统后台处理session验证操作一样提供了一个名为路由过滤器的机制。

路由过滤器的本质就是在需要验证的请求之前进行一次包装,让所有的请求会先经过一到“闸门”,其实就是路由。在路由这校验登录状态,若没能通过则直接阻断请求并直接跳转到登录页面,等待登录之后再进行请求的分发操作。

beego框架中添加的路由过滤器由两部分组成:路由过滤器注册、路由过滤器函数

(1)路由过滤器注册

beego.InsertFilter("/请求筛选统一路径/*", 校验执行时机, 校验函数)

参数一:其实就是对所有请求之前添加的一道屏障,随便一个什么字段都行。例如原本请求路径是/StuList,那就可以变成/check/StuList。这样所有的请求会统一先经过check路径,那么过滤器就可以在此生效了。*代表这个路径下所有的请求都需要经过校验函数的校验。

参数二:校验执行时机在beego中共有五种。

beforeStatic 静态路由执行之前
beforeRouter 动态路由执行之前
beforeExec 找到路由之后,开始执行相应的controller之前
afterExec 执行完controller逻辑之后执行的过滤器
finishRouter 执行完逻辑之后执行的过滤器

                 beego中存在静态路由和动态路由两种路由:
                 静态路由:可以通过路径直接访问,不需要通过router.go文件匹配分发,并且静态路由优先级高于动态路由

                 动态路由:通过router.go中beego.Router("/..")分发请求,不能通过路径直接访问。

参数三:写入过滤器函数名,随便啥名字都行。

(2)路由过滤器函数

其实就是一个普通的函数,就是语法结构有些特殊而已。

import "github.com/astaxie/beego/context"
...
var 随便写个函数名就行 = func(ctx *context.Context){
	//登录校验
	userName := ctx.Input.Session("session")
	if userName==nil{
		/*
			千万注意,ctx的跳转和controller跳转完全不同,参数正好相反。
		*/
		ctx.Redirect(302,"/login")
	}
}
...

特殊的地方在于两点:
        ·过滤器函数声明使用的包不是系统的自动导入的"context"包,而是beego自己的包"github.com/astaxie/beego/context"
        ·通过形参ctx进行重定向函数Redirect函数的参数第一个是跳转码,第二个才是重定向路径。
至于要如何进行校验,那就随便了。

8.视图模版

视图模板是方便后段快速构建前端结构的内容,了解下就行。使用就三个步骤:
        ·创建一个模板html文件,例如就叫layout.html
        ·在模板html文件的重复使用位置添加占位符{{.LayoutContent}}
        ·在.go文件中tplName渲染页面之前指定模板页面*controller.Layout = "layout.html"

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u013792921/article/details/84881802
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 20:59:55
  • 阅读 ( 2581 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢