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\n", 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

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM