Gin框架

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
import "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{
             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, "
", 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

原文地址:https://www.cnblogs.com/bubu99/p/14797990.html