Gin框架
Gin 是一个用 Go (Golang) 编写的 web 框架。 它是一个类似于 martini 但拥有更好性能的 API 框架, 由于 httprouter,速度提高了近 40 倍。 如果你是性能和高效的追求者, 你会爱上 Gin.
一、安装
1.1、安装
要安装 Gin 软件包,需要先安装 Go 并设置 Go 工作区。
1.下载并安装 gin:
1
|
$ go get -u github.com/gin-gonic/gin
|
2.将 gin 引入到代码中:
1
|
import "github.com/gin-gonic/gin"
|
3.(可选)如果使用诸如 http.StatusOK
之类的常量,则需要引入 net/http
包:
1.2、基本案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
// 返回一个json数据
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
// 返回一个html页面
r.LoadHTMLGlob("templates/*")
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html",nil)
})
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
|
二、Gin路由
2.1、路由方法
路由系统支持任意方式的请求,如下的方法用来提供对应方法来接收请求:
1
2
3
4
5
6
7
8
9
10
|
func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes
func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes
func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes
func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes
func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes
func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes
// 任意路由
func (group *RouterGroup) ANY(relativePath string, handlers ...HandlerFunc) IRoutes
|
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
|
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 加载模板
r.LoadHTMLGlob("templates/*")
r.GET("/get", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "GET请求",
})
})
r.POST("/post",func(c *gin.Context){
c.JSON(200, gin.H{
"message": "POST请求",
})
})
// 路由匹配不成功
r.NoRoute(func(c *gin.Context) {
c.HTML(http.StatusNotFound, "404.html", nil)
})
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
|
2.2、路由分组
路由分组用于将多个路由进行统一的处理
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
|
package main
import (
"github.com/gin-gonic/gin"
)
func app01_foo(c *gin.Context) {
c.JSON(200, gin.H{
"message": "app01_foo",
})
}
func app01_bar(c *gin.Context) {
c.JSON(200, gin.H{
"message": "app01_bar",
})
}
func app02_foo(c *gin.Context) {
c.JSON(200, gin.H{
"message": "app02_foo",
})
}
func app02_bar(c *gin.Context) {
c.JSON(200, gin.H{
"message": "app02_bar",
})
}
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*")
// 简单的路由组: a1
a1 := r.Group("/app01")
{
a1.GET("/foo", app01_foo)
a1.GET("/bar", app01_bar)
}
// 简单的路由组: a2
a2 := r.Group("/app02")
{
a2.GET("/foo", app02_foo)
a2.GET("/bar", app02_bar)
}
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
|
路由组也支持嵌套使用:
1
2
3
4
5
6
7
8
9
|
a3 := r.Group("/app03")
{
a3.Group("/shop")
{
a3.GET("/cart", func(context *gin.Context) {
context.String(200,"cart...")
})
}
}
|
三、Gin视图函数
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func index(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{"name": "Yuan"})
}
func login(c *gin.Context) {
// 获取get数据
user := c.Query("user")
pwd := c.Query("pwd")
// user = c.DefaultQuery("user","")
fmt.Println("GET user",user)
fmt.Println("GET pwd",pwd)
// 获取请求方式
fmt.Println(c.Request.Method)
c.HTML(http.StatusOK, "login.html", nil)
}
func auth(c *gin.Context) {
// 获取post数据
user := c.PostForm("user")
pwd := c.PostForm("pwd")
// user := c.DefaultPostForm("user","")
fmt.Println("POST user",user)
fmt.Println("POST pwd",pwd)
if user == "yuan" && pwd == "123"{
c.String(200,"验证成功!")
}else {
c.String(200,"验证失败!")
}
}
func not_found(c *gin.Context) {
c.HTML(http.StatusNotFound, "notFound.html", nil)
}
func article_year_month(c *gin.Context) {
// 获取动态路径参数
fmt.Println(c.Param("year"))
fmt.Println(c.Param("month"))
// 获取全路径
// 获取url全路径 url : 协议:IP:端口:路径?get参数
fmt.Println(c.FullPath())
}
func article_delete(c *gin.Context) {
// 获取动态路径参数
delete_id:=c.Param("delete_id")
fmt.Println("删除书籍",delete_id)
// 重定向
//c.Header("Content-Type", "text/html; charset=utf-8")
//c.String(200,"<h3>删除成功!</h3>")
c.Redirect(http.StatusMovedPermanently,"/index")
}
var r = gin.Default()
func main() {
r.LoadHTMLGlob("./templates/*")
r.GET("/index", index)
r.GET("/login", login)
r.POST("/auth", auth)
// 设置博客路由组
blog := r.Group("/blog")
{
blog.GET("/articles/:year/:month", article_year_month)
blog.GET("/articles/delete/:delete_id", article_delete)
}
// 没有匹配到路由的请求分配处理函数
r.NoRoute(not_found)
r.Run(":9090") // 监听并在 0.0.0.0:8080 上启动服务
}
|
四、Gin模板
4.1、Go模板的变量渲染
视图部分:
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
|
package main
import (
"fmt"
"net/http"
"html/template"
)
// main.go
type Student struct {
Name string
Gender string
Age int
}
func index(w http.ResponseWriter, r *http.Request) {
// 1、解析指定文件生成模板对象
tmpl, err := template.ParseFiles("templates/index.tmpl")
if err != nil {
fmt.Println("create template failed, err:", err)
return
}
// 2、利用给定数据渲染模板,并将结果写入w
// obj1:=Student{"yuan","male",23}
s1:=Student{"yuan","male",23}
obj2:=map[string]interface{}{
"s1":s1,
"books":[]string{"三国演义","西游记","红楼梦","UI设计"},
"articles":[]string{},
}
tmpl.Execute(w,obj2)
}
func main() {
http.HandleFunc("/", index)
err := http.ListenAndServe(":9995", nil)
if err != nil {
fmt.Println("HTTP server failed,err:", err)
return
}
}
|
模板部分:
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
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>一 变量渲染</h3>
<p>hi,{{.}}</p>
<p>姓名: {{.Name}}</p>
<p>年龄: {{.Age}}</p>
<p>性别: {{.Gender}}</p>
<p>{{.s1}}</p>
<p>{{.s1.Name}}</p>
<p>{{.books}}</p>
<p>{{index .books 2}}</p>
<h3>二 条件判断</h3>
{{if .articles }}
{{.articles}}
{{else}}
<p>没有任何文章</p>
{{end}}
<h3>三 循环变量</h3>
{{range $index,$value := .books}}
<p>{{$index}} : {{$value}} </p>
{{end}}
<h3>with语句</h3>
{{with .s1}}
<p>{{.Name}}</p>
<p>{{.Age}}</p>
{{end}}
<h3>注释</h3>
{{/*这是一个注释语法*/}}
</body>
</html>
|
4.2、Go模板函数
语法格式:
functionName [Argument...]
Argument参数是可选的,如果有多个参数,参数直接用空格分隔。
函数名 | 函数调用格式 | 对应关系运算 | 说明 |
eq |
eq arg1 arg2 |
arg1 == arg2 |
arg1等于arg2则返回true |
ne |
ne arg1 arg2 |
arg1 != arg2 |
arg1不等于arg2则返回true |
lt |
lt arg1 arg2 |
arg1 < arg2 |
arg1小于arg2则返回true |
le |
le arg1 arg2 |
arg1 <= arg2 |
arg1小于等于arg2则返回true |
gt |
gt arg1 arg2 |
arg1 > arg2 |
arg1大于arg2则返回true |
ge |
ge arg1 arg2 |
arg1 >= arg2 |
arg1大于等于arg2则返回true |
and |
and 表达式1 表达式2 |
表达式1 && 表达式2 |
表达式1和表达式2都为真的时候返回true |
or |
or 表达式1 表达式2 |
表达式1 || 表达式2 |
表达式1和表达式2其中一个为真的时候返回true |
not |
not 表达式 |
!表达式 |
表达式为false则返回true, 反之返回false |
index |
index arg 索引/键 |
index x 2 即x[2] |
每个被索引的主体必须是数组、切片或者字典 |
len |
len arg |
len x 即x的元素个数 |
用于计算数组大小 |
urlquery |
urlquery arg |
urlquery url |
用于url编码 |
4.3、Go模板的嵌套与继承
在实际项目中,我们不可能只有一个模板,一般来说都有很多个模板,而且这些模板也会共享一些公共的模板,这些公共的模板我们都可以定义成子模板,在需要的时候调用子模板,就可以将子模板的内容嵌入当前模板中。
提示:在项目中使用子模板,可以让项目模板具有模块化的能力,提高模块复用能力和可维护性。
main.go
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
package main
import (
"fmt"
"net/http"
"html/template"
)
// main.go
func index(w http.ResponseWriter, r *http.Request) {
fmt.Println("index...")
// 1、解析指定文件生成模板对象
tmpl, err := template.ParseFiles("./templates/layout.html","./templates/index.html","./templates/ads.html")
if err != nil {
fmt.Println("create template failed, err:", err)
return
}
// 2、利用给定数据渲染模板,并将结果写入w
err = tmpl.ExecuteTemplate(w,"index.html",nil)
if err != nil {
fmt.Println("render template failed, err:", err)
return
}
}
func article_detail(w http.ResponseWriter, r *http.Request) {
fmt.Println("article_detail...")
// 1、解析指定文件生成模板对象
tmpl, err := template.ParseFiles("./templates/layout.html","./templates/article_detail.html","./templates/ads.html")
if err != nil {
fmt.Println("create template failed, err:", err)
return
}
// 2、利用给定数据渲染模板,并将结果写入w
err = tmpl.ExecuteTemplate(w,"article_detail.html",nil)
if err != nil {
fmt.Println("render template failed, err:", err)
return
}
}
func archives(w http.ResponseWriter, r *http.Request) {
fmt.Println("achives...")
// 1、解析指定文件生成模板对象
tmpl, err := template.ParseFiles("./templates/layout.html","./templates/archives.html","./templates/ads.html")
if err != nil {
fmt.Println("create template failed, err:", err)
return
}
// 2、利用给定数据渲染模板,并将结果写入w
err = tmpl.ExecuteTemplate(w,"archives.html",nil)
if err != nil {
fmt.Println("render template failed, err:", err)
return
}
}
func main() {
http.HandleFunc("/index", index)
http.HandleFunc("/article_detail", article_detail)
http.HandleFunc("/archives", archives)
err := http.ListenAndServe(":6677", nil)
if err != nil {
fmt.Println("HTTP server failed,err:", err)
return
}
}
|
templates/layout.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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
*{
margin: 0;
padding: 0;
}
.header{
width: 100%;
background-color: #369;
color: white;
line-height: 48px;
}
.content{
margin-top: 10px;
}
</style>
</head>
<body>
<div class="header">yuan老师的个人博客</div>
<div class="content container-fluid">
<div class="row">
<div class="col-md-2">
<div class="panel panel-info">
<div class="panel-heading">文章分类</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading">文章标签</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-success">
<div class="panel-heading">其它</div>
<div class="panel-body">
Panel content
</div>
</div>
</div>
<div class="col-md-8">
<div class="content">
{{block "content" .}}
{{end}}
</div>
</div>
{{/*模板嵌套*/}}
<div class="col-md-2">
{{template "ads.html"}}
</div>
</div>
</div>
</body>
</html>
|
templates/index.html,templates/article_detail.html,templates/archives.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// index.html
{{template "layout.html" .}}
{{define "content"}}
Hello index !!!
{{end}}
// article_detail.html
{{template "layout.html" .}}
{{define "content"}}
Hello article_detail !!!
{{end}}
// archives.html
{{template "layout.html" .}}
{{define "content"}}
Hello archievs!!!
{{end}}
|
五、Gorm
5.1、gorm介绍
5.2、连接数据库
中文文档: https://www.kancloud.cn/sliver_horn/gorm/1861152
连接数据库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package main
import (
"fmt"
"gorm.io/gorm"
"gorm.io/driver/mysql"
"time"
)
// Gorm
func main() {
// 连接mysql
dsn := "用户名:密码@tcp(127.0.0.1:3306)/数据库名?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("err:",err)
}
}
|
5.3、声明模型
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 创建表对应的结构体
type Book struct {
ID uint `gorm:"primaryKey"`
Title string `gorm:"type:varchar(100);unique;not null"`
Price int64
Is_publish byte `gorm:"default:1"`
Publish_date *time.Time
CreateTime *time.Time `gorm:"autoCreateTime"`
UpdateTime *time.Time `gorm:"autoCreateTime"`
}
// 自动迁移
db.AutoMigrate(&Book{})
|
5.4、gorm单表操作
5.4.1、添加记录
1
2
3
4
5
6
7
8
9
10
|
// 添加一条记录
b1 := Book{Title: "UI设计",Price:0}
db.Create(&b1)
fmt.Println("添加书籍的ID:",b1.ID)
// 批量插入记录
books := []Book{{Title: "西游记",Price:100},{Title: "红楼梦",Price:200},{Title: "三国演义",Price:300}}
db.Create(&books)
//每批500条创建(gorm2新添加方法)
//db.CreateInBatches(books,500)
|
5.4.2、查询记录
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
51
52
53
|
// ****************************** (1) 查询全部记录 **************************
books := []Book{}
result := db.Find(&books)
fmt.Println(result.RowsAffected )
fmt.Println(books)
for _, book := range books {
fmt.Println(book.Title,book.Price)
}
// ****************************** (2) 查询单条记录 **************************
book:=Book{}
db.First(&book) // 按id升序排序,获取第一条记录
fmt.Println(book1)
book:=Book{}
db.Last(&book) // 按id升序排序,获取最后一条记录
fmt.Println(book)
// ****************************** (3) String 条件 ***************************
db.Where("title = ?","红楼梦").First(&book)
db.Where("price <> ?",200).Find(&books)
db.Where("price between ? and ?",100,200).Find(&books)
db.Where("price in ?",[]int64{0,100,200}).Find(&books)
db.Where("title like ?","金%").Find(&books)
db.Where("create_time > ?","2021-01-01 00:00:00").Find(&books)
db.Where("publish_name = ? AND price > ?","苹果出版社",300).Find(&books)
// ****************************** (4) Struct & Map 条件 ******************************
// Struct条件
db.Where(&Book{PublishName: "苹果出版社",Price:200}).Find(&books)
// 意: 使用结构作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0、''、false 或其他 零值
// 于构建查询条件,例如:
db.Where(&Book{PublishName: "苹果出版社",Price:0}).Find(&books)
// SELECT * FROM Books WHERE PublishName = "苹果出版社";
// Map条件
db.Where(map[string]interface{}{"publish_name": "苹果出版社","price":0}).Find(&books)
// SELECT * FROM Books WHERE PublishName = "苹果出版社";
// ****************************** (5) Select、Omit语句 ******************************
db.Select("title", "price").Find(&books)
db.Omit("title", "price").Find(&books)
// ****************************** (6) Not Or语句 ******************************
// Not语句:用法类似于Where
db.Not("price between ? and ?",100,200).Find(&books)
// Or语句
db.Where("price = ?",200).Or("publish_name = ?","苹果出版社").Find(&books)
// ****************************** (7) 其他查询语句 ******************************
// 排序
db.Order("price desc, id").Find(&books)
// limit
db.Limit(2).Find(&books)
// db.Offset(3).Find(&users)
db.Limit(2).Offset(1).Find(&books)
|
5.4.3、删除记录
1
2
3
4
5
6
7
|
// 删除一条记录
book:=Book{ID: 2}
db.Delete(&book)
// 按条件删除
db.Where("price between ? and ?",200,300).Delete(Book{})
// 删除所有记录
db.Where("1 = 1").Delete(&Book{})
|
5.4.4、更新记录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 更新所有字段
book := Book{}
db.First(&book)
book.Title = "新西游记"
db.Save(&book)
// update更新单个字段
book := Book{ID: 20}
db.Model(&book).Update("title","UI设计")
book := Book{}
db.Model(&book).Where("id = ?",20).Update("title","UI设计2")
// update更新多个字段
// 通过 `struct` 更新多个字段,不会更新零值字段
book := Book{}
db.Model(&book).Where("id = ?",20).Updates(Book{Title:"UI设计3",Price: 333})
// 通过 `map` 更新多个字段,零值字段也会更新
book := Book{}
db.Model(&book).Where("id = ?",20).Updates(map[string]interface{}{"title":"UI设计4","publish_name":"西瓜出版社"})
|
5.5、gorm创建关联表
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
)
// Gorm
func main() {
// 创建日志对象
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
logger.Config{
//SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // Log level
},
)
// 连接mysql,格式如下
dsn := "root:@tcp(127.0.0.1:3306)/gobook?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger, // 日志配置
})
if err != nil {
fmt.Println("err:", err)
}
// 创建表对应的结构体
type Company struct {
ID int
Name string
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
type Language struct {
gorm.Model
Name string
}
type User struct {
gorm.Model
Name string
// belong to
CompanyID int
Company Company
// has one
// CreditCard CreditCard
// has many
CreditCard []CreditCard
// 多对多
Languages []Language `gorm:"many2many:user_languages;"`
}
db.AutoMigrate(User{})
db.AutoMigrate(Company{})
db.AutoMigrate(CreditCard{})
// db.AutoMigrate(Language{}) // 多对多的自动迁移Language
}
|
5.6、gorm创建关联记录
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
//(1)单表添加
companys:=[]Company{Company{Name: "tencent",ID: 1},Company{Name: "alibaba",ID: 2}}
db.Create(&companys)
user:=User{Name: "yuan",CompanyID: 1}
db.Create(&user)
//(2)关联添加
user=User{
Name: "alvin",
// CompanyID:1, // 已经存在
Company: Company{
ID: 3,
Name: "bytedance",
}, // 公司不存在在Company表中
}
db.Create(&user)
//(3)
user:=User{
Name: "zhangsan",
// CompanyID:1, // 已经存在
CompanyID:3, // 公司不存在在Company表中
CreditCard:[]CreditCard{
CreditCard{
Number: "1001",
UserID: 3,
},
CreditCard{
Number: "1002",
UserID: 3,
},
},
}
db.Create(&user)
//(4) 一对多添加
user:=User{
Name: "lisi",
// CompanyID:1, // 已经存在
CompanyID:2, // 公司不存在在Company表中
CreditCard:[]CreditCard{
CreditCard{
Number: "1003",
UserID: 3,
},
},
Languages:[]Language{
Language{
Name: "english",
},
Language{
Name: "chinese",
},
},
}
db.Create(&user)
// (5) 多对多添加
languages:= []Language{}
db.Where("name in ?",[]string{"english","chinese"}).Find(&languages)
user:=User{
Name: "wangwu",
// CompanyID:1, // 已经存在
CompanyID:2, // 公司不存在在Company表中
Languages:languages,
}
db.Create(&user)
|
5.7、gorm关联查询
5.7.1、Preload(子查询 )
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
51
52
53
54
55
56
57
58
59
|
// (1) 查询所有用户所在公司名
users:=[]User{}
db.Preload("Company").Find(&users)
fmt.Println(users)
/*
sql:
SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL
SELECT * FROM `companies` WHERE `companies`.`id` IN (1,3,2)
结果:
[
{3 yuan 1 {1 tencent} [] []}
{4 alvin 3 {3 bytedance} [] []}
{5 zhangsan 3 {3 bytedance} [] []}
{6 lisi 2 {2 alibaba} [] []}
{8 wangwu 2 {2 alibaba} [] []}
]
*/
// (2) 查询用户lisi所在的公司
user := User{Name: "lisi"}
db.Where(&user).Preload("Company").Find(&user)
fmt.Println(user)
/*
sql:
SELECT * FROM `users` WHERE `users`.`name` = 'lisi'
SELECT * FROM `companies` WHERE `companies`.`id` = 2
结果:
{6 lisi 2 {2 alibaba} [] []}
*/
// (3) 查询lisi的公司和掌握语言
user := User{Name: "lisi"}
db.Where(&user).Preload("Company").Preload("Languages").Find(&user)
fmt.Println(user)
/*
sql:
SELECT * FROM `users` WHERE `users`.`name` = 'lisi'
SELECT * FROM `companies` WHERE `companies`.`id` = 2
SELECT * FROM `user_languages` WHERE `user_languages`.`user_id` = 6
SELECT * FROM `languages` WHERE `languages`.`id` IN (1,2)
*/
// (4) 查询用户yuan的所有信用卡
user := User{}
db.Where("name =?","zhangsan").Preload("CreditCard").Find(&user)
fmt.Println(user.CreditCard)
/*
sql:
SELECT * FROM `users` WHERE name ='zhangsan'
SELECT * FROM `credit_cards` WHERE `credit_cards`.`user_id` = 5
结果:
[{2 1001 5} {3 1002 5}]
*/
|
5.7.2、Joins
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
|
// 案例1 查询所有用户的所有信息
users:=[]User{}
db.Joins("Company").Find(&users)
fmt.Println(users)
/*
sql:
SELECT `users`.`id`,`users`.`name`,`users`.`company_id`,
`Company`.`id` AS `Company__id`,`Company`.`name` AS `Company__name`
FROM `users` LEFT JOIN `companies` `Company`
ON `users`.`company_id` = `Company`.`id`
*/
//案例2 查询ID为5的用户的公司名称
user:=User{ID: 5}
db.Joins("Company").Find(&user)
fmt.Println(user)
fmt.Println(user.Company.Name)
/*
sql
SELECT `users`.`id`,`users`.`name`,`users`.`company_id`,`Company`.`id` AS `Company__id`,`Company`.`name` AS `Company__name`
FROM `users` LEFT JOIN `companies` `Company`
ON `users`.`company_id` = `Company`.`id`
WHERE `users`.`id` = 5
*/
|
5.7.3、Association增删改查
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
|
// (1)、Association查询
// 查看id为6的用户的掌握语言
user:= User{ID: 6}
languages:=[]Language{}
db.Model(&user).Association("Languages").Find(&languages)
fmt.Println(languages) // [{1 english} {2 chinese}]
/*
sql:
SELECT `languages`.`id`,`languages`.`name` FROM
`languages` JOIN `user_languages` ON
`user_languages`.`language_id` = `languages`.`id` AND
`user_languages`.`user_id` = 6
*/
// 查看所有用户的掌握语言信息
languages:=[]Language{}
db.Model(&User{}).Association("Languages").Find(&languages)
fmt.Println(languages)
// (2) Association添加 // upsert模式
user:=User{ID: 5}
l := Language{}
db.Where(&Language{ID: 1}).Find(&l)
db.Model(&user).Association("Languages").Append([]Language{l,Language{Name: "riyu"}})
// (3) Association删除
user:=User{ID: 5}
db.Model(&user).Association("Languages").Delete(Language{ID: 1})
db.Model(&user).Association("Languages").Clear()
// (4) Association替换
user:=User{ID: 5}
db.Model(&user).Association("Languages").Replace([]Language{Language{ID: 1},Language{ID: 7}}) // reset
db.Model(&user).Association("Languages").Replace(&Language{ID: 2},) // reset
// (5) Association计数
// ID为5的用户的掌握语言数量
user:=User{ID: 5}
c:=db.Model(&user).Association("Languages").Count()
fmt.Println(c)
|
六、中间件
七、cookie与session