gin 框架:2 Gin 基本使用-基础篇

2 Gin 基本使用-基础篇

2.1 路由与传参

2.1.1 无参路由

所谓的无参路由最主要的区别就是将处理函数单独拿出来

package main

import (
    "fmt"

    "github.com/gin-gonic/gin"
)

// 将处理函数 handler 单独拆分开
// 无参数路由
func HelloHandler(c *gin.Context) {
    c.String(200, "hello!!")
}

func main() {

    // 1.生成 engine
    r := gin.Default()

    // 2.注册路由,将写在外面的处理函数注册到 GET 路由中
    r.GET("/", HelloHandler)

    fmt.Println("http://10.0.0.134:8888")

    // 3.启动服务
    r.Run(":8888")
}

postman 访问

2.1.2 API 传参

可以通过 Context 的 Param 方法来获取 API 参数

package main

import (
    "fmt"

    "github.com/gin-gonic/gin"
)

func GetBookDeatilHandler(c *gin.Context) {
    // 通过 c.Param 参数解析
    // 因为我们在 r.GET 函数中指定了 :id 的 url 所以需要将 c.Param() 中的 key 定义为 id 这样才能够正常解析
    bookId := c.Param("id")

    fmt.Println(bookId)

    c.String(200, "API 路由")
}

func main() {
    r := gin.Default()

    // 所谓的 API 路由其实就是直接通过斜杠的方式来进行传递
    // API 路由:类似于 /book/1/ 这样的 URL 方式
    // 这里定义了 :id 那么在上面的处理函数中也需要指定 id 这个 key 从而实现对 key 的解析
    r.GET("/book/:id", GetBookDeatilHandler)

    r.Run(":8888")
}

postman 请求的时候我在 book 的 uri 后面跟上了 99 ,这里的 99 就是对应代码中的 id

可以看到在代码中我将 bookid 输出就是 99

2.1.3 url 参数

方法一:Query() 获取传参

package main

import (
    "fmt"

    "github.com/gin-gonic/gin"
)

func GetUserUrlHandelr(c *gin.Context) {
    // 1.通过 Query() 方式传递
    name := c.Query("name")
    fmt.Println(name)

    c.String(200, "user URL 解析!!")
}

func main() {
    r := gin.Default()

    // url 传参: http://127.0.0.1/user?id=20&name=zhangsan
    // 所谓的 url 传参就是通过 ? 和 & 符进行传递
    r.GET("/user", GetUserUrlHandelr)

    r.Run(":8888")
}

postman 访问:我们在传递 url 的时候将 name 的值定义为张三

可以看到 gin 服务端成功获取我们传入的 张三

但是如果我们在请求的时候没有传递 ?name 的 URL 那么就会获取到一个空的字符串,那这种情况我们该怎么办?

方法二:DefaultQuery() 方式获取

package main

import (
    "fmt"

    "github.com/gin-gonic/gin"
)

func URLGETUserHandler(c *gin.Context) {
    // 2.通过 DefaultQuery() 获取,如果在放的时候没有指定 url 那么就通过默认值获取
    /* func (*gin.Context).DefaultQuery(key string, defaultValue string) string
    第一个参数为 key 的值
    第二个参数为默认值,也就是说如果用户没有传递 url 那么就获取默认值
    并且返回一个 key 的 value
    */
    name := c.DefaultQuery("name", "default value !")
    fmt.Println("获取到的用户名", name)
}

func main() {
    r := gin.Default()
    r.GET("/user", URLGETUserHandler)

    r.Run()
}

postman 第一次传递 name url 访问

gin 终端成功获取张三

postman 第二次未传递任何数据访问


gin 终端输出默认值

2.1.4 ShouldBind 参数绑定(使用较多)

  • 我们可以基于请求的 Content-Type 识别请求数据类型并利用反射机制
  • 自动提取请求中 QueryString form 表单 、 JSONXML 等参数到结构体中
  • 下面的示例代码演示了 ShouldBind() 强大的功能
  • 它能够基于请求自动提取 JSON form 表单 和 QueryString 类型的数据,并把值绑定到指定的结构体对象。

比如用户在 POST 请求时候有非常复杂的数据的话,那么我们想要验证用户名的 name 和 password 是否正确,所以这时候我们就需要使用到 func (*gin.Context).ShouldBind(obj any) error

package main

import (
    "fmt"

    "github.com/gin-gonic/gin"
)

// 定义 login 结构体,并在 PostLoginHandler 函数中用来解析
type Login struct {

    // post 请求的数据字段名一定要和 json:"username" 一摸一样
    // binding:"requierd" 要求 json 中定义的字段不能为空
    UserName string `json:"username" binding:"required"`
    Password string `json:"password" binding:"required"`
}

// shouldBind 方法,获取 json 中复杂数据
func PostLoginHandler(c *gin.Context) {
    login := Login{}

    // 将 net/http 中的 r.Body 数据解析到 Login 的结构体中
    // 将 login 结构体的指针数据传递给 c.ShouldBind
    if err := c.ShouldBind(&login); err != nil {
        // 如果用户提交数据有错误直接响应"用户名或密码错误"
        c.String(200, "用户名或密码错误!")
        return
    }

    fmt.Println(login)

    c.String(200, "登陆成功!")
}

func main() {
    r := gin.Default()

    // 这里已经不再是 GET 请求,而是一个复杂的 json 格式的 POST 请求
    r.POST("/login", PostLoginHandler)

    r.Run()
}

postman 提交数据验证登录成功

gin 服务器输出导入数据成功

传递错误参数:直接响应用户或密码错误!

总结:

通过上面的两个示例得出 shouldbind 不仅能够解析参数,还能够对参数进行校验。

2.2 响应返回

如何通过 gin 框架的封装进行返回数据

2.2.1 响应 String

package main

import "github.com/gin-gonic/gin"

// 响应一个普通的 string 字符串
func ResponseHandler(c *gin.Context) {
    c.String(200, "响应 string 字符串")
}

func main() {
    r := gin.Default()

    r.GET("/response", ResponseHandler)
    r.Run()
}

PostMan 请求,可以看到响应一个 string 字符串

2.2.2 响应 json

所谓响应 json 数据就是给客户端响应一个结构体,因为在 golang 中所有的服务返回的 json 本质就是一个 结构体

操作流程如下:

  1. 先定义一个结构体
  2. 然后将结构体赋值
  3. 最后将数据返回

方式一:直接通过结构体返回

package main

import "github.com/gin-gonic/gin"

// 响应一个 json 数据
func ResponseHandler(c *gin.Context) {
    type Data struct {
        Msg  string `json:"msg"`
        Code int    `json:"code"`
    }

    /* 
        初始化响应结构体
        其实这块就相当于在数据库中获取到的数据,并将起响应给客户端
    */
    d := Data{Msg: "json 响应", Code: 17}

    // c.JSON 将初始化的结构体 d 通过 json 格式响应给用户
    c.JSON(200, d)
}

func main() {
    r := gin.Default()

    r.GET("/json", ResponseHandler)
    r.Run()
}

postman 成功获取响应数据

方法二:直接通过 json 返回

package main

import "github.com/gin-gonic/gin"

func JsonHandler(c *gin.Context) {

    /*
        直接在 c.JSON 中通过 gin.H 进行返回, type H map[string]any
        本质就 gin.H 是一个 map
    */
    c.JSON(200, gin.H{
        "msg":  "gin.H",
        "code": 123,
    })
}

func main() {
    r := gin.Default()

    r.GET("/", JsonHandler)

    r.Run()
}

2.2.3 路由重定向

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

// 路由重定向
func ResponseRedirectHandler(c *gin.Context) {

    // 重定向至百度
    // http.StatusMovedPermanently 自动注册状态码,因为想要实现重定向就需要 300 系列状态码
    c.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
}

func main() {
    r := gin.Default()

    // 当用户访问 /redirect URL 的时候就会被重定向至百度
    r.GET("/redirect", ResponseRedirectHandler)
    r.Run()
}

可以看到当前状态码已经为 302 并且已经跳转至百度

2.3 路由分发

为什么需要路由分发?

  • 我们一个项目有非常多的模块,如果全部写在一块导致代码结构混乱,不利于后续的扩展

  • 按照大的模块,每个模块有自己独立的路由,主路由可以再main.go中进行注册

所谓的路由分发就是将不同的内容分开写,然后将相同的信息写到一起,比如有图书相关的内容那么就将图书相关的写到图书的路由中;如果有用户的信息就写到用户的路由中,以此类推

如何进行路由分层呢,其实基本的目录结构如下:

├── go.mod 
├── go.sum 
├── main.go 
└── routers 
    ├── books.go 
    └── users.go

2.3.1 演示如下

下面将进行一个演示项目的编写,在这个项目中分别有一个用户模块和一个书籍模块

2.3.1.1 初始化目录结构

创建对应的目录结构,准备初始环境

$ mkdir demo_router_layer
$ cd demo_router_layer/
/demo_router_layer$ mkdir routers
/demo_router_layer$ touch main.go
/demo_router_layer$ touch routers/users.go
/demo_router_layer$ go mod init demo_router_layer
/demo_router_layer$ go mod tidy

2.3.1.2 编写 user 路由

编写 users.go 路由程序

package routers

import "github.com/gin-gonic/gin"

// 编写加载用户路由的方法
func LoadUser(e *gin.Engine) {
    e.GET("/users", UserHandler)
}

func UserHandler(c *gin.Context) {
    c.String(200, "用户模块路由分发!")
}

2.3.1.3 编写 main 程序注册 user 路由

main.go 主程序注册 LoadUser 路由

package main

import (
    "demo_router_layer/routers"

    "github.com/gin-gonic/gin"
)

// 主程序只能有一个,并且用了实现注册路由操作
func main() {

    // 初始化引擎
    r := gin.Default()

    // 注册加载用户路由,并传递 r 引擎
    routers.LoadUser(r)

    r.Run()

}

启动程序浏览器访问 http://10.0.0.134:8080/users URL 路由成功


以上就是所谓的路由分层写法,当然我们还有图书相关的路由需要完成所以接下来就需要编写 book 路由

2.3.1.4 编写 book 路由

1 创建 book.go 程序文件

demo_router_layer# touch routers/book.go

2 编写 book.go 代码

package routers

import "github.com/gin-gonic/gin"

// e 就是由 main.go 函数中 gin.Default 返回
func LoadBook(e *gin.Engine) {
    // 注册路由
    e.GET("/book", Books)
}

// 处理函数
func Books(c *gin.Context) {
    c.String(200, "books")
}

3 编写 main.go 文件,合并 book 代码

package main

import (
    "demo_router_layer/routers"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    // 注册 user 路由
    routers.LodeUser(r)

    // 注册 BOOK 路由
    routers.LoadBook(r)
    r.Run()
}

4 启动然后浏览器访问 http://10.0.0.134:8080/book

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