Go 的gin 框架 和 gorm 和 html/template库

Gin 基础 :

Gin 的hello world :

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    engine := gin.Default()
    engine.GET("/", func(context *gin.Context) {
        context.String(http.StatusOK,"hello world!")
    })
    engine.Run()
}
View Code

Gin 的 context.Params(path 参数) :

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    engine := gin.Default()
    engine.GET("/:name/*rest", func(context *gin.Context) {
        context.String(http.StatusOK,"hello world!")
        fmt.Println(context.Params)
        params := context.Params
        fmt.Printf("%T
", params)
        ret,ok := params.Get("name")
        if ok{
            fmt.Println(ret)
        }
        fmt.Println(params[0])      
    })

    engine.Run()
}
View Code

Gin 的 context.Query (get 参数):

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    engine := gin.Default()
    engine.GET("/", func(context *gin.Context) {
        context.String(http.StatusOK,"hello world!")
        fmt.Println(context.Query("name")) // 如果不存在返回 空串  
        fmt.Println(context.DefaultQuery("name","none"))// 如果不存在返回 none  
    })
    engine.Run()
}
View Code

Gin 的 context.PostForm(post 参数):

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    engine := gin.Default()
    engine.POST("/", func(context *gin.Context) {
        context.String(http.StatusOK,"hello world")
        fmt.Println(context.PostForm("name"))
        fmt.Println(context.DefaultPostForm("name","none"))
    })
    engine.Run()
}
View Code

Gin 的HTML渲染:

package main

import (
    "github.com/gin-gonic/gin"
    "html/template"
    "net/http"
)

func main() {
    eng := gin.Default()
    eng.SetFuncMap(template.FuncMap{
        "safe": func(s string)template.HTML {
            return template.HTML(s)
        },
    })
    eng.LoadHTMLGlob("templates/**/*")
    eng.GET("/test01", func(context *gin.Context) {
        context.HTML(http.StatusOK,"test/test01.html",gin.H{
            "a":`<a href="http://www.baidu.com">百度一下</a>`,
        })
    })
    eng.Run()
}
main.go
{{define "test/test01.html"}}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>posts/index</title>
</head>
<body>
    <h3>hello test01</h3>
    {{ .a | safe }}
</body>
</html>
{{end}}
templates/test/test01.html

注意:使用自定义模板函数的时候要先 SetFuncMap 后  LoadHTMLGlob  

当HTML文件中引用了静态文件时:

package main

import (
    "github.com/gin-gonic/gin"
    "html/template"
    "net/http"
)

func main() {
    eng := gin.Default()
    eng.SetFuncMap(template.FuncMap{
        "safe": func(s string)template.HTML {
            return template.HTML(s)
        },
    })
    eng.Static("/xxx","./static")
    eng.LoadHTMLGlob("templates/**/*")
    eng.GET("/test01", func(context *gin.Context) {
        context.HTML(http.StatusOK,"test/test01.html",gin.H{
            "a":`<a href="http://www.baidu.com">百度一下</a>`,
        })
    })
    eng.Run()
}
main.go
{{define "test/test01.html"}}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>posts/index</title>
</head>
<body>
    <h3>hello test01</h3>
    {{ .a | safe }}
    <script src="xxx/js/my.js"></script>
    <script>
        printHello()
    </script>
</body>
</html>
{{end}}
templates/test/test01.html
function printHello() {
    console.log("hello world!")
}
static/js/my.js

Gin 的文件上传:

单个文件上传:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>上传文件示例</title>
</head>
<body>
<form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="f1">
    <input type="submit" value="上传">
</form>
</body>
</html>
upload.html
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "log"
    "net/http"
)

func main()  {
    eng :=gin.Default()
    eng.POST("/upload", func(context *gin.Context) {
        file,err := context.FormFile("f1")
        if err != nil {
            context.JSON(http.StatusInternalServerError,gin.H{
                "msg":err.Error(),
            })
        }

        log.Println(file.Filename)
        dst := fmt.Sprintf("D:/temp/%s",file.Filename)
        context.SaveUploadedFile(file,dst)
        context.JSON(http.StatusOK,gin.H{
            "msg":fmt.Sprintf(`%s uploaded!`,file.Filename),
        })
    })
    eng.Run()


}
main.go

多个文件上传:

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "log"
    "net/http"
)

func main()  {
    eng :=gin.Default()
    eng.POST("/upload", func(context *gin.Context) {
        // 多文件
        form,_ := context.MultipartForm()
        files := form.File["f1"]
        for idx,file := range files{
            log.Printf(file.Filename)
            dst := fmt.Sprintf("D:/temp/%s_%d",file.Filename,idx)
            context.SaveUploadedFile(file,dst)
            context.JSON(http.StatusOK,gin.H{
                "msg":fmt.Sprintf(`%s uploaded!`,file.Filename),
            })
        }
    })
    eng.Run()
}
main.go
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>上传文件示例</title>
</head>
<body>
<form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="f1" multiple>
    <input type="submit" value="上传">
</form>
</body>
</html>
upload.html

Gin 的重定向:

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    eng :=gin.Default()
    eng.GET("/test", func(context *gin.Context) {
        context.Redirect(http.StatusMovedPermanently,"http://www.baidu.com")
    })
    eng.Run()
}
main.go 

Gin 的请求的转发:

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    eng :=gin.Default()
    eng.GET("/a", func(context *gin.Context) {
        context.Request.URL.Path = "/b"
        eng.HandleContext(context)
    })
    eng.GET("/b", func(context *gin.Context) {
        context.JSON(http.StatusOK,gin.H{
            "msg":"ok2",
        })
    })
    eng.Run()
}
main.go

Gin 的路由:

context.Any() 可以接受任何方式的请求,

context.NoRoute() 处理没有匹配的路由,404 请求,

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    eng :=gin.Default()
    eng.LoadHTMLGlob("templates/*")
    eng.NoRoute(func(context *gin.Context) {
        context.HTML(http.StatusNotFound,"404.html",nil)
    })
    eng.Run()
}
main.go

路由组:

习惯性一对{}包裹同组的路由,只是为了看着清晰,用不用{}包裹功能上没什么区别。

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    eng :=gin.Default()
    eng.LoadHTMLGlob("templates/*")
    eng.NoRoute(func(context *gin.Context) {
        context.HTML(http.StatusNotFound,"404.html",nil)
    })
    userGroup := eng.Group("/user")
    {
        userGroup.GET("/index", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"user_index"})
        })
        userGroup.GET("/login", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"user_login"})
        })
    }
    adminGroup := eng.Group("/admin")
    {
        adminGroup.GET("/index", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"admin_index"})
        })
        adminGroup.GET("/login", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"admin_login"})
        })
    }
    eng.Run()
}
main.go

路由组也可以嵌套:

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
func main()  {
    eng :=gin.Default()
    eng.LoadHTMLGlob("templates/*")
    eng.NoRoute(func(context *gin.Context) {
        context.HTML(http.StatusNotFound,"404.html",nil)
    })
    userGroup := eng.Group("/user")
    {
        userGroup.GET("/index", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"user_index"})
        })
        userGroup.GET("/login", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"user_login"})
        })
        vipGroup := userGroup.Group("/vip")
        {
            vipGroup.GET("/index", func(context *gin.Context) {
                context.JSON(http.StatusOK,gin.H{"msg":"user_vip_index"})
            })
            vipGroup.GET("/login", func(context *gin.Context) {
                context.JSON(http.StatusOK,gin.H{"msg":"user_vip_login"})
            })
        }
    }
    adminGroup := eng.Group("/admin")
    {
        adminGroup.GET("/index", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"admin_index"})
        })
        adminGroup.GET("/login", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"admin_login"})
        })
    }
    eng.Run()
}
main.go

Gin 的绑定数据到结构体上:

form表单,json格式,

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)

type myData struct {
    Username string `form:"username" json:"user" binding:"required"`
    Password string `form:"password" json:"pwd" binding:"required"`
}
func main()  {
    eng :=gin.Default()
    eng.POST("/", func(context *gin.Context) {
        var d myData
        // Content-type 为 multipart/form-data // POST 表单上传
        //err := context.Bind(&d) // Bind 可以解析form 格式
        //if err != nil {
        //    fmt.Println("bind data to struct failed,err:",err)
        //    return
        //}
        //fmt.Println(d.Username)
        //fmt.Println(d.Password)

        //Content-type 为 application/json 格式
        err := context.ShouldBindUri(&d)
        if err != nil {
            fmt.Println("bind data to struct failed,err:",err)
            return
        }
        fmt.Println(d.Username)
        fmt.Println(d.Password)
        context.JSON(http.StatusOK,gin.H{"msg":"ok"})
    })

    eng.Run()
}
main.go

uri:(path 路径)

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)

