【Go语言】Gin 框架教程

news2024/11/25 2:41:19

Gin 框架教程

1.第一个 Gin 程序

1.1 Gin 安装

# 执行执行如下操作即可,安装Gin前需要安装Go环境
go get -u -v github.com/gin-gonic/gin
# -v:打印出被构建的代码包的名字
# -u:已存在相关的代码包,强行更新代码包及其依赖包

1.2 Gin 项目创建

在一个空文件夹里新建文件 main.go,参考如下代码编写一个 Gin 程序。

// blog.euansu.cn
// main.go
package main

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

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.String(200, "Hello, EuanSu")
	})
	r.Run() // listen and serve on 0.0.0.0:8080
}

运行 main.go 程序,如下图所示。

go run main.go

在这里插入图片描述

代码说明:

  1. 首先,r := gin.Default()这里生成了一个 Gin 引擎实例,用于处理 HTTP 请求,也即 WSGI 应用程序,这个实例会预先加载一些默认的中间件。
  2. r.GET("/", ...) 则是声明了一个路由,以及路由对应的函数方法。
  3. r.Run() 函数则是运行应用程序,默认的监听端口是 8080,也可以传入参数设置应用程序运行端口,例如 r.Run(":8888"),即应用运行在 8888 端口。

1.3 网站图标设置

这里使用一个 Gin 的中间件 github.com/thinkerou/favicon,使用同 gin 框架,首先是安装 github.com/thinkerou/favicon 库。

go get github.com/thinkerou/favicon

接下来,则是使用该中间件,代码如下所示:

// blog.euansu.cn
// main.go
package main

import (
	"github.com/gin-gonic/gin"
	"github.com/thinkerou/favicon"
)

func main() {
	// 创建一个服务
	r := gin.Default()
	// 使用中间件
	r.Use(favicon.New("./static/favicon.ico"))
	// 路由函数
	r.GET("/", func(c *gin.Context) {
		c.String(200, "Hello, EuanSu")
	})
	r.Run() // listen and serve on 0.0.0.0:8080
}

项目运行后,就能够在浏览器中看到 favicon.ico 网站图标。

在这里插入图片描述

2.Gin 中的路由

2.1 路由语法

$router.$method("$router", $handlerFunction)
# router,Gin 引擎实例
# method,http路由方法,可选参数为:GET、POST、PUT、PATCH、DELETE、OPTIONS、HEAD以及能够处理任意类型的HTTP请求的Any和处理指定类型的HTTP请求的Match
# handlerFunction,路由函数,处理路由响应

示例如下:

router.GET("/path", handlerFunction) 								// 获取资源
router.POST("/path", handlerFunction) 								// 创建资源	
router.PUT("/path", handlerFunction) 								// 更新资源
router.DELETE("/path", handlerFunction) 							// 删除资源
router.PATCH("/path", handlerFunction) 								// 更新部分资源
router.OPTIONS("/path", handlerFunction) 							// 获取服务器支持的 HTTP 方法
router.HEAD("/path", handlerFunction) 								// 获取资源的头部信息
router.Any("/path", handlerFunction) 								// 处理任意类型的 HTTP 请求
router.Match([]string{"GET", "POST"}, "/path", handlerFunction) 	// 处理指定类型的 HTTP 请求

2.2 请求参数的处理

2.2.1 路由参数解析

参数包含在路由中,如 /user/:name,通过调用不同的 路由参数 传入不同的 name,如下所示:

r.GET("/user/:name", func(c *gin.Context) {
    name := c.Param("name")
    c.String(http.StatusOK, "%s, Welcome to your clicl.", name)
})

在这里插入图片描述

这里需要注意下,如果新增了路由,需要重启 Gin 程序,重启之后,再次访问路由地址,就能够正常解析路由参数了。

在这里插入图片描述

2.2.2 Query 参数解析

Query 参数 与上文的路由参数一样,参数都是路由的一部分,不同的是 Query 参数 是键值对的形式,查询参数通常位于URL的问号(?)之后,以键值对的形式出现,并且多个参数之间用与号(&)分隔。

r.GET("/users", func(c *gin.Context) {
    name := c.Query("name")
    c.String(http.StatusOK, "%s, Thank you for your click.", name)
})

在这里插入图片描述

也可以直接使用 URL 通过浏览器请求该接口。

在这里插入图片描述

2.2.3 POST 参数解析(form表单)

这里使用一个表单参数进行举例,如下所示,输入分数转化为及格、不及格的判断,代码如下所示。

package main

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

func evaluateScore(score int) string {
	if score >= 90 {
		return "优秀"
	} else if score >= 60 {
		return "及格"
	} else {
		return "不及格"
	}
}

func main() {
	r := gin.Default()
	// POST参数解析
	// POST
	r.POST("/form", func(c *gin.Context) {
		username := c.PostForm("username")
        // DefaultPostForm,只支持string类型,因此需要进行类型的转换
		scoreStr := c.DefaultPostForm("score", "0")
		score, err := strconv.Atoi(scoreStr)
		if err != nil {
			// 处理错误情况,例如当输入的值不是整数时
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid score"})
			return
		}

		result := evaluateScore(score)
		c.JSON(http.StatusOK, gin.H{"username": username, "score": score, "evaluation": result})
	})

	r.Run() // listen and serve on 0.0.0.0:8080
}
r.POST("/form", func(c *gin.Context) {
    username := c.PostForm("username")
    password := c.DefaultPostForm("password", "000000") // 可设置默认值
    fmt.Println(password)
    c.String(http.StatusOK, "%s, Thank you for your login.", username)
})

请求后端的接口,返回如下。

在这里插入图片描述

2.2.4 POST 参数解析(json)
package main

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

func evaluateScore(score int) string {
	if score >= 90 {
		return "优秀"
	} else if score >= 60 {
		return "及格"
	} else {
		return "不及格"
	}
}

// 定义结构体,与JSON数据匹配
type Person struct {
	Username string `json:"username"`
	Score    int    `json:"score"`
}

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

	// 处理POST请求,接收JSON参数
	r.POST("/json", func(c *gin.Context) {
		var person Person

		// 绑定JSON到结构体
		if err := c.ShouldBindJSON(&person); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		result := evaluateScore(person.Score)
		c.JSON(http.StatusOK, gin.H{"username": person.Username, "score": person.Score, "evaluation": result})
	})

	r.Run() // listen and serve on 0.0.0.0:8080
}

请求后端的接口,返回如下。

在这里插入图片描述

2.3 路由处理

2.3.1 重定向
r.GET("/redirect", func(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "/")
})

如下所示,当后端收到 /redirect 路由的请求,会重定向至 /

在这里插入图片描述

2.3.2 分组路由

分组路由主要是为了处理路由前缀一致的情况,例如有一组路由前缀都是 /api/v1 开头,通过分组路由就能够简化路由的定义,也可以更好的实现路由的权限控制,例如将需要登录的路由放到同一分组中。代码示例如下:

// 默认的路由方法
defaultHandler := func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
        "path": c.FullPath(),
    })
}

// group: v1
v1 := r.Group("/v1")
{
    v1.GET("/posts", defaultHandler)
    v1.GET("/series", defaultHandler)
}
// group: v2
v2 := r.Group("/v2")
{
    v2.GET("/posts", defaultHandler)
    v2.GET("/series", defaultHandler)
}

请求不同的路由地址,均能够得到正常的响应。

在这里插入图片描述

在这里插入图片描述

3.RESTful API

RESTful API 具体概念可以查看 https://blog.euansu.cn/post/djangorestframework/ 这篇文章中关于 RESTful API 的相关介绍 。

使用 Go 语言能够快速的实现 RESTful API,实现如下:

r.GET("/user", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"msg": "get user"})
})
r.POST("/user", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"msg": "post user"})
})
r.PUT("/user", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"msg": "put user"})
})
r.DELETE("/user", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"msg": "delete user"})
})

使用 Apifox 等接口测试工具测试,应用程序能够根据使用的 HTTP 请求方式的不同而使用不同的函数进行处理。

  • GET 请求

    在这里插入图片描述

  • POST 请求

    在这里插入图片描述

  • PUT 请求

    在这里插入图片描述

  • DELETE 请求

    在这里插入图片描述

如上测试所示,Gin 框架能够快速、简洁的实现 RESTful API

4.响应页面

可以通过以下方式,先加载静态页面到 Gin 应用程序中。

// 加载静态页面
r.LoadHTMLGlob("templates/*")
// 加载指定的静态页面(不推荐)
r.LoadHTMLFiles("templates/index.html")

