1. 什么是Gin框架
Gin框架:是一个由 Golang 语言开发的 web 框架,能够极大提高开发 web 应用的效率!

1.1 什么是web框架
web框架体系图(前后端不分离)如下图所示:

从上图中我们可以发现一个Web框架最重要的一些组成部分:
- HTTP解析/封装系统:解析HTTP请求以及将响应构造为HTTP请求等任务交由web框架来完成
- 路由系统:将一个请求路由给某一个指定的处理器函数
- 逻辑处理系统:是后端人员需要关注的重点区域,编写具体业务逻辑以及链接数据库
- 模板引擎(前后端不分离):将数据嵌入到HTML模板中,构建动态页面
简单来说,web框架将一些繁琐且与业务逻辑无关的部分封装起来供开发者使用,这样开发人员只需要关注业务逻辑层的实现
1.2 web框架两种架构模式
常见的 web 架构模式有两种:
- 前后端不分离
- 前后端分离
上面已经介绍了前后端不分离的架构体系图,下图是前后端分离的架构图:

可以看出主要区别在于后端没有了模板引擎,意味着HTML页面、图片等static静态资源全部都在前端服务器部署(如nginx),后端服务器只负责编写接口进行业务逻辑处理,然后将前端所需的数据暴露成接口返回!(不和页面打任何交道)
2. Gin框架
2.1 Gin框架如何安装
在Go 1.11之后引入了包管理机制,我们就可以使用go mod tidy
一键将代码中所需导入的包从远程服务器下载到本地
go
package main
import "github.com/gin-gonic/gin"
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/hello", func(c *gin.Context) {
c.String(200, "Hello Gin")
})
// 启动
r.Run(":8080")
}
编写完上述代码以后在控制台输入以下命令:
go mod init gin_first
:包管理初始化go mod tidy
:下载所需依赖

看到上述信息就表明 gin 框架已经引入完毕!可以正式编写代码啦~
2.2 Gin框架的路由系统
2.2.1 基本使用
其实在 2.1 节我们已经初步使用过路由系统了
go
// 设置路由
r.GET("/hello", func(c *gin.Context) {
c.String(200, "hello gin")
})
基本语法:r.操作方法(url, 处理器函数)
- 操作方法:引擎对象基本支持所有的HTTP请求方法,比如GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS,以及Any(任何请求)、NoRoute(没有请求对应上时访问)
- url:表示请求对应的路径
- 处理器函数:表示请求路径为"/hello"时映射到该处理器函数进行执行
现在我们通过浏览器使用GET请求访问路径:http://localhost:8080/hello

2.2.2 路由分组
有时候我们希望对一个 url 路径做更统一化的管理,比如"/user/login"和"/user/register"实际上都是在"/user"路径下的子路由,这个时候就需要引入 路由分组
基本语法:子路由对象 := r.Group(根路由)
go
package main
import "github.com/gin-gonic/gin"
func main() {
// 获取引擎对象
r := gin.Default()
// 设置根路由
userRouter := r.Group("/user")
{
userRouter.GET("/login", func(ctx *gin.Context) {
ctx.String(200, "/user/login")
})
userRouter.GET("/register", func(ctx *gin.Context) {
ctx.String(200, "/user/register")
})
}
// 启动
r.Run(":8080")
}
2.3 Gin框架获取参数
2.3.1 获取基本信息
2.3.1.1 获取请求方法
比如在Any请求内部想要知道具体请求方法可以使用:
基本语法:var method string = ctx.Request.Method
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func handleFunc(ctx *gin.Context) {
// 获取请求方法
method := ctx.Request.Method
fmt.Println("请求方法是:" + method)
ctx.String(200, "request ok")
}
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.Any("/method", handleFunc)
// 启动
r.Run(":8080")
}
代码运行结果:

2.3.1.2 获取请求URL
基本语法:var url string = ctx.Request.URL
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func handleFunc(ctx *gin.Context) {
// 获取请求URL
var url string = ctx.Request.URL.String()
fmt.Println("请求URL是:" + url)
ctx.String(200, "request ok")
}
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/url", handleFunc)
// 启动
r.Run(":8080")
}
代码运行结果:

2.3.1.3 获取远程IP地址
基本语法:
- 方式一:
var remoteAddr string = ctx.Request.RemoteAddr
(包含端口) - 方式二:
var remoteAddr string = ctx.ClientIP()
(不包含端口)
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func handleFunc1(ctx *gin.Context) {
// 获取远程ip
var addr string = ctx.Request.RemoteAddr
fmt.Println("远程ip:", addr)
ctx.String(200, "request ok")
}
func handleFunc2(ctx *gin.Context) {
// 获取远程ip
var addr string = ctx.ClientIP()
fmt.Println("远程ip:", addr)
ctx.String(200, "request ok")
}
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/addr1", handleFunc1)
r.GET("/addr2", handleFunc2)
// 启动
r.Run(":8080")
}
代码运行结果:

2.3.1.4 获取请求头信息
本语法:var headerInfo string = ctx.GetHeader(键)
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func handleFunc(ctx *gin.Context) {
// 获取指定请求头
var userAgent string = ctx.GetHeader("User-Agent")
fmt.Println("Content-Type:", userAgent)
ctx.String(200, "request ok")
}
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/header", handleFunc)
// 启动
r.Run(":8080")
}
代码运行结果:

2.3.2 获取请求数据
2.3.2.1 获取查询字符串内容
通常来说使用 GET 请求发送请求都会将数据放置在查询字符串位置
- 方式一 :
var content string = ctx.Query(键)
- 方式二:
var content string = ctx.DefaultQuery(键, 缺省值)
,如果不存在则使用默认值填充 - 方式三:
value, ok := ctx.GetQuery(键)
,可以通过ok判断是否存在键
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func handleFunc1(ctx *gin.Context) {
// 获取查询字符串数据
var username = ctx.Query("username")
var pwd = ctx.Query("pwd")
fmt.Println("username:", username)
fmt.Println("pwd:", pwd)
ctx.String(200, "request ok")
}
func handleFunc2(ctx *gin.Context) {
// 获取查询字符串数据
var user = ctx.DefaultQuery("user", "wjj")
fmt.Println("user:", user)
ctx.String(200, "request ok")
}
func handleFunc3(ctx *gin.Context) {
// 获取查询字符串数据
user, exists := ctx.GetQuery("user")
if exists {
fmt.Println("键存在,值为:", user)
} else {
fmt.Println("键不存在!")
}
ctx.String(200, "request ok")
}
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/queryString1", handleFunc1)
r.GET("/queryString2", handleFunc2)
r.GET("/queryString3", handleFunc3)
// 启动
r.Run(":8080")
}
程序运行结果:

2.3.2.2 获取表单数据
前端使用 form表单 提交发送请求,此时Content-Type
为x-www-form-urlencoded
可以使用PostForm获取表单内容
- 方式一 :
var content string = ctx.PostForm(键)
- 方式二:
var content string = ctx.DefaultPostForm(键, 缺省值)
,如果不存在则使用默认值填充 - 方式三:
value, ok := ctx.GetPostForm(键)
,可以通过ok判断是否存在键
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func handleFunc1(ctx *gin.Context) {
// 获取查询字符串数据
var username = ctx.PostForm("username")
var pwd = ctx.PostForm("pwd")
fmt.Println("username:", username)
fmt.Println("pwd:", pwd)
ctx.String(200, "request ok")
}
func handleFunc2(ctx *gin.Context) {
// 获取查询字符串数据
var user = ctx.DefaultPostForm("user", "wjj")
fmt.Println("user:", user)
ctx.String(200, "request ok")
}
func handleFunc3(ctx *gin.Context) {
// 获取查询字符串数据
user, exists := ctx.GetPostForm("user")
if exists {
fmt.Println("键存在,值为:", user)
} else {
fmt.Println("键不存在!")
}
ctx.String(200, "request ok")
}
func main() {
// 获取引擎对象
r := gin.Default()
// 加载HTML资源
r.LoadHTMLGlob("templates/*")
// 设置路由
r.GET("/", func(ctx *gin.Context) {
ctx.HTML(200, "index.html", nil)
})
r.POST("/postform1", handleFunc1)
r.POST("/postform2", handleFunc2)
r.POST("/postform3", handleFunc3)
// 启动
r.Run(":8080")
}
程序运行结果:

2.3.2.3 获取JSON请求体数据
Go语言没有提供类似于 PostForm、Query 这样的API直接获取JSON数据,但是Go提供了ShouldBind
函数,可以将 json 类型的数据自动映射到指定的结构体对象上
语法格式:ctx.ShouldBind(&结构体对象)
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
type Student struct {
Username string `json:"username"`
Password string `json:"password"`
}
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.POST("/", func(ctx *gin.Context) {
// 使用ShouldBind函数获取JSON数据
var student Student
err := ctx.ShouldBind(&student)
if err != nil {
fmt.Println(err)
ctx.String(500, "解析错误")
} else {
fmt.Println(student)
ctx.String(200, "request ok")
}
})
// 启动
r.Run(":8080")
}
程序运行结果:

2.4 Gin框架返回响应
2.4.1 返回HTML页面
语法格式:ctx.HTML(响应状态码, 页面, 数据对象)
- 响应状态码:对应的HTTP状态码
- 页面:具体页面路径
- 数据对象:与模板引擎相关(后续章节介绍)
go
package main
import "github.com/gin-gonic/gin"
func main() {
// 获取引擎对象
r := gin.Default()
// 加载模板文件
r.LoadHTMLGlob("templates/*")
// 设置路由
r.GET("/", func(ctx *gin.Context) {
// 返回首页
ctx.HTML(202, "index.html", nil)
})
// 启动
r.Run(":8080")
}
程序运行结果:

2.4.2 返回String类型
语法格式:ctx.String(响应状态码, 格式化字符串)
- 响应状态码:对应的HTTP状态码
- 格式化字符串:具体返回的文本内容
go
package main
import "github.com/gin-gonic/gin"
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/", func(ctx *gin.Context) {
// 返回sring类型
ctx.String(200, "string 类型")
})
// 启动
r.Run(":8080")
}
程序运行结果:

2.4.3 返回JSON类型
语法格式:ctx.JSON(响应状态码, gin.H对象)
- 响应状态码:对应的HTTP状态码
- gin.H对象:具体返回JSON格式对象
go
package main
import "github.com/gin-gonic/gin"
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/", func(ctx *gin.Context) {
// 返回json类型
ctx.JSON(200, gin.H{
"name": "wjj",
"age": 21,
})
})
// 启动
r.Run(":8080")
}
程序运行结果:

2.4.4 返回XML类型
语法格式:ctx.XML(响应状态码, gin.H对象)
- 响应状态码:对应的HTTP状态码
- gin.H对象:具体返回XML格式对象
go
package main
import "github.com/gin-gonic/gin"
func main() {
// 获取引擎对象
r := gin.Default()
// 设置路由
r.GET("/", func(ctx *gin.Context) {
ctx.XML(200, gin.H{
"name": "wjj",
"age": 21,
})
})
// 启动
r.Run(":8080")
}
程序运行结果:
