zoukankan      html  css  js  c++  java
  • 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

     

  • 相关阅读:
    英语语法学习
    react-hook
    rrweb手机端录屏,pc端使用
    uni-app
    日期
    Mongodb 保存地理信息 并实现范围检索
    webpack2.2API阅读笔记
    react-lazyload
    项目中常用的各个依赖包的解释
    Android-----test----monkeyrunner
  • 原文地址:https://www.cnblogs.com/zach0812/p/12856519.html
Copyright © 2011-2022 走看看