路由函数

r.GET("/", func(c *gin.Context) {
    c.HTML(http.StatusOK, "index.html", gin.H{"msg": "index.html", "path": "/"})
})

打开浏览器,访问 Gin/ 路由,显示如下。

在这里插入图片描述

5.中间件

首先是在项目中,声明一个中间件方法 myHandler(),如下是 myHandler() 的代码方法。

func myHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 设置中间件的值
		c.Set("usersession", "xxx")
		if c.Request.URL.Path == "/" {
			// 阻止
			fmt.Println("阻止")
			c.Abort()
		}
		// 放行
		fmt.Println("放行")
		c.Next()
	}
}

Gin 应用程序中使用这个中间件。

func main() {
	// 创建一个服务
	r := gin.Default()
	// 使用中间件
	r.Use(myHandler())
	...
    
	r.Run() // listen and serve on 0.0.0.0:8080
}

实际测试效果如下:

  • 请求 / 路由,后端返回为空。

    在这里插入图片描述

  • 请求其他的路由,则不受影响,就如我们在中间件方法所写的判断一样,仅仅只是拦截了 / 的路由请求。

    在这里插入图片描述

6.数据库

Gin 项目中使用数据库,涉及以下操作:

  1. 安装数据库驱动和 ORM 库,安详需要使用的数据库驱动和 ORM 库,常见的 ORM 库是 GORM,支持 MySQLPostgreSQLSQLite 等数据库。
  2. 配置数据库的连接信息,需要在 Gin 项目配置中配置数据库连接,通常是 main.go 或者单独的配置文件。
  3. 初始化数据库,在项目启动的时候,进行数据库连接的初始化。
  4. 项目中使用数据库, 在路由关联的函数中使用数据进行增删改查的操作。

6.1 安装数据库驱动和 ORM 库

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

6.2 配置数据库的连接信息

main.go 文件中配置数据库的连接信息。

// 数据库连接信息
dsn := "username:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
var err error

// 连接数据库
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
    log.Fatalf("无法连接数据库: %v", err)
}

6.3 数据库初始化

使用 gorm 库,定义数据库模型,在 main.go 文件中添加 AutoMigrate 方法,进行数据库的迁移操作。

// 定义一个全局的数据库连接变量
var db *gorm.DB

// User 定义数据库模型
type User struct {
	ID       uint   `json:"id" gorm:"primaryKey"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

func main() {
	// 创建一个服务
	r := gin.Default()
	// 使用中间件
	r.Use(favicon.New("./static/favicon.ico"))
	r.Use(myHandler())
	// 加载静态页面
	r.LoadHTMLGlob("templates/*")
	// 数据库连接信息
	dsn := "username:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
	var err error

	// 连接数据库
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatalf("无法连接数据库: %v", err)
	}

	// 自动迁移数据库
	db.AutoMigrate(&User{})

	r.Run() // listen and serve on 0.0.0.0:8080
}

项目启动如下,项目启动后,执行 AutoMigrate 方法。

在这里插入图片描述

连接配置的数据库,发现 AutoMigrate 初始化生成的表,数据库迁移操作成功。

在这里插入图片描述

6.4 数据库使用

如下是获取用户列表和创建用户的两个函数方法。

// 获取用户列表的处理函数
func getUsers(c *gin.Context) {
	var users []User
	result := db.Find(&users)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
		return
	}
	c.JSON(http.StatusOK, users)
}

// 创建用户的处理函数
func createUser(c *gin.Context) {
	var user User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	result := db.Create(&user)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
		return
	}
	c.JSON(http.StatusOK, user)
}

main.go 中添加路由函数,如下所示:

// 定义路由和处理函数
r.GET("/users", getUsers)
r.POST("/users", createUser)

进行路由请求,如下所示:

  • POST 请求进行用户的创建。

    在这里插入图片描述

  • GET 请求获取用户信息。

    在这里插入图片描述

数据库操作的完整代码为:

// blog.euansu.cn
// main.go
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/thinkerou/favicon"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	"net/http"
)

func myHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 设置中间件的值
		c.Set("usersession", "xxx")
		if c.Request.URL.Path == "/" {
			// 阻止
			fmt.Println("阻止")
			c.Abort()
		}
		// 放行
		fmt.Println("放行")
		c.Next()
	}
}

// 定义一个全局的数据库连接变量
var db *gorm.DB

// User 定义数据库模型
type User struct {
	ID       uint   `json:"id" gorm:"primaryKey"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

func main() {
	// 创建一个服务
	r := gin.Default()
	// 使用中间件
	r.Use(favicon.New("./static/favicon.ico"))
	r.Use(myHandler())
	// 加载静态页面
	r.LoadHTMLGlob("templates/*")
	// 数据库连接信息
	dsn := "username:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
	var err error

	// 连接数据库
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatalf("无法连接数据库: %v", err)
	}

	// 自动迁移数据库
	db.AutoMigrate(&User{})

	// 定义路由和处理函数
	r.GET("/users", getUsers)
	r.POST("/users", createUser)

	// 路由函数
	r.GET("/", func(c *gin.Context) {
		//c.String(200, "Hello, EuanSu")
		c.HTML(http.StatusOK, "index.html", gin.H{"msg": "index.html", "path": "/"})
	})

	r.GET("/home", func(c *gin.Context) {
		//c.String(200, "Hello, EuanSu")
		c.HTML(http.StatusOK, "index.html", gin.H{"msg": "index.html", "path": "/home"})
	})

	r.Run() // listen and serve on 0.0.0.0:8080
}

