Gin框架使用详解
1.什么是Gin
Gin是go编写的一个web应用框架。
2.Gin安装
go get github.com/gin-gonic/gin
3.Gin使用示例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
// 初始化引擎
engine := gin.Default()
// 注册一个路由和处理函数
engine.Any("/", WebRoot)
// 绑定端口,然后启动应用
engine.Run(":9205")
}
/**
* 根请求处理函数
* 所有本次请求相关的方法都在 context 中,完美
* 输出响应 hello, world
*/
func WebRoot(context *gin.Context) {
context.String(http.StatusOK, "hello, world")
}
运行结果:

4.路由(Router)
1)restful api
注册路由方法有GET,POST,PUT,PATCH,DELETE,OPTIONS
// 省略的代码 ...
func main() {
router := gin.Default()
router.GET("/someGet", getting)
router.POST("/somePost", posting)
router.PUT("/somePut", putting)
router.DELETE("/someDelete", deleting)
router.PATCH("/somePatch", patching)
router.HEAD("/someHead", head)
router.OPTIONS("/someOptions", options)
// 默认绑定 :8080
router.Run()
}
2)动态路由(参数路由)
如/user/:id
// 省略的代码 ...
func main() {
router := gin.Default()
// 注册一个动态路由
// 可以匹配 /user/joy
// 不能匹配 /user 和 /user/
router.GET("/user/:name", func(c *gin.Context) {
// 使用 c.Param(key) 获取 url 参数
name := c.Param("name")
c.String(http.StatusOK, "Hello %s", name)
})
// 注册一个高级的动态路由
// 该路由会匹配 /user/john/ 和 /user/john/send
// 如果没有任何路由匹配到 /user/john, 那么他就会重定向到 /user/john/,从而被该方法匹配到
router.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
message := name + " is " + action
c.String(http.StatusOK, message)
})
router.Run(":8080")
}
// 省略的代码 ...
3)路由组
url统一前缀
// 省略的代码 ...
func main() {
router := gin.Default()
// 定义一个组前缀
// /v1/login 就会匹配到这个组
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// 定义一个组前缀
// 不用花括号包起来也是可以的。上面那种只是看起来会统一一点。看你个人喜好
v2 := router.Group("/v2")
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
router.Run(":8080")
}
// 省略的代码 ...
5.中间件(middleware)
如验证Auth,身份鉴别,集中处理返回的数据等等。
1)单个路由中间件
// 省略的代码 ...
func main() {
router := gin.Default()
// 注册一个路由,使用了 middleware1,middleware2 两个中间件
router.GET("/someGet", middleware1, middleware2, handler)
// 默认绑定 :8080
router.Run()
}
func handler(c *gin.Context) {
log.Println("exec handler")
}
func middleware1(c *gin.Context) {
log.Println("exec middleware1")
//你可以写一些逻辑代码
// 执行该中间件之后的逻辑
c.Next()
}
// 省略的代码 ...
c.Next()控制调用逻辑
2)路由组使用中间件
中间件放到路由组Group中
// 省略的代码 ...
func main() {
router := gin.Default()
// 定义一个组前缀, 并使用 middleware1 中间件
// 访问 /v2/login 就会执行 middleware1 函数
v2 := router.Group("/v2", middleware1)
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
router.Run(":8080")
}
// 省略的代码 ...
6.参数
1)Url查询参数
使用c.Query方法,该方法始终返回一个string类型的数据。
// 省略的代码 ...
func main() {
router := gin.Default()
// 注册路由和Handler
// url为 /welcome?firstname=Jane&lastname=Doe
router.GET("/welcome", func(c *gin.Context) {
// 获取参数内容
// 获取的所有参数内容的类型都是 string
// 如果不存在,使用第二个当做默认内容
firstname := c.DefaultQuery("firstname", "Guest")
// 获取参数内容,没有则返回空字符串
lastname := c.Query("lastname")
c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})
router.Run(":8080")
}
2)表单和body参数(Multipart/Urlencoded Form)
对于POST请求,无论是multipart/form-data,还是application/x-www-form-urlencoded格式,都可以使用c.PostForm获取到参数,该方法始终返回一个string类型的数据
// 省略的代码 ...
func main() {
router := gin.Default()
router.POST("/form_post", func(c *gin.Context) {
// 获取post过来的message内容
// 获取的所有参数内容的类型都是 string
message := c.PostForm("message")
// 如果不存在,使用第二个当做默认内容
nick := c.DefaultPostForm("nick", "anonymous")
c.JSON(200, gin.H{
"status": "posted",
"message": message,
"nick": nick,
})
})
router.Run(":8080")
}
3)上传文件
使用c.FormFile获取文件
// 省略的代码 ...
func main() {
router := gin.Default()
// 设置文件上传大小 router.MaxMultipartMemory = 8 << 20 // 8 MiB
// 处理单一的文件上传
router.POST("/upload", func(c *gin.Context) {
// 拿到这个文件
file, _ := c.FormFile("file")
log.Println(file.Filename)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
// 处理多个文件的上传
router.POST("/uploads", func(c *gin.Context) {
form, _ := c.MultipartForm()
// 拿到集合
files := form.File["upload[]"]
for _, file := range files {
log.Println(file.Filename)
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
})
router.Run(":8080")
}
使用curl工具测试一下:
# 单一文件上传
$ curl -X POST http://localhost:8080/upload \
-F "file=@/Users/appleboy/test.zip" \
-H "Content-Type: multipart/form-data"
# 多文件上传
$ curl -X POST http://localhost:8080/uploads \
-F "upload[]=@/Users/appleboy/test1.zip" \
-F "upload[]=@/Users/appleboy/test2.zip" \
-H "Content-Type: multipart/form-data"
4)JSON参数(application/json)
使用c.GetRawData
// 省略的代码 ...
func main() {
router := gin.Default()
router.POST("/post", func(c *gin.Context) {
// 获取原始字节
d, err := c.GetRawData()
if err!=nil {
log.Fatalln(err)
}
log.Println(string(d))
c.String(200, "ok")
})
router.Run(":8080")
}
curl请求示例:
$ curl -v -X POST \
http://localhost:8080/post \
-H 'content-type: application/json' \
-d '{ "user": "manu" }'
7.数据绑定
将用户传来的参数自动跟我们定义的结构体绑定在一起
1)绑定Url查询参数
使用c.ShouldBindQuery方法
package main
import (
"log"
"github.com/gin-gonic/gin"
)
// 定义一个 Person 结构体,用来绑定 url query
type Person struct {
Name string `form:"name"` // 使用成员变量标签定义对应的参数名
Address string `form:"address"`
}
func main() {
route := gin.Default()
route.Any("/testing", startPage)
route.Run(":8085")
}
func startPage(c *gin.Context) {
var person Person
// 将 url 查询参数和person绑定在一起
if c.ShouldBindQuery(&person) == nil {
log.Println("====== Only Bind By Query String ======")
log.Println(person.Name)
log.Println(person.Address)
}
c.String(200, "Success")
}
2)绑定url查询参数和POST参数
使用c.ShouldBind方法,该方法会检查url查询参数和POST参数,并且会根据content-type类型,优先匹配JSON或XML,之后才是Form
package main
import "log"
import "github.com/gin-gonic/gin"
import "time"
// 定义一个 Person 结构体,用来绑定数据
type Person struct {
Name string `form:"name"`
Address string `form:"address"`
Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}
func main() {
route := gin.Default()
route.GET("/testing", startPage)
route.Run(":8085")
}
func startPage(c *gin.Context) {
var person Person
// 绑定到 person
if c.ShouldBind(&person) == nil {
log.Println(person.Name)
log.Println(person.Address)
log.Println(person.Birthday)
}
c.String(200, "Success")
}
8.数据验证
Gin提供了数据检验的方法,Gin的数据验证是和数据绑定结合在一起的,只需要在数据绑定的结构体成员变量的标签添加bingding规则即可。
// 省略的代码 ...
// 定义的 Login 结构体
// 该 struct 可以绑定在 Form 和 JSON 中
// binding:"required" 意思是必要参数。如果未提供,Bind 会返回 error
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
router := gin.Default()
// POST 到这个路由一段 JSON, 如 ({"user": "manu", "password": "123"})
router.POST("/loginJSON", func(c *gin.Context) {
var json Login
// 验证数据并绑定
if err := c.ShouldBindJSON(&json); err == nil {
if json.User == "manu" && json.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
}
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// POST 到这个路由一个 Form 表单 (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) {
var form Login
// 验证数据并绑定
if err := c.ShouldBind(&form); err == nil {
if form.User == "manu" && form.Password == "123" {
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
}
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
router.Run(":8080")
}
9.输出响应
Gin提供了多种常见格式的输出,包括HTML, String, JSON, XML, YAML
1)String
// 省略的代码 ...
func Handler(c *gin.Context) {
// 使用 String 方法即可
c.String(200, "Success")
}
// 省略的代码 ...
2)JSON, XML, YAML
gin.H表示实例化一个json对象
// 省略的代码 ...
func main() {
r := gin.Default()
// gin.H 本质是 map[string]interface{}
r.GET("/someJSON", func(c *gin.Context) {
// 会输出头格式为 application/json; charset=UTF-8 的 json 字符串
c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
r.GET("/moreJSON", func(c *gin.Context) {
// 直接使用结构体定义
var msg struct {
Name string `json:"user"`
Message string
Number int
}
msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
// 会输出 {"user": "Lena", "Message": "hey", "Number": 123}
c.JSON(http.StatusOK, msg)
})
r.GET("/someXML", func(c *gin.Context) {
// 会输出头格式为 text/xml; charset=UTF-8 的 xml 字符串
c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
r.GET("/someYAML", func(c *gin.Context) {
// 会输出头格式为 text/yaml; charset=UTF-8 的 yaml 字符串
c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
r.Run(":8080")
}
// 省略的代码 ...
3)HTML
待实现
10.其他
Gin没有提供ORM,CONFIG组件,可以由开发者自己选择。
Gin框架使用详解的更多相关文章
- Hadoop 新 MapReduce 框架 Yarn 详解
Hadoop 新 MapReduce 框架 Yarn 详解: http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-yarn/ Ap ...
- 测试框架mochajs详解
测试框架mochajs详解 章节目录 关于单元测试的想法 mocha单元测试框架简介 安装mocha 一个简单的例子 mocha支持的断言模块 同步代码测试 异步代码测试 promise代码测试 不建 ...
- 转: javascript模块加载框架seajs详解
javascript模块加载框架seajs详解 SeaJS是一个遵循commonJS规范的javascript模块加载框架,可以实现javascript的模块化开发和模块化加载(模块可按需加载或全部加 ...
- Android热门网络框架Volley详解[申明:来源于网络]
Android热门网络框架Volley详解[申明:来源于网络] 地址:http://www.cnblogs.com/caobotao/p/5071658.html
- 【python3+request】python3+requests接口自动化测试框架实例详解教程
转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...
- python+requests接口自动化测试框架实例详解
python+requests接口自动化测试框架实例详解 转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实 ...
- redux-saga框架使用详解及Demo教程
redux-saga框架使用详解及Demo教程 前面我们讲解过redux框架和dva框架的基本使用,因为dva框架中effects模块设计到了redux-saga中的知识点,可能有的同学们会用dva框 ...
- Quartz.net开源作业调度框架使用详解
前言 quartz.net作业调度框架是伟大组织OpenSymphony开发的quartz scheduler项目的.net延伸移植版本.支持 cron-like表达式,集群,数据库.功能性能强大更不 ...
- Quartz.net开源作业调度框架使用详解(转)
前言 quartz.net作业调度框架是伟大组织OpenSymphony开发的quartz scheduler项目的.net延伸移植版本.支持 cron-like表达式,集群,数据库.功能性能强大更不 ...
随机推荐
- Alpha(7/10)
鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...
- LOJ.6073.[2017山东一轮集训Day5]距离(可持久化线段树 树链剖分)
题目链接 就是恶心人的,简单写写了...(似乎就是[HNOI2015]开店?) 拆式子,记\(dis_i\)为\(i\)到根节点的路径权值和,\(Ans=\sum dis_{p_i}+\sum dis ...
- NEO学习笔记,从WIF到地址
2018开年,先给大家拜个年,Happy Neo Year. 开年总得写点什么,就打算继续开学习笔记系列,一点一点仔细的去分析NEO. 今天说一说从WIF到地址的这一串关系. 简单说就一张图: 或 ...
- Java并发编程(十二)-- 阻塞队列
在介绍Java的阻塞队列之前,我们简单介绍一下队列. 队列 队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就是说,队列以一种先进先出的方式管理数据,如果你试图向 ...
- [CF575B]Bribes
[CF575B]Bribes 题目大意: 一棵\(n(n\le10^5)\)个结点的树,有些边有方向,对于每条边,如果第\(i\)次逆向走过这条边,就会产生\(2^{i-1}\)的代价.开始在\(1\ ...
- nodejs+koa2微信app支付,小程序支付
企业付款到零钱文档:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2 1,搞微信支付,先看流程图 https: ...
- bzoj3376/poj1988[Usaco2004 Open]Cube Stacking 方块游戏 — 带权并查集
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3376 题目大意: 编号为1到n的n(1≤n≤30000)个方块正放在地上.每个构成一个立方 ...
- [模板][P3803]多项式乘法
Description: FFT真的容易忘,所以就放到上面来了 #include<bits/stdc++.h> using namespace std; const int mxn=4e6 ...
- VS2013 C#中调用DLL
winform界面中,使用C#编程调用DLL过程记录: (1)什么是DLL 动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL 是一个包含可由多个程序同时使用的代码 ...
- 09树莓派一体化安装(All-In-One Installer)智能家居平台Home Assistant
2017-08-30 13:29:38 Raspberry Pi All-In-One Installer 全新安装树莓派系统(系统为官方的RASPBIAN STRETCH WITH DESKTOP, ...