头像

bseazh




离线:49分钟前



bseazh
17小时前

GORM连接MySQL

GORM入门指南

演示样例

package main

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

// 定义结构体
// 命名规则 以大写为间隔分开,大写变小写,最后加's'
type UseInfo struct{
    Name string
    Gender string
    Hobby string
}

func main(){
    db , err := gorm.Open("mysql",
        "root:root@tcp(127.0.0.1:3306)/db1?charset=utf8&mb4&parseTime=True&loc=Local")
    if err != nil{
        fmt.Printf("")
        panic(err)
    }
    defer db.Close()

    fmt.Printf("成功连接数据库!\n")
    //创建表: 自动迁移
    db.AutoMigrate(UseInfo{})
    // 添加行
    user := UseInfo{
        Name :"靓仔",
        Gender: "男",
        Hobby:"媾女",
    }
    db.Create(&user)

    // 查询
    db.First(&user)
    fmt.Printf("%#v\n",user)

    // 更新
    db.Model(&user).Update("hobby","泡妞")
    fmt.Printf("%#v\n",user)

    // 删除
    db.Delete(&user)
}

上课笔记

  • Mac版本命令行打开mysql, "mysql -u root -p"
  • Open("mysql","root:root@tcp(127.0.0.1:3306)/db1?charset=utf8&mb4&parseTime=True&loc=Local")
  • 账号:密码@(IP:端口号)/数据库名称?,charset=中文编码&mb4,parseTime=True,loc=Local
  • AutoMigrate,自动迁移创建表
  • db.Create(&user),创建行,添加数组,记住一定要传指针
  • db.First(&user),查询第一行,记住一定是要传指针
  • db.Model(&user).Update("hobby","泡妞"),对应的字段更新
  • db.Delete(&user),删除与user值相匹配的行



bseazh
18小时前

Gin框架中间件

Gin框架介绍及使用

package main

import(
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)
func indexHandler( c *gin.Context ){
    fmt.Printf("index...\n")
    name , ok := c.Get("name") // 从上下文取值(跨中间件存取值)
    if !ok {
        name = "匿名用户"
    }
    c.JSON(http.StatusOK,gin.H{
        "username":name,
    })

}
// 定义一个中间件m1;统计请求处理函数的耗时
func m1( c *gin.Context ){

    fmt.Printf("m1 in...\n")
    start := time.Now()
    // 计时
    c.Next() // 调用后续的处理函数
    //c.Abort() // 阻止后续的函数执行
    cost := time.Since(start)
    fmt.Printf("cost : %v\n",cost)
    fmt.Printf("m1 out ... \n")
}

// 定义m2的中间件来测试
func m2( c * gin.Context ){
    c.Set("name","靓仔")
    fmt.Printf("m2 in ...\n")
    c.Next()
    fmt.Printf("m2 out ...\n")
}

func authMiddleware( doCheck bool  ) func(*gin.Context){
    // 连接数据库
    // 或者做一些其他准备工作
    return func(c *gin.Context){
        if doCheck {
            // 存放具体的逻辑
            // 是否登录的判断
            // if 是登录用户
                    c.Next()
            // else 不是登录用户
            //      c.Abort()
        }else{
            c.Next()
        }
    }
}

func main(){
    r := gin.Default() // Logger 和 Recovery 中间件
    // 其中Logger用于写日志
    // Recovery用于错误处理
    r.Use(m1,m2,authMiddleware(true))
    // GET(relativePath string , handlers... HandlerFunc ) IRoutes
    r.GET("/index", indexHandler)
    r.GET("/user", indexHandler)
    r.GET("/shop", indexHandler)

    //路由组注册中间件  方法1:
    //xxGroup := r.Group("/xx",authMiddleware(true))
    //{
    //  xxGroup.GET("/index", func(c *gin.Context) {
    //      c.JSON(http.StatusOK,gin.H{
    //          "msg":"/xx/index",
    //      })
    //  })
    //}
    ////路由组注册中间件  方法2:
    //xx2Group := r.Group("/xx2")
    //xx2Group.Use(authMiddleware(true))
    //{
    //  xx2Group.GET("/index", func(c *gin.Context) {
    //      c.JSON(http.StatusOK,gin.H{
    //          "msg":"/xx2/index",
    //      })
    //  })
    //}
    r.Run()
}

上课笔记

  • 中间件的使用方法:GET(relativePath string , handlers... HandlerFunc ) IRoutes或者r.Use(m1,m2,authMiddleware(true))
  • 中间件的使用场景:对于没有权限的用户隔绝观看相关页面,又如没有登录的用户不能点击货物进入购物车,必须限制其进入下一个支付页面,同时返回相应的登录界面。
  • c.Next():中间件函数,继续后续的路由函数的执行
  • c.Abort():阻止接下来的路由函数运行
  • 路由组添加其中间件
  • 方法1:xxGroup := r.Group("/xx",authMiddleware(true))
  • 方法2:xx2Group := r.Group("/xx2")然后xx2Group.Use(authMiddleware(true))
  • r := gin.Default() 里面默认包含Logger和Recovery中间件,其中Logger用于写日志,Recovery用于错误处理
  • 从上下文取值(跨中间件存取值)
  • c.Set("name","靓仔")
  • name , ok := c.Get("name")



bseazh
23小时前

gin路由和路由组

Gin框架介绍及使用

演示实例

package main

import(
    "github.com/gin-gonic/gin"
    "net/http"
)
func main(){
    r := gin.Default()
    // 请求方法的大集合 / 大杂烩
    r.Any("/user", func(c *gin.Context) {
        switch c.Request.Method{
        case http.MethodGet:
            c.JSON(http.StatusOK,gin.H{
                "Method":"Get",
            })
        case http.MethodPost:
            c.JSON(http.StatusOK,gin.H{
                "Method":"Post",
            })
        case http.MethodDelete:
            c.JSON(http.StatusOK,gin.H{
                "Method":"Delete",
            })
        }
    })
    //NoRoute
    r.NoRoute(func(c *gin.Context) {
        c.JSON(http.StatusNotFound,gin.H{
            "Message" : "Notfound",
        })
    })
    // 路由组的组 多用于区分不同业务线或API
    // 把公用的前缀提取出来,创建一个路由组
    videoGroup := r.Group("/video")
    {
        videoGroup.GET("index", func(c *gin.Context) {
            c.JSON(http.StatusOK,gin.H{
                "Message":"/video/index",
            })
        })
        videoGroup.GET("home", func(c *gin.Context) {
            c.JSON(http.StatusOK,gin.H{
                "Message":"/video/home",
            })
        })
        videoGroup.GET("user", func(c *gin.Context) {
            c.JSON(http.StatusOK,gin.H{
                "Message":"/video/user",
            })
        })
    }
    r.Run()
}

上课笔记

  • r.Any("/user", func(c *gin.Context){...}访问/user的任意方法 利用switch来分别编写不同请求方法对应不同的处理函数即可
    switch c.Request.Method{
    case http.MethodGet:
        c.JSON(http.StatusOK,gin.H{
            "Method":"Get",
        })
    case http.MethodPost:
        c.JSON(http.StatusOK,gin.H{
            "Method":"Post",
        })
    case http.MethodDelete:
        c.JSON(http.StatusOK,gin.H{
            "Method":"Delete",
        })
    }
  • NoRoute如果监听的IP地址下访问了其他的Path而没有编写时,进行处理
    videoGroup := r.Group("/video")
    {
        videoGroup.GET("index", func(c *gin.Context) {
            c.JSON(http.StatusOK,gin.H{
                "Message":"/video/index",
            })
        })
        videoGroup.GET("home", func(c *gin.Context) {
            c.JSON(http.StatusOK,gin.H{
                "Message":"/video/home",
            })
        })
        videoGroup.GET("user", func(c *gin.Context) {
            c.JSON(http.StatusOK,gin.H{
                "Message":"/video/user",
            })
        })
    }
  • 路由组的组 多用于区分不同业务线或API,把公用的前缀提取出来,创建一个路由组



bseazh
1天前

gin请求重定向

Gin框架介绍及使用

package main

import(
    "github.com/gin-gonic/gin"
    "net/http"
)
func main(){
    r := gin.Default()
    r.GET("/index", func(c *gin.Context) {
        // 跳转到sogo.com
        c.Redirect(http.StatusMovedPermanently,"http://sogo.com")
    })

    r.GET("/a", func(c *gin.Context) {
        // 跳转/b对应的路由处理函数
        c.Request.URL.Path = "/b" // 把请求的URI修改
        r.HandleContext(c)  // 继续后续的处理
    })

    r.GET("/b", func(c *gin.Context) {
        c.JSON(http.StatusOK,gin.H{
            "message":"B",
        })
    })
    r.Run()
}

上课笔记

  • c.Redirect(http.StatusMovedPermanently,"http://sogo.com"),转到外网
  • 跳转/b对应的路由处理函数c.Request.URL.Path = "/b"并同时r.HandleContext(c)



bseazh
1天前

Gin框架介绍及使用

Gin文件上传

演示样例

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
    "path"
)
func main(){
    r := gin.Default()
    r.LoadHTMLFiles("./index.html")
    r.GET("/index", func(c *gin.Context) {
        c.HTML(http.StatusOK,"index.html",nil)
    })
    r.POST("/upload", func(c *gin.Context) {
        // 从请求html中获取文件
        f , err := c.FormFile("f1")
        if err != nil{
            c.JSON(http.StatusBadRequest,gin.H{
                "error" : err.Error(),
            })
            return
        }else{
            // 把文件保存到本地(服务器)
            //dst := fmt.Sprintf("./%s",f.Filename)
            dst := path.Join("./",f.Filename)
            c.SaveUploadedFile(f,dst)
            c.JSON(http.StatusOK,gin.H{
                "status":"ok",
            })
        }
    })
    r.Run()
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>

<form action="/upload" method="post" enctype="multipart/form-data">
    <div>
        <input type="file" name="f1">
    </div>
    <div>
        <input type="submit" value="上传">
    </div>

</form>

</body>
</html>

上课笔记

  • 好比大象放进冰箱有多少步
  • 第一步: 打开冰箱 r.GET("/index", func(c *gin.Context)设置页面上传文件
  • 第二步: 把大象放进冰箱,然后再让index.html中返回相应的file
  • 第三步: 关上冰箱门c.SaveUploadedFile(f,dst),其中保存路径的名称可以有两种方法保存
    dst := fmt.Sprintf("./%s",f.Filename)
    dst := path.Join("./",f.Filename)



bseazh
1天前

Gin框架介绍及使用

Gin参数绑定

package main

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

type UserInfo struct{
    Username string `form:"username" json:"user"`
    Password string `form:"password" json:"pwd"`
}
func main(){
    r := gin.Default()
    r.GET("/user", func(c *gin.Context) {
        //username := c.Query("username")
        //password := c.Query("password")
        //u := UserInfo{
        //  Username : username ,
        //  Password : password ,
        //}
        var u UserInfo
        err := c.ShouldBind(&u)
        if err != nil{
            c.JSON(http.StatusBadRequest,gin.H{
                "error":err.Error(),
            })
        }else{
            fmt.Printf("%#v\n", u)
            c.JSON(http.StatusOK,gin.H{
                "Message":"OK",
            })
        }
    })
    r.Run(":9090")
}

上课笔记

  • 访问页面格式:http://127.0.0.1:9090/user?username=Ben&password=123456
  • 对应的querystring = user?username=Ben&password=123456获取其usernamepassword
  • 方法1:分别获取c.Query("username")c.Query("password")
  • 方法2:建立结构体UserInfo并使用c.ShouldBind(&u),其中的结构体的字段必须是大写字母开头

golang部分

package main

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

type UserInfo struct{
    Username string `form:"username" json:"user"`
    Password string `form:"password" json:"pwd"`
}
func main(){
    r := gin.Default()

    // './'是当前目录别忘了加'.'
    r.LoadHTMLFiles("./index.html")
    // 在"/user"路径下,GET请求
    r.GET("/user", func(c *gin.Context) {
        //username := c.Query("username")
        //password := c.Query("password")
        //u := UserInfo{
        //  Username : username ,
        //  Password : password ,
        //}
        var u UserInfo
        err := c.ShouldBind(&u)
        if err != nil{
            c.JSON(http.StatusBadRequest,gin.H{
                "error":err.Error(),
            })
        }else{
            fmt.Printf("%#v\n", u)
            c.JSON(http.StatusOK,gin.H{
                "Message":"OK",
            })
        }
    })

    // 在"/index"路径下,GET请求
    r.GET("/index", func(c *gin.Context) {
        c.HTML(http.StatusOK,"index.html",nil)
    })

    // 在html中声明:<form action="/form" method="post">

    // 就会在form页面下提出请求"post"
    // 页面返回OK,在控制台中打印绑定的参数
    r.POST("/form", func(c *gin.Context) {
        var user UserInfo
        if err := c.ShouldBind(&user) ; err == nil {
            fmt.Printf("username : %s , password : %s\n", user.Username, user.Password)
            c.JSON(http.StatusOK, gin.H{
                "message": "Ok",
            })
        }else{
            c.JSON(http.StatusBadRequest, gin.H{
                "error": err.Error(),
            })
        }
    })


    // 利用postman调试
    r.GET("/json", func(c *gin.Context) {
        var user UserInfo
        if err := c.ShouldBind(&user) ; err == nil {
            fmt.Printf("username : %s , password : %s\n", user.Username, user.Password)
            c.JSON(http.StatusOK, gin.H{
                "message": "Ok",
            })
        }else{
            c.JSON(http.StatusBadRequest, gin.H{
                "error": err.Error(),
            })
        }

    })
    r.Run(":9090")
}

HTML部分

<!DOCTYPE html>

<html lang="zh-CN">
<head>
    <title>index</title>
</head>
<body>
<form action="/form" method="post">
    用户名:
    <input type="text" name="username">
    密码:
    <input type="password" name="password">
    <input type="submit" value="提交">
</form>
</body>
</html>

上课笔记

  • r.LoadHTMLFiles("./index.html") 别忘了加’./’表示相对路径查找文件
  • 在”/index”路径下,GET请求 => [HTML_REMOVED] => 在form页面下提出请求”post”
  • form在index页面中获取usernamepassworderr := c.ShouldBind(&user)



bseazh
1天前

gin获取URI路径参数

Gin框架介绍及使用

演示样例

package main


import(
    "github.com/gin-gonic/gin"
    "net/http"
)
// 获取请求的path(URI)参数,返回的都是字符串类型
func main(){
    r := gin.Default()
    r.GET("user/:name/:age", func(c *gin.Context) {
        // 获取路径参数
        name := c.Param("name")
        age := c.Param("age")
        c.JSON(http.StatusOK,gin.H{
            "name":name,
            "age":age,
        })
    })
    r.GET("blogs/:year/:month", func(c *gin.Context) {
        year := c.Param("year")
        month := c.Param("month")
        c.JSON(http.StatusOK,gin.H{
            "year":year,
            "month":month,
        })
    })
    r.Run(":9090")
}

上课笔记

  • 格式:/web/:name/:age
  • 获取方法:name := c.Param("name") , age := c.Param("age")
  • 注意,如果有多个获取路径时,必须相互间不能有交集,不然解析会错误



bseazh
1天前

gin获取form参数

Gin框架介绍及使用

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
// 获取form表单提交的参数


func main() {
    r := gin.Default()
    r.LoadHTMLFiles("./login.html", "./index.html")

    r.GET("/login", func(c *gin.Context) {
        c.HTML(http.StatusOK, "login.html", nil)
    })
    // /login post
    r.POST("/login", func(c *gin.Context) {
        // 获取form表单提交的数据
        //username := c.PostForm("username")
        //password := c.PostForm("password")  // 取到就返回值,取不到返回空字符串
        //username := c.DefaultPostForm("username", "somebody")
        //password := c.DefaultPostForm("xxx", "***")
        username, ok := c.GetPostForm("username")
        if !ok {
            username = "sb"
        }
        password, ok := c.GetPostForm("password")
        if !ok {
            password = "***"
        }
        c.HTML(http.StatusOK, "index.html", gin.H{
            "Name": username,
            "Password": password,
        })
    })

    r.Run(":9090")
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h1>Hello, {{ .Name }}!</h1>
<p>你的密码是:{{ .Password }}</p>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>

<form action="/login" method="post" novalidate autocomplete="off">
    <div>
        <label for="username">username:</label>
        <input type="text" name="username" id="username">
    </div>

    <div>
        <label for="password">password:</label>
        <input type="password" name="password" id="password">
    </div>

    <div>
        <input type="submit" value="登录">
    </div>

</form>

</body>
</html>

上课笔记

  • 今天遇到两个调试错误
    1. r.GET("/login", func(c *gin.Context) {c.HTML(http.StatusOK, "login.html", nil)})返回值中的login.html->/login.html,应该是login.html因为在解析后该文件就会以它自己本身的名字存在,不需要在路径去查找.
    1. LoadHTMLFiles少了一个文件index.html
  • 获取form表单提交的数据有三种方法

    1. c.PostForm("username")
    1. c.DefaultPostForm("username", "somebody")
    1. username, ok := c.GetPostForm("username")



bseazh
1天前

Gin框架获取querystring

Gin框架介绍及使用

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)
func main() {
    r := gin.Default()

    // GET 请求URL?name=`???`&age=`??`
    // "key = value" 多个key=value用"&"连接
    // <=> /index/?name=靓女&age=22

    r.GET("/index", func(c *gin.Context) {
        // 三种方式获取相应字段的值
        //name := c.Query("name")
        //name := c.DefaultQuery("name","靓女")
        name , ok := c.GetQuery("name")
        if !ok {
            name = "靓女"
        }
        // key - value 都为string
        age := c.DefaultQuery("age","18")
        c.JSON(http.StatusOK,gin.H{
            "name" : name,
            "age" : age,
        })
    })
    r.Run(":9000")
}

上课笔记

  • GET 请求URL?name=???&age=??“key=value”,多个kv用”&”连接<=> /web/name=靓女&age=18
  • 方法1 : name := c.Query("name")
  • 方法2 : name := C.DefaultQuery("name","靓女")
  • 方法3 : name , ok := c.GetQuery("name") 返回值(值,true)|| (“”,false)
  • querystring 的类型都为string



bseazh
1天前

Gin框架返回Json

Golang程序

package main

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


func main(){
    r := gin.Default()
    r.GET("/Json", func(c *gin.Context) {
        // 方法一:
        //data := map[string]interface{}{
        //  "name" : "靓仔" ,
        //  "msg" : "hello Go" ,
        //  "age" : 18 ,
        //}
        // gin.H 底层逻辑就是map[string]interface{}
        data := gin.H{
            "name":"靓仔",
            "msg":"hello world",
            "age":18,
        }
        c.JSON(http.StatusOK,data)
    })
    // 方法2 : 结构体 (字段必须大写)
    // 灵活使用tag来对结构体字段做定制化操作
    type msg struct {
        Name string `json:"name"`
        Message string `json:"message"`
        Age int `json:"age"`
    }

    r.GET("/anotherJson", func(c *gin.Context) {
        data := msg{
            Name: "靓仔",
            Message :"hello world",
            Age : 18,
        }
        c.JSON(http.StatusOK,data)
    })
    r.Run()
}

上课笔记

  • c.JSON(http.StatusOK,data),主要调用该函数进行返回json格式
  • 第一种方法:常见就是传入map[string]interface{}类型,其中gin.H底层就是map[string]interface{}类型
  • 第二种方法:定义结构体,直接传入结构体,但是必须注意,其定义字段必须是要大写字母开头(跨包必须相互间可见,底层实则实现一种反射来获取字段),我们可以利用tag来定义其json格式下的json:name