func getUsers(c *gin.Context) {
	var users []User
	result := db.Find(&users)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
		return
	}
	c.JSON(http.StatusOK, users)
}

func createUser(c *gin.Context) {
	var user User
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	result := db.Create(&user)
	if result.Error != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
		return
	}
	c.JSON(http.StatusOK, user)
}

7.相关链接

[1] Go Gin 简明教程 https://geektutu.com/post/quick-go-gin.html

[2] 【【狂神说】Gin框架一小时上手 | 快速转型GoWeb开发 | Go语言零基础教程】 https://www.bilibili.com/video/BV1Rd4y1C7A1/?share_source=copy_web&vd_source=5fdcc6213ac2d30f16a78fe5d6e8df4d

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1828692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH) 一、最大通话时间 1、配置拨号方案 1、点击拨号方案 ->2、在框中输入通话最大时长->3、点击添加->4、根据图中配置->5、勾选continue。修改拨号方案需要等待一分钟即可生效 action"sched…

趣味C语言——【猜数字】小游戏

🥰欢迎关注 轻松拿捏C语言系列,来和 小哇 一起进步!✊ 🎉创作不易,请多多支持🎉 🌈感谢大家的阅读、点赞、收藏和关注💕 🌹如有问题,欢迎指正 感谢 目录 代码…

高阶数据结构[3]图的遍历

图的两种遍历 前言 1.图的遍历 2.图的广度优先遍历 3.图的深度优先遍历 4.总结 前言 书接上回,这篇文章将在图的存储结构上学习图的遍历方法。 图的遍历分为两种:1.BFS(Breadth First Search)宽度优先搜索 2.DFS&#xff08…

Linux构建本地时间同步ntp

环境介绍: 主机名 IP地址 系统发行版 环境 Node01 192.168.100.102 Centos 7.4 可联网、已关闭防火墙selinux Node02 192.168.100.103 Centos 7.4 已关闭防火墙selinux 1.主节点同步阿里云标准时间 在保证连接外网的情况下,同步阿里服务器的…

[Linux] TCP协议介绍(1): TCP协议 数据格式、可靠性的控制、标记位... 简单介绍

上一篇文章, 针对UDP协议的格式、数据等内容做了一些简单的介绍. 并且提到, 在网络协议栈TCP/IP模型的传输层中, 有两个最具代表性的协议: UDP和TCP 下面就简单介绍分析一下TCP协议 TCP协议, 完整的称呼其实叫: 传输控制协议(Transmission Control Protocol) 从名字就可以看出…

MobaXterm卡顿问题 解决方案

写在最前面,解决方案是:setting->X11->关闭Automatically start X server at MobaXterm start up 若有空,可以看一下下面的排障流程~ 现象描述 使用MobaXterm作为远程连接工具的时候,会出现很奇怪的卡顿问题。每隔几秒&…

Modbus转Profibus网关接变频器:实现工业自动化无缝连接

一、背景 在工业自动化领域,Modbus和Profibus是两种常见的通讯协议,而变频器作为控制电机转速的重要设备。为了实现不同设备之间的无缝连接和数据传输,现场大多数采用Modbus转Profibus网关(XD-MDPB100)来解决Modbus设…

linux 部署瑞数6实战(维普,药监局)sign第二部分

声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!wx …

从业余到专业:拼多多跨境选品师的成功之路

拼多多(Pinduoduo)作为中国颇具影响力的电商平台,其跨境电商领域近年来发展迅猛。作为跨境选品师,是否可以将其作为一项副业呢?以下将探讨这个问题,并提供一些实用建议。 1. 跨境电商市场概述 跨境电商市场正在迅速扩展,尤其是在…

UI学习--分栏控制器

UI学习 分栏控制器基础概念用法 分栏控制器高级高级属性 总结 分栏控制器基础 概念 分栏控制器可以理解为一个容器,可以容纳多个子视图控制器,并通过选项卡的方式进行切换。每个选项卡都与一个特定的视图控制器相关联,当用户点击不同的选项…

Elasticsearch 8.1官网文档梳理 - 十一、Ingest pipelines(管道)

Ingest pipelines 管道(Ingest pipelines)可让让数据在写入前进行常见的转换。例如可以利用管道删除文档(doc)的字段、或从文本中提取数据、丰富文档(doc)的字段等其他操作。 管道(Ingest pip…

2024年【广东省安全员A证第四批(主要负责人)】复审考试及广东省安全员A证第四批(主要负责人)复审模拟考试

题库来源:安全生产模拟考试一点通公众号小程序 广东省安全员A证第四批(主要负责人)复审考试参考答案及广东省安全员A证第四批(主要负责人)考试试题解析是安全生产模拟考试一点通题库老师及广东省安全员A证第四批&…

Bytebase 2.19.0 - 支持 DynamoDB

Bytebase 2.19.0 支持 DynamoDB 支持独立的 SQL 审核工单。 支持为工单事件配置 Slack 私信通知。 file 支持 PostgreSQL 的 DML 变更事前备份。 为 SQL Server 添加 SQL 审核规则:禁止冗余索引。 重大变更 创建多数据库工单时,不同数据库会共享同…

windows权限提升-WIN提权

Windows权限提升-WIN 全平台 Windows系统内置了许多本地用户组,这些用户组本身都已经被赋予一些权限(permissions),它们具有管理本地计算机或访问本地资源的权限。只要用户账户加入到这些本地组内,这回用户账户也将具备该组所拥有的权限。 普通权限 默…

二维数组与指针【C语言】

二维数组与指针 一维数组一维数组与指针二维数组二维数组与指针总结补充判断以下方式是否正确打印二维数组一维数组 int arr[] = {11, 22, 33, 44};arr:首地址(第一个元素的地址) 一维数组与指针 int arr[] = {11, 22, 33, 44};因为,arr表示的是首地址,等价于 int* p =…

C# TextBox模糊查询及输入提示

在程序中,我们经常会遇到文本框中不知道输入什么内容,这时我们可以在文本框中显示提示词提示用户;或者需要查询某个内容却记不清完整信息,通常可以通过文本框列出与输入词相匹配的信息,帮助用户快速索引信息。 文本框…

【区分】累次极限与二重极限

累次极限与二重极限不要混淆,区分好下面5个命题

学会python——读取大文本文件(python实例六)

目录 1、认识Python 2、环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3、读取大文本文件 3.1 代码构思 3.2 代码示例 3.3 运行结果 4、总结 1、认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强…

计算机组成原理之定点乘法运算

文章目录 原码并行乘法与补码并行乘法原码算法运算规则存在的问题带符号的阵列乘法器习题原码阵列乘法器间接补码阵列乘法器直接补码阵列乘法器 补码与真值的转换 原码并行乘法与补码并行乘法 原码算法运算规则 存在的问题 理解流水式阵列乘法器(并行乘法器&#x…

本学期嵌入式期末考试的综合项目,我是这么出题的

时间过得真快,临近期末,又到了老师出卷的时候。作为《嵌入式开发及应用》这门课的主讲教师,今年给学生出的题目有一点点难度,最后的综合项目要求如下所示,各位学生朋友和教师同行可以评论一下难度如何,单片…