2、Go Gin 使用、程序的热加载、路由结构与数据结构

Gin 使用

下载并安装 gin

go get -u github.com/gin-gonic/gin

由于网络原因国内部分用户可能没法直接下载第三方包,go get 失败,Golang Gin中没法下载第三方包解决办法如下: 

//打开终端并执行
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

如果使用诸如 http.StatusOK 之类的常量,则需要引入 net/http 包

net/http //go自带基础包

案例

package main

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

func main() {
	// 创建gin的默认路由引擎
	r := gin.Default()
	// 配置路由
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{ // c.JSON:返回 JSON 格式的数据
			"message": "Hello world!"})
	})

	// 浏览器访问请求127.0.0.1:8080/ping路由时,调用回调函数
	r.GET("/ping", func(c *gin.Context) {
		//浏览器输出
		//c.JSON(200, gin.H{
		//    "message": "pong",
		//})
		c.String(http.StatusOK, "值:%v", "你好")
	})

	//监听并在 0.0.0.0:8080 上启动服务(启动一个web服务)
	r.Run()
	// 监听并在 0.0.0.0:8000 上启动服务(启动一个web服务)
	//r.Run("8000")
}

go gin程序的热加载 

Go Gin 程序的热加载是指在开发过程中,当您修改了源代码后,无需手动停止并重新启动应用程序,而是让框架自动检测代码变更并重新编译、加载新的代码版本,从而立即反映到正在运行的服务中。这对于提高开发效率、缩短反馈循环非常有帮助。虽然 Gin 框架本身并未内置热加载功能,但可以通过以下第三方工具实现这一特性:

1、Fresh

Fresh 是一个常用的 Go 应用程序热加载工具,由 Pilu Ristea 开发。要使用 Fresh 实现 Gin 程序的热加载,可以按照以下步骤操作:

安装 Fresh

go install github.com/pilu/fresh@latest

启动应用: 在项目根目录下运行 fresh 命令代替直接执行 go run main.go 或 go build && ./myapp

fresh

Fresh 将监听项目中的源文件变化,一旦检测到改动,会自动重新编译并重启应用程序。

结束程序

Ctrl + C

2. codegangsta

//进入终端执行
go get -u github.com/codegangsta/gin
//然后运行命令
gin run main.go

注意事项

  • 使用热加载工具时,请确保您的开发环境已正确设置 Go 的模块支持(如设置 GO111MODULE=on 环境变量),特别是在使用 Go modules 进行依赖管理的情况下。
  • 对于生产环境部署,不建议使用热加载功能,应通过正常的构建和部署流程更新应用,以确保稳定性和一致性。

通过集成第三方工具可以实现 Go Gin 程序的热加载,显著提升开发过程中的迭代速度和工作效率。选择适合自己项目的工具,按照对应的文档或上述指导步骤进行配置和使用即可。

Gin框架中的路由系统是其核心功能之一,负责将接收到的HTTP请求映射到相应的处理函数。以下是对Gin框架路由特性和使用方法的详细说明:

路由结构与数据结构

前缀树(Trie/Radix Tree)

Gin框架底层使用了基于前缀树(Trie或Radix Tree)的数据结构来高效存储和查找路由。这种数据结构非常适合处理HTTP路径,因为它允许以接近O(1)的时间复杂度查找具有共同前缀的路径。这意味着即使面对大量路由规则,Gin也能快速定位到正确的处理函数,从而保证了高并发场景下的性能。

O(1):意味着Gin框架在处理路由查找时,尽管理论上的时间复杂度与路径长度有关,但在实际应用中,由于路径长度较小且固定,查找过程的时间开销几乎不受路由集合大小的影响,表现得如同常数时间复杂度算法一样高效。这种特性使得Gin框架在处理高并发请求时,能够迅速定位到对应的处理函数,保证了系统的响应速度和吞吐量

路由定义

在Gin中,开发者使用简洁的API来定义路由及其关联的HTTP方法、路径和处理函数。例如:

package main

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

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

	// 定义GET请求路由
	r.GET("/users/:id", getUser)

	// 定义POST请求路由
	r.POST("/users", createUser)

	// 启动服务器
	r.Run(":8080")
}

// 处理函数示例
func getUser(c *gin.Context) {
	id := c.Param("id")
	// ...
}
func createUser(c *gin.Context) {
	// ...
}

在这个例子中:

  • GET 和 POST 方法分别用于定义处理相应HTTP方法的路由。
  • 路径 /users/:id 中的 :id 是一个参数占位符,表示该位置可以接收任意字符串作为参数,通过 c.Param("id") 在处理函数中访问。
  • createUser 和 getUser 分别是与这些路由关联的处理函数,它们接受一个 *gin.Context 参数,包含了请求上下文的所有相关信息。