type myData struct {
    Username string `uri:"name" binding:"required"`
    Password string `uri:"pwd"  binding:"required"`
}
func main()  {
    eng :=gin.Default()
    eng.GET("/:name/:pwd", func(context *gin.Context) {
        var d myData
        err := context.ShouldBindUri(&d)
        if err != nil {
            fmt.Println("bind data to struct failed,err:",err)
            return
        }
        fmt.Println(d.Username)
        fmt.Println(d.Password)

        context.JSON(http.StatusOK,gin.H{"msg":"ok"})
    })
    eng.Run()
}
main.go

Gin 的中间件: 

全局中间件(contex.Next() 和 context.Abort() )

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)

// 请求耗时的中间件函数
func countReqTime()gin.HandlerFunc  {
    return func(context *gin.Context) {
        start := time.Now()
        m := make(map[string]interface{})
        m["name"] = "tom"
        m["age"] = 18
        context.Set("data",m) // 可以通过context.Set在请求上下文中设置值,后续的处理函数能够取到该值

        time.Sleep(time.Second)

        res := time.Since(start)
        fmt.Println("耗时:",res)
        context.Next()


    }
}
// 打印 hello world 的中间件
func printHello()gin.HandlerFunc  {
    return func(context *gin.Context) {
        fmt.Println("hello world")

        context.Next() // 如果使用 context.Abort()  请求会到此返回,洋葱模型
    }
}

func main()  {
    eng :=gin.Default()
    // 注册两个全局中间件
    eng.Use(printHello())
    eng.Use(countReqTime())
    // {} 是为了代码规范
    eng.GET("/", func(context *gin.Context) {
        fmt.Println(context.Get("data"))
        context.JSON(http.StatusOK,gin.H{"msg":"ok"})
    })
    eng.Run()
}
main.go

局部中间件(给单个路由 设置中间件)

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)

// 打印 hello world 的中间件
func printHello()gin.HandlerFunc  {
    return func(context *gin.Context) {
        fmt.Println("hello world")

        context.Next() // 如果使用 context.Abort()  请求会到此返回,洋葱模型
    }
}

func main()  {
    eng :=gin.Default()
    eng.GET("/",printHello(), func(context *gin.Context) {
        context.JSON(http.StatusOK,gin.H{"msg":"ok"})
    })
    eng.Run()
}
main.go

给路由组加上中间件:

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
)

func printHello() gin.HandlerFunc  {
    return func(context *gin.Context) {
        fmt.Println("hello world")
        context.Next()
    }
}


func main()  {
    eng :=gin.Default()
    eng.LoadHTMLGlob("templates/*")
    eng.NoRoute(func(context *gin.Context) {
        context.HTML(http.StatusNotFound,"404.html",nil)
    })
    // 方式一
    //userGroup := eng.Group("/user",printHello())
    //{
    //    userGroup.GET("/index", func(context *gin.Context) {
    //        context.JSON(http.StatusOK,gin.H{"msg":"user_index"})
    //    })
    //    userGroup.GET("/login", func(context *gin.Context) {
    //        context.JSON(http.StatusOK,gin.H{"msg":"user_login"})
    //    })
    //}

    // 方式二
    userGroup := eng.Group("/user")
    userGroup.Use(printHello())
    {
        userGroup.GET("/index", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"user_index"})
        })
        userGroup.GET("/login", func(context *gin.Context) {
            context.JSON(http.StatusOK,gin.H{"msg":"user_login"})
        })
    }


    eng.Run()
}
main.go

默认中间件:

Gin 的获取设置Cookie: 

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func main()  {
    eng :=gin.Default()
    eng.GET("/", func(context *gin.Context) {
        // 获取客户端cookie
        cookie,err := context.Cookie("xxx")
        if err != nil {
            fmt.Println("get cookie failed,err:",err)
            // 给客户端设置 cookie
            // name, value string, maxAge(过期时间) int, path, domain string, secure(是否https), httpOnly(是否允许通过js 获取cookie) bool
            context.SetCookie("xxx","value_cookie",60,"/","localhost",false,false)
            return
        }
        fmt.Println(cookie)
    })
    eng.Run()
}
View Code

Go Session: 

https://files.cnblogs.com/files/zach0812/go%E7%9A%84session.zip

处理请求使用异步:

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)
func main()  {
    eng :=gin.Default()
    // 1 异步
    eng.GET("/", func(context *gin.Context) {
        // 不能直接使用 context 上下文
        copyCtx := context.Copy()
        go func() {
            time.Sleep(3*time.Second)
            fmt.Println("async",copyCtx.Request.URL)
        }()
        context.JSON(http.StatusOK,gin.H{"msg":"ok"})
    })
    // 2 同步
    eng.GET("/2", func(context *gin.Context) {
        time.Sleep(3*time.Second)
        fmt.Println("sync",context.Request.URL)
        context.JSON(http.StatusOK,gin.H{"msg":"ok"})
    })

    eng.Run()
}
main.go

Go 的 html/template 标准库 模板渲染:

模板语法 和 自定义函数 和 嵌套HTML:

package main

import (
    "fmt"
    "html/template"
    "net/http"
)

type userInfo struct {
    Name string
    Sex string
    Age int
}
// 自定义一个函数
func myFunc (arg string) string{
    return "hello "+arg+" ;this is my function!"
}
func sayHello(response http.ResponseWriter,request *http.Request)  {
    tmpl,err := template.New("hello.html").Funcs(template.FuncMap{"myFunc":myFunc}).ParseFiles("./hello.html","./test.html")
    if err != nil {
        fmt.Println("create template failed,err:",err)
        return
    }
    user := userInfo{
        Name: "tom",
        Sex: "",
        Age:18,
    }

    m := make(map[string]interface{})
    m["user"]= user
    m["hobby"] = []string{"Basketball","Movie"}
    tmpl.Execute(response,m)
}

func main()  {
    http.HandleFunc("/",sayHello)
    err := http.ListenAndServe(":9000",nil)
    if err != nil {
        fmt.Println("HTTP server failed,err:",err)
        return
    }

}
main.go
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hello</title>
</head>
<body>
    <h3>我靠,无情</h3>
    <p>Name {{.user.Name}}</p>
    <p>Sex {{.user.Sex}}</p>
    <p>Age {{.user.Age}}</p>
    <hr>
    <ul>
        {{range $idx,$hobby := .hobby}}
            <li>{{$idx}} --- {{$hobby}}</li>
        {{end}}
    </ul>
    <ul>
        {{range .hobby}}
        <li>{{.}}</li>
        {{end}}
    </ul>
    <hr>
    <p>{{$v1 := 0}}</p>
    <p>{{$v1}}</p>
    <p>{{$age := .user.Age}}</p>
    <p>{{$age}}</p>

    <hr>
    {{if $v1}}
        <p>Hello</p>
    {{else}}
        <p>World</p>
    {{end}}
    <hr>
    {{with .user}}
        <p>{{.Name}}</p>
        <p>{{.Age}}</p>
        <p>{{.Sex}}</p>
    {{end}}
    <hr>
    <h3>自定义函数</h3>
    {{myFunc "tom"}}
    <hr>
    <h3>嵌套其他的 template</h3>
    {{template "test.html"}}
    <hr>
    {{template "test02.html"}}
    <hr>
</body>
</html>


{{ define "test02.html"}}
    <ol>
        <li>吃饭</li>
        <li>睡觉</li>
        <li>打豆豆</li>
    </ol>
{{end}}
hello.html
<ul>
    <li>注释</li>
    <li>日志</li>
    <li>测试</li>
</ul>
test.html

模板继承:

package main

import (
    "fmt"
    "html/template"
    "net/http"
)

func test(response http.ResponseWriter,request *http.Request)  {
    tmpl,err := template.ParseFiles("base.html","index.html")
    if err != nil {
        fmt.Println("parse index.html failed,err:",err)
        return
    }
    name := "tom"
    //tmpl.Execute(response,name)
    tmpl.ExecuteTemplate(response,"index.html",name)
}

func main()  {
    http.HandleFunc("/",test)
    err := http.ListenAndServe(":9000",nil)
    if err != nil {
        fmt.Println("HTTP server failed,err:",err)
        return
    }
}
main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{block "xx" .}}
    {{end}}
</body>
</html>
base.html
{{template "base.html" .}}

{{define "xx"}}
    <h3>Hello {{.}}</h3>
    <div>Hello World</div>
{{end}}
index.html

安全标签:

package main

import (
    "fmt"
    "html/template"
    "net/http"
)

func test(response http.ResponseWriter,request *http.Request)  {
    tmpl,err := template.New("test.html").Funcs(
        template.FuncMap{
            "safe": func(s string)template.HTML {
                return template.HTML(s)
            },
        }).ParseFiles("./test.html")
    if err != nil {
        fmt.Println("parse test.html failed,err:",err)
        return
    }
    s := `<script>alert("hello world")</script>`
    tmpl.Execute(response,s)
}

func main()  {
    http.HandleFunc("/",test)
    err := http.ListenAndServe(":9000",nil)
    if err != nil {
        fmt.Println("HTTP server failed,err:",err)
        return
    }
}
main.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{. | safe}}
</body>
</html>
test.html

gorm :

官网: https://gorm.io/zh_CN/docs/

安装:

go get -u github.com/jinzhu/gorm

初始化数据库(mysql):

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Person struct {
    gorm.Model
    Name string
    Age int
}


func initDB()*gorm.DB  {
    db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println("gorm open msyql failed,err",err)
        return nil
    }

    // 自动迁移
    db.AutoMigrate(&Person{})

    return db
}
func main() {
    db := initDB()
    defer db.Close()

    // 创建
    //for i := 1; i < 20; i++ {
    //    db.Create(&Person{Name: fmt.Sprintf("tom%d",i),Age: 18+i})
    //    time.Sleep(10*time.Second)
    //}



}
View Code

建表:

指定名称建表

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Book struct {
    gorm.Model
    Title string
    price float64
}

func createTable(db *gorm.DB)  {
    // 指定名称 建表
    db.Table("my_book").CreateTable(&Book{})
}
func initDB()*gorm.DB  {
    db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println("gorm open msyql failed,err",err)
        return nil
    }
    return db
}
func main() {
    db := initDB()
    defer db.Close()
    createTable(db)
    db.AutoMigrate(&Book{})
    
    // 增 删 改 查 

}
View Code

增:

package main

import (
    "database/sql"
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Person struct {
    gorm.Model
    Name sql.NullString `gorm:"default:'tom'"`
    Age int
}

func insert(db *gorm.DB)  {
    //=================创建记录====================
    //db.Create(&Person{Name: "tommm",Age: 18})

    // 关于默认值 相关 !!!  
    // 如果通过 tag 定义字段的默认值,那么生成的 SQL 语句会排除没有值或值为 零值 的字段。 将记录插入到数据库后,Gorm会从数据库加载那些字段的值。
    // 解决方法 :考虑使用指针或实现 Scanner/Valuer 接口
    //db.Create(&Person{Name: "",Age: 22})

    // 1,通过指针的方式
    // 此时结构体应该:
    /*
    type Person struct {
        gorm.Model
        Name *string `gorm:"default:'tom'"`
        Age int
    }
    */
    //db.Create(&Person{Name: new(string),Age: 33})

    //2 通过实现 Scanner/Valuer 接口
    // 此时结构体应该:
    /*
        type Person struct {
            gorm.Model
            Name *string `gorm:"default:'tom'"`
            Age int
        }
    */
    //db.Create(&Person{Name: sql.NullString{String: "",Valid: true},Age: 44})

}


func initDB()*gorm.DB  {
    db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println("gorm open msyql failed,err",err)
        return nil
    }

    // 自动迁移
    db.AutoMigrate(&Person{})

    return db
}
func main() {
    db := initDB()
    defer db.Close()

    // 增
    insert(db)

}
View Code

查询: 

单表查询:

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Person struct {
    gorm.Model
    Name string
    Age int
}

// 查询
func query(db *gorm.DB)  {
    //=================普通查询====================
    //1,第一条记录
    //var p Person
    //db.First(&p)
    //fmt.Println(p)

    //2,最后一条记录
    //var p Person
    //db.Last(&p)
    //fmt.Println(p)

    // 查询指定的某条记录(仅当主键为整型时可用)
    //var p Person
    //db.First(&p, 10)
    //fmt.Println(p)

    //3,全部数据
    //var l []Person
    //db.Find(&l)
    //fmt.Println(l)

    //=================where 查询====================
    //4 where 条件
    // 获取第一个匹配的记录
    //var p Person
    //db.Where("name=?","tom").First(&p)
    //fmt.Println(p)

    // 获取所有匹配的记录
    //var l []Person
    //db.Where("name=?","tom").Find(&l)
    //fmt.Println(l)

    // <>
    //var l []Person
    //db.Where("name <> ?","tom").Find(&l)
    //fmt.Println(l)

    // IN
    //var l []Person
    //db.Where("name IN (?)",[]string{"tom","tom2"}).Find(&l)
    //fmt.Println(l)

    // LIKE
    //var l []Person
    //db.Where("name LIKE ?","%tom_").Find(&l)
    //fmt.Println(l)

    // AND
    //var l []Person
    //db.Where("name = ? AND age > ?","tom",28).Find(&l)
    //fmt.Println(l)

    // Time
    //var l []Person
    //t := time.Now().Add(-time.Hour*2) // 两小时之前 创建的
    //db.Where("created_at < ?",t).Find(&l)
    //fmt.Println(l)

    // BETWEEN  【 】
    //var l []Person
    //db.Where("age BETWEEN ? AND ?",25,30).Find(&l)
    //fmt.Println(l)

    //=================Not 条件====================

    //var l []Person
    //db.Not("name","tom").Find(&l)
    //fmt.Println(l)

    // Not In
    //var l []Person
    //db.Not("name",[]string{"tom","tom11","tom18","tom19"}).Find(&l)
    //fmt.Println(l)


    //=================Or 条件====================
    //var l []Person
    //db.Where("name='tom'").Or("age>32").Or("id<3").Find(&l)
    //fmt.Println(l)


    //=================高级查询====================
    //=================子查询====================
    //var l []Person
    //db.Where("age > ?", db.Table("people").Select("AVG(age)").SubQuery()).Find(&l) // person 表 存入数据库中默认名字是 people
    //fmt.Println(l)

    //=================Select 选择字段====================
    //var l []Person
    //db.Find(&l)// 全部字段
    //fmt.Println(l)

    //var l []Person
    //db.Select( "name,age").Find(&l) // 只有name age 有值 其余为nil
    //fmt.Println(l)

    //=================排序====================
    //var l []Person
    //db.Order("name,age desc").Find(&l) // name 升序 age 降序
    //fmt.Println(l)

    //=================Limit ====================
    //var l []Person
    //db.Limit(3).Find(&l)
    //fmt.Println(l)

    //=================偏移====================
    //开始返回记录前要跳过的记录数

    //var l []Person
    //db.Offset(3).Limit(10).Find(&l)
    //fmt.Println(l)

    //=================Count====================
    //var count int
    //var l []Person
    //db.Where("name='tom'").Find(&l).Count(&count)
    //fmt.Println(count)

    //db.Table("people").Where("name='tom'").Count(&count) // Count 必须是链式查询的最后一个操作
    //fmt.Println(count)

    //=================Group & Having==================== // Having 是 分组之后筛选 ,where 是分组之前筛选
    //rows

    //rows, err := db.Table("people").Select("name,sum(age) as s").Group("name").Having("s>30").Rows()
    //if err != nil {
    //    fmt.Println("group by name failed,err:",err    )
    //    return
    //}
    //var name string
    //var s int
    //for rows.Next(){
    //    err := rows.Scan(&name,&s)
    //    if err != nil {
    //        fmt.Println(err)
    //        return
    //    }
    //    fmt.Println(name,s)
    //}

    // 直接Scan
    //type temp struct {
    //    Name string
    //    S int
    //}
    //var l []temp
    //db.Table("people").Select("name,sum(age) as s").Group("name").Having("s>30").Scan(&l)
    //fmt.Println(l)


    //=================连接 Join (left join,right join,inner join ) ====================
    // manager 表结构  id name addr 

    //rows, _ := db.Table("people").Select("people.name,people.age, manager.addr").Joins("inner join manager on people.name = manager.name").Rows()
    //var name string
    //var age int
    //var addr string
    //for rows.Next() {
    //    rows.Scan(&name,&age,&addr)
    //    fmt.Println(name,age,addr)
    //}



    //type temp struct {
    //    Name string
    //    Age int
    //    Addr string
    //}
    //var l []temp
    //db.Table("people").Select("people.name,people.age, manager.addr").Joins("inner join manager on people.name = manager.name").Scan(&l)
    //fmt.Println(l)



}

func initDB()*gorm.DB  {
    db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println("gorm open msyql failed,err",err)
        return nil
    }

    // 自动迁移
    db.AutoMigrate(&Person{})

    return db
}
func main() {
    db := initDB()
    defer db.Close()

    // 查询
    //query(db)




}
View Code

更新: 

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Person struct {
    gorm.Model
    Name string
    Age int
}

func update(db *gorm.DB)  {
    // 先找到 再修改
    //================= 常用Update ====================
    //================= 常用Update ====================
    //================= 常用Update ====================
    //================= 常用Update ====================
    //================= 常用Update ====================
    //================= 常用Update ====================
    // 常用1
    //db.Table("people").Where("id=12").Update("name","ahtom")


    // 常用2
    //var p Person
    //db.Model(&p).Where("id=12").Update("name","yyytom")

    //=================Save 更新====================
    // Save会更新所有字段,即使你没有赋值
    //var p Person
    //db.Where("id=10").Find(&p)
    //fmt.Println(p)

    //p.Name = "newtom"
    //db.Save(&p)

    //db.Where("id=10").Find(&p)
    //fmt.Println(p)

    //=================Update====================
    //如果你只希望更新指定字段,可以使用Update或者Updates
    //var p Person
    //db.Where("id=11").Find(&p)
    //fmt.Println(p)
    //
    //db.Model(&p).Update("name","xxxtom")
    //
    //db.Where("id=11").Find(&p)
    //fmt.Println(p)
    

    //=================更新多个属性====================
    // 使用 struct 更新多个属性,只会更新其中有变化且为非零值的字段
    //var p Person
    //db.Model(&p).Where("id=12").Updates(Person{Name: "hellotomtom", Age: 19})

    //// 警告:当使用 struct 更新时,GORM只会更新那些非零值的字段
    //// 对于下面的操作,不会发生任何更新,"", 0, false 都是其类型的零值
    //db.Model(&user).Updates(User{Name: "", Age: 0, Actived: false})


    // 使用 map 更新多个属性,只会更新其中有变化的属性
    //var p Person
    //db.Model(&p).Where("id=12").Updates(map[string]interface{}{"name": "hellotom", "age": 18})


    //=================无Hooks 更新====================
    //上面的更新操作会自动运行 model 的 BeforeUpdate, AfterUpdate 方法,更新 UpdatedAt 时间戳, 在更新时保存其 Associations, 如果你不想调用这些方法,你可以使用 UpdateColumn, UpdateColumns

    // 单个属性
    //var p Person
    //db.Model(&p).Where("id=14").UpdateColumn("name","zzztom")
    //fmt.Println(p) // 只返回更新的字段

    // 多个属性
    //var p Person
    //db.Model(&p).Where("id=14").UpdateColumn(&Person{Name: "tomtom",Age: 22})
    //fmt.Println(p) // 只返回更新的字段

    //=================批量更新====================
    //批量更新时 Hooks 不会运行
    //db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(&Person{Name: "hello0123", Age: 23})
    //// UPDATE users SET name='hello0123', age=23 WHERE id IN (10, 11,12,13);


    // 使用 struct 更新时,只会更新非零值字段,若想更新所有字段,请使用map[string]interface{}
    //db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(&Person{Name: "", Age: 23}) // 不能更新 零值字段

    //db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(map[string]interface{}{"name":"","age":10}) // 不能更新 零值字段

    // 使用 `RowsAffected` 获取更新记录总数
    //ret := db.Table("people").Where("id IN (?)", []int{10, 11,12,13}).Updates(&Person{Name: "xxxyyyzzz", Age: 23}).RowsAffected
    //fmt.Println(ret)

    //=================使用 SQL 表达式更新====================
    //db.Table("people").Where("id=10").Update("age",gorm.Expr("age * ? + ?",2,10))



}

func initDB()*gorm.DB  {
    db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println("gorm open msyql failed,err",err)
        return nil
    }

    // 自动迁移
    db.AutoMigrate(&Person{})

    return db
}
func main() {
    db := initDB()
    defer db.Close()

    // 更新
    update(db)

}
View Code

删除: 

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Person struct {
    gorm.Model
    Name string
    Age int
}

func delete(db *gorm.DB)  {

    //=================删除====================
    //警告 删除记录时,请确保主键字段有值,GORM 会通过主键去删除记录,如果主键为空,GORM 会删除该 model 的所有记录。
    //db.Where("id=2").Delete(&Person{})


    //=================批量删除====================
    // 删除所有匹配的记录
    //db.Where("id IN (?)",[]int{10,11,12}).Delete(&Person{})


    //=================软删除====================
    //如果一个 model 有 DeletedAt 字段,他将自动获得软删除的功能! 当调用 Delete 方法时, 记录不会真正的从数据库中被删除, 只会将DeletedAt 字段的值会被设置为当前时间

    // 查询记录时会忽略被软删除的记录
    //var l []Person
    //db.Where("id BETWEEN ? AND ?",1,20).Find(&l)
    //fmt.Println(l)
    //// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;


    // Unscoped 方法 返回的是 包含 已经软删除的所有记录
    //var l []Person
    //db.Unscoped().Where("id BETWEEN ? AND ?",1,20).Find(&l)
    //fmt.Println(l)

    // 查询deleted_at 是 NULL 的 记录 (自己手工查的话)
    //var l []Person
    //db.Where("deleted_at is null").Find(&l)
    //fmt.Println(l)

    // 查询已经被软删除的字段
    //var l []Person
    //db.Unscoped().Where("deleted_at is not null").Find(&l)
    //fmt.Println(l)

    //=================物理删除====================
    //db.Unscoped().Where("id=1").Delete(&Person{}) // 真正删除 该记录
}

func initDB()*gorm.DB  {
    db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println("gorm open msyql failed,err",err)
        return nil
    }

    // 自动迁移
    db.AutoMigrate(&Person{})

    return db
}
func main() {
    db := initDB()
    defer db.Close()

    // 删除
    delete(db)



}
View Code

一对一,一对多,多对多:

package main

import (
    "fmt"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
)

type Author struct {
    gorm.Model
    Name string
    Books []Book `gorm:"many2many:author_books;"` // Many to Many
}
// 一个Author 对应一个 AuthorInfo
type AuthorInfo struct {
    gorm.Model
    Addr string
    Qq string
    Author Author  // belongs to 如果写在Author中就是 Has one // 一对一
    AuthorID int `gorm:"unique"` // 一对一
}

// 一个出版社出版 多本书 ,一本书只能由一个出版社出版
type Press struct {
    gorm.Model
    Name string
    Books []Book // Has Many  // 一对多
}
type Book struct {
    gorm.Model
    Title string
    PressID int // 一对多
    Authors []Author `gorm:"many2many:author_books;"` // Many to Many
}

func initDB()*gorm.DB  {
    db,err := gorm.Open("mysql","root:123456@(localhost)/go_mysql?charset=utf8mb4&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println("gorm open msyql failed,err",err)
        return nil
    }
    return db
}

func main() {
    db := initDB()
    defer db.Close()

    db.AutoMigrate(&Author{},&AuthorInfo{},&Press{},&Book{})
    //=================一对一====================
    //一对一 创建
    //author := Author{Name: "xxx"}
    //db.Create(&author)
    //db.Create(&AuthorInfo{Addr: "中山街大道",Qq: "1056768935",Author: author})

    // 一对一 查询
    //var author Author
    //var info AuthorInfo
    //db.Find(&author,1)
    //db.Model(&author).Related(&info)
    //fmt.Println(info)


    //=================一对多====================
    //一对多 创建
    //book1 := Book{Title: "钢铁是怎样炼成的"}
    //book2 := Book{Title: "红楼梦"}
    //book3 := Book{Title: "西游记"}
    //db.Create(&book1)
    //db.Create(&book2)
    //db.Create(&book3)
    //db.Create(&Press{Name: "胜利出版社",Books: []Book{
    //    book1,
    //    book2,
    //    book3,
    //}})
    // 一对多 查询
    //var press Press
    //var books []Book
    //db.Find(&press,1)
    //db.Model(&press).Related(&books)
    //fmt.Println(books)

    //=================多对多====================
    // 创建多对多
    // id为1 Book 是由 id 为1,2 的两位作者写的
    //var author1 Author
    //var author2 Author
    //db.Find(&author1,1)
    //db.Find(&author2,2)
    //
    //var book Book
    //db.Find(&book,1)
    //book.Authors=[]Author{
    //    author1,
    //    author2,
    //}
    //db.Save(&book)

    // id 为2 Book 是由 id 为1 的作者写的
    //var author1 Author
    //db.Find(&author1,1)
    //
    //var book Book
    //db.Find(&book,2)
    //book.Authors=[]Author{author1}
    //db.Save(&book)

    // id 为3 Book 是由 id 为2 的作者写的
    //var author1 Author
    //db.Find(&author1,2)
    //
    //var book Book
    //db.Find(&book,3)
    //book.Authors=[]Author{author1}
    //db.Save(&book)


    // 多对多 查询
    // 正向查询
    // id 为1的书 的作者都有谁
    //var book Book
    //db.Find(&book,1)
    //var authors []Author
    //db.Model(&book).Related(&authors,"Authors")
    //fmt.Println(authors)

    // 查询id 为1 的作者写了哪几本书
    // 反向查询
    //var author Author
    //db.Find(&author,1)
    //
    //var books []Book
    //db.Model(&author).Related(&books,"Books")
    //fmt.Println(books)


    //=====================================
    // 数据库中现在是: 作者1 写了1,2 两本书 作者2 写了2,3两本书
    // 写了 2这本书的 作者的 详细信息
    //var book Book
    //db.Find(&book,2)
    //var authors []Author
    //db.Model(&book).Related(&authors,"Authors")
    //fmt.Println(authors)
    //m := make(map[string]interface{},10)
    //for idx,author :=  range authors{
    //    var info AuthorInfo
    //    db.Model(&author).Related(&info)
    //    k := strconv.Itoa(idx)
    //    temp := make(map[string]interface{},3)
    //    temp["author_name"] = author.Name
    //    temp["author_addr"] = info.Addr
    //    temp["author_qq"] = info.Qq
    //    m[k] = temp
    //}
    //author_data,_ := json.Marshal(m)
    //fmt.Println(string(author_data))

}
View Code

 

原文地址:https://www.cnblogs.com/zach0812/p/12856519.html