路由特性

静态路由与动态路由
  • 静态路由:指路径中不含参数占位符的路由,如 /about。这类路由匹配的是完全相同的URL路径。

  • 动态路由:指路径中含有参数占位符的路由,如 /users/:id。这些占位符可以捕获URL中的特定部分作为参数传递给处理函数。

路由组

为了更好地组织和复用路由,Gin支持创建路由组。路由组可以共享中间件、设置共同的前缀,并保持代码的模块化。创建路由组的示例如下:

v1 := r.Group("/api/v1")
{
    v1.GET("/users", listUsers)
    v1.GET("/users/:id", getUserDetails)
    v1.POST("/users", createUser)
    // 更多v1组内的路由...
}

在这个例子中,所有定义在 v1 组内的路由都将带有前缀 /api/v1

路由参数

除了简单的参数占位符,Gin还支持更复杂的路由参数约束和命名参数:

  • 参数约束:通过在参数名后添加冒号和正则表达式来限制参数值的格式,如 :id([0-9]+) 表示 id 参数只能包含数字。

  • 命名参数:在 GET 请求的查询参数中,可以直接通过 c.Query("paramName") 访问;在 POST 请求的表单数据或JSON请求体中,可通过 c.PostForm("paramName") 或 c.ShouldBindJSON(&struct{}) 解析。

中间件与路由

路由定义不仅可以关联处理函数,还可以附加中间件。中间件是在请求到达实际处理函数之前或之后执行的函数,常用于身份验证、日志记录、响应压缩、跨域处理等通用任务。中间件可以全局应用、应用于特定路由组,也可以仅作用于单个路由。

r := gin.Default()

// 全局中间件示例
r.Use(gin.Logger(), gin.Recovery())



// 路由组中间件示例
authMiddleware := func(c *gin.Context) {
    // ...身份验证逻辑...
}
protected := r.Group("/", authMiddleware)
{
    protected.GET("/private", handlePrivateResource)
}



// 单个路由中间件示例,someMiddleware为够个中间件,slowHandler为处理函数
r.GET("/slow-resource", someMiddleware, slowHandler)

总结

Gin框架中的路由系统以其高效的前缀树数据结构、简洁的API设计、支持静态与动态路由、路由组、参数约束、中间件集成等特性,为开发者提供了强大且灵活的路由管理能力。这些特性使得构建清晰、高性能的RESTful API和Web应用程序变得轻松高效。

代码案例

GET请求

返回一个字符串

//  GET 请求
r.GET("网址", func(c *gin.Context) {
    c.String(200, "Get")
})

// 域名/news?aid=20
// 返回一个字符串
r.GET("/news", func(c *gin.Context) {
    aid := c.Query("aid")
    c.String(200, "aid=%s", aid)
})

// 域名/user/20
r.GET("/user/:uid", func(c *gin.Context) {
    uid := c.Param("uid")
    c.String(200, "userID=%s", uid)
})

GET请求返回一个 JSON 数据

//方法一:自己拼接JSON
r.GET("/json", func(c *gin.Context) {
	//返回json数据,使用 map[string]interface
	//c.JSON(返回的状态码, 任意类型的数据(如:map,struct,...)
	c.JSON(200, map[string]interface{}{
		"success": true,
		"msg":     "你好",
	})
})
//方法二:gin中的H函数
r.GET("/json2", func(c *gin.Context) {
	//返回json数据,使用gin中的H函数, gin.H 是 map[string]interface{}的缩写
	c.JSON(200, gin.H{
		"success": true,
		"msg":     "你好gin",
	})
})
//方法三:使用结构体
r.GET("/json3", func(c *gin.Context) {
	//实例化一个结构体
	a := &Article{
		Title:   "标题",
		Desc:    "说明",
		Content: "内容",
	}
	c.JSON(200, a)
})

GET请求返回 XML 数据

//方法一:使用gin.H返回
r.GET("/xml", func(c *gin.Context) {
	c.XML(http.StatusOK, gin.H{
		"success": true,
		"msg":     "成功xml",
	})
})
//方法二:使用结构体
r.GET("/xmlStruct", func(c *gin.Context) {
	//实例化一个结构体
	a := &Article{
		Title:   "标题-xmlStruct",
		Desc:    "说明-xmlStruct",
		Content: "内容-xmlStruct",
	}
	c.XML(200, a)
})

GET请求返回HTML数据

 //初始化路由
 r := gin.Default()
 //加载templates文件中所有模板文件,以便后续c.HTML()渲染文件时使用
 r.LoadHTMLGlob("templates/*")
 r.GET("/news", func(c *gin.Context) {
	//使用模板文件渲染HTML文件
	//前提: r.LoadHTMLGlob("templates/*")
	//HTML(状态码, 要渲染的文件名, 加载的参数)
	c.HTML(http.StatusOK, "news.html", gin.H{
		"title": "我是一个news",
	})
})

POST请求

// POST请求
r.POST("网址", func(c *gin.Context) {
    c.String(200, "POST")
})

PUT请求

// PUT请求
r.PUT("网址", func(c *gin.Context) {
    c.String(200, "PUT")
})

DELETE请求

//DELETE请求
r.DELETE("网址", func(c *gin.Context) {
    c.String(200, "DELETE")
})

完整代码案例一

package main

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

func main() {
	r := gin.Default() // 创建gin的默认路由引擎
	//配置路由
	// 浏览器访问请求127.0.0.1:8080/ping路由时,调用回调函数
	r.GET("/ping", func(c *gin.Context) {
		//浏览器输出
		//c.JSON(200, gin.H{
		//    "message": "pong",
		//})
		c.String(http.StatusOK, "值:%v", "你好")
	})
	r.GET("/news", func(c *gin.Context) {
		//使用http.StatusOK状态码
		c.String(http.StatusOK, "新闻页11面")
	})
	r.POST("/add", func(c *gin.Context) {
		c.String(200, "这是一个POST请求,主要用于增加数据")
	})
	r.PUT("/edit", func(c *gin.Context) {
		c.String(200, "这是一个PUT请求,主要用于修改数据")
	})
	r.DELETE("/delete", func(c *gin.Context) {
		c.String(200, "这是一个DELETE请求,主要用于删除数据")
	})
	r.Run() // 监听并在 0.0.0.0:8080 上启动服务(启动一个web服务)
}

完整代码案例二 

package main
 
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
 
type Article struct {
    Title   string `json:"title"`
    Desc    string `json:"desc"`
    Content string `json:"content"`
}
 
func main() {
    //初始化路由
    r := gin.Default()
    //加载templates文件中所有模板文件,以便后续c.HTML()渲染文件时使用
    r.LoadHTMLGlob("templates/*")
    //配置路由
    r.GET("/", func(c *gin.Context) {
        c.String(200, "首页")
    })
    r.GET("/json", func(c *gin.Context) {
        //返回json数据,使用 map[string]interface
        //c.JSON(返回的状态码, 任意类型的数据(如:map,struct,...)
        c.JSON(200, map[string]interface{}{
            "success": true,
            "msg":     "你好",
        })
    })
    r.GET("/json2", func(c *gin.Context) {
        //返回json数据,使用gin中的H函数
        c.JSON(200, gin.H{
            "success": true,
            "msg":     "你好gin",
        })
    })
    r.GET("/json3", func(c *gin.Context) {
        //实例化一个结构体
        a := &Article{
            Title:   "标题",
            Desc:    "说明",
            Content: "内容",
        }
        c.JSON(200, a)
    })
    //jsonp请求 主要用来解决跨域问题
    //http://127.0.0.1:8080/jsonp?callback=call
    //call({"title":"标题-jsonp","desc":"说明-jsonp","content":"内容-jsonp"});
    r.GET("/jsonp", func(c *gin.Context) {
        //实例化一个结构体
        a := &Article{
            Title:   "标题-jsonp",
            Desc:    "说明-jsonp",
            Content: "内容-jsonp",
        }
        c.JSONP(200, a)
    })
    r.GET("/xml", func(c *gin.Context) {
        c.XML(http.StatusOK, gin.H{
            "success": true,
            "msg":     "成功xml",
        })
    })
    r.GET("/news", func(c *gin.Context) {
        //使用模板文件渲染HTML文件
        //前提: r.LoadHTMLGlob("templates/*")
        //HTML(状态码, 要渲染的文件名, 加载的参数)
        c.HTML(http.StatusOK, "news.html", gin.H{
            "title": "我是一个news",
        })
    })
    r.GET("/goods", func(c *gin.Context) {
        //使用模板文件渲染HTML文件
        //前提: r.LoadHTMLGlob("templates/*")
        //HTML(状态码, 要渲染的文件名, 加载的参数)
        c.HTML(http.StatusOK, "goods.html", gin.H{
            "title": "我是一个goods",
            "price": 12.99,
        })
    })
    r.Run() // 启动一个web服务
}

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值