11.2Go gin
11.1 Go gin
框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用。
成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用。
Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确。
具有快速灵活,容错方便等特点。
其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。
自身的net/http足够简单,性能也非常不错。
框架更像是一些常用函数或者工具的集合。
借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。
1.1. 使用gin
安装gin
go get github.com/gin-gonic/gin
gin与hello world
package main import (
"net/http" "github.com/gin-gonic/gin"
) func main() {
//gin.Default方法创建路由handler
router := gin.Default()
//绑定路由规则和路由函数,gin支持restful方法
//gin把request和response都封装到了gin.Context的上下文环境中
router.GET("/", func(c *gin.Context) {
//返回字符串
c.String(http.StatusOK, "Hello World")
})
//监听端口
router.Run(":8000")
}
运行代码,即可访问http://0.0.0.0:8000/寻找hello world页面
1.2. restful api
借助于postman测试restful api
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
- PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
- DELETE(DELETE):从服务器删除资源。
- HEAD:获取资源的元数据。
- OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
restful案例
- GET /zoos:列出所有动物园
- POST /zoos:新建一个动物园
- GET /zoos/ID:获取某个指定动物园的信息
- PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
- PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
- DELETE /zoos/ID:删除某个动物园
- GET /zoos/ID/animals:列出某个指定动物园的所有动物
- DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物
状态码
- 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
- 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
- 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
- 204 NO CONTENT - [DELETE]:用户删除数据成功。
- 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
- 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
- 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
- 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
- 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
- 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
- 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
- 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
gin代码示例
用户信息接口设计 restful风格
package main import "github.com/gin-gonic/gin" func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
//匿名函数可以用有名函数,也可以匿名函数
r.GET("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "get user info succ",
})
})
r.POST("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "create user info succ",
})
})
r.PUT("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "update user info succ",
})
})
r.DELETE("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "delete user info succ ",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
非restful风格的API
/user/info
/user/create
/user/delete
/user/update
1.3. Gin框架参数传递
实例代码,传入2个get参数
querystring传递参数
package main import "github.com/gin-gonic/gin" func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/user/search", func(c *gin.Context) {
//username := c.DefaultQuery("username", "少林")
username := c.Query("username")
address := c.Query("address")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"username": username,
"address": address,
})
}) r.Run() // listen and serve on 0.0.0.0:8080
}
通过postman发送请求,携带参数
127.0.0.1:8080/user/search?username=超哥&address=沙河
DefaultQuery返回URL参数
package main import "github.com/gin-gonic/gin" func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/user/search", func(c *gin.Context) {
//使用默认值参数
username := c.DefaultQuery("username", "超老板")
//username := c.Query("username")
address := c.Query("address")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"username": username,
"address": address,
})
}) r.Run() // listen and serve on 0.0.0.0:8080
}
访问结果
127.0.0.1:8080/user/search?address=沙河
1.4. 获取路径中的参数
不建议使用,使用表单或者querystring方式获取参数
package main import "github.com/gin-gonic/gin" func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/user/search/:username/:address", func(c *gin.Context) {
username := c.Param("username")
address := c.Param("address")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"username": username,
"address": address,
})
}) r.Run(":8080") // listen and serve on 0.0.0.0:8080
}
访问方式
127.0.0.1:8080/user/search/chao/beijing/
1.5. 获取表单的参数
package main import "github.com/gin-gonic/gin" func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.POST("/user/search", func(c *gin.Context) {
//username := c.DefaultPostForm("username", "少林")
username := c.PostForm("username")
address := c.PostForm("address")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"username": username,
"address": address,
})
}) r.Run(":8080") // listen and serve on 0.0.0.0:8080
}
运行方式,使用post方式提交form

1.6. Gin文件上传
上传文件的名字应该由服务端统一文件名规则,防止非法字符
package main import (
"fmt"
"log"
"net/http" "github.com/gin-gonic/gin"
) func main() {
router := gin.Default()
// Set a lower memory limit for multipart forms (default is 32 MiB)
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// single file
file, err := c.FormFile("file")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
})
return
}
//
log.Println(file.Filename)
dst := fmt.Sprintf("文件夹路径/%s", file.Filename)
// Upload the file to specific dst.
c.SaveUploadedFile(file, dst)
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
})
})
router.Run(":8080")
}
上传单个文件

上传多个文件
package main import (
"fmt"
"log"
"net/http" "github.com/gin-gonic/gin"
) func main() {
router := gin.Default()
//文件比较大,默认文件存在内中占32M,大于32M就写入到磁盘
// Set a lower memory limit for multipart forms (default is 32 MiB)
//设置上传文件的内存大小
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["file"] for index, file := range files {
log.Println(file.Filename)
dst := fmt.Sprintf("/Users/yuchao/go/src/gostudy/gobook/%s_%d", file.Filename, index)
// Upload the file to specific dst.
c.SaveUploadedFile(file, dst)
}
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("%d files uploaded!", len(files)),
})
})
router.Run(":8080")
}
上传方式

1.7. 路由分组
把前缀一样的url,放入一个组
package main import "github.com/gin-gonic/gin" func login(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
} func read(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
} func submit(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
} func main() {
//Default返回一个默认的路由引擎
router := gin.Default() // Simple group: v1
// /v1/login
// /v1/submit
// /v1/read
v1 := router.Group("/v1")
{
v1.POST("/login", login)
v1.POST("/submit", submit)
v1.POST("/read", read)
} // Simple group: v2
// /v2/login
// /v2/submit
// /v2/read
v2 := router.Group("/v2")
{
v2.POST("/login", login)
v2.POST("/submit", submit)
v2.POST("/read", read)
} router.Run(":8080")
}
运行方式

1.8. Gin参数绑定
使用方便,提高开发效率
通过反射机制,自动提取querystring,from表单,json,xml等参数到struct中
通过http协议中的context type,识别json、xml或是表单
package main import (
"fmt"
"net/http" "github.com/gin-gonic/gin"
) // Binding from JSON
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
} func main() {
router := gin.Default() // Example for binding JSON ({"user": "manu", "password": "123"})
router.POST("/loginJSON", func(c *gin.Context) {
var login Login if err := c.ShouldBindJSON(&login); err == nil {
fmt.Printf("login info:%#v\n", login)
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}) // Example for binding a HTML form (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) {
var login Login
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}) // Example for binding a HTML querystring (user=manu&password=123)
router.GET("/loginForm", func(c *gin.Context) {
var login Login
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}) // Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
json方式提交数据

form方式提交

1.9. gin框架渲染
json渲染
package main import (
"net/http" "github.com/gin-gonic/gin"
) func main() {
r := gin.Default() // gin.H is a shortcut for map[string]interface{}
r.GET("/someJSON", func(c *gin.Context) {
//第一种方式,自己拼json
c.JSON(http.StatusOK, gin.H{"message": "你大爷", "status": http.StatusOK})
}) r.GET("/moreJSON", func(c *gin.Context) {
// You also can use a struct
var msg struct {
Name string `json:"user"`
Message string
Number int
}
msg.Name = "大王"
msg.Message = "大王,唐僧给你捉来了"
msg.Number = 123
// Note that msg.Name becomes "user" in the JSON
c.JSON(http.StatusOK, msg)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}

xml渲染
package main import (
"net/http" "github.com/gin-gonic/gin"
) func main() {
r := gin.Default()
r.GET("/moreXML", func(c *gin.Context) {
// You also can use a struct
type MessageRecord struct {
Name string
Message string
Number int
} var msg MessageRecord
msg.Name = "二王"
msg.Message = "你大爷"
msg.Number = 123
c.XML(http.StatusOK, msg)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}

HTML 模板渲染

package main import (
"net/http" "github.com/gin-gonic/gin"
) func main() {
router := gin.Default()
//模板路径,一层就是templates/*
//两层就是templates/**/*
router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "我是标题",
})
})
router.GET("/users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "我是标题",
})
})
router.Run(":8080")
}
访问路径
注意先go build main.go 再运行
http://127.0.0.1:8080/users/index
http://127.0.0.1:8080/posts/index
1.10. Gin 静态文件服务器
package main import (
"github.com/gin-gonic/gin"
) func main() {
r := gin.Default()
//在main.go同级准备static文件夹,内含图片
r.Static("/static", "./static")
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
注意先go build main.go 再运行
go build main.go
./main.go http://127.0.0.1:8080/static/1.png
1.11. Go中间件
golang的net/http设计的一大特点就是特别容易构建中间件。
gin也提供了类似的中间件。需要注意的是中间件只对注册过的路由函数起作用。
对于分组路由,嵌套使用中间件,可以限定中间件的作用范围。
中间件分为全局中间件,单个路由中间件和群组中间件。
Gin框架允许请求处理过程中,加入用户自己的钩子函数。这个函数就是中间件
利用中间件可以处理例如耗时统计,日志打印,登录校验等
计算耗时的中间件
package main import (
"log"
"time" "net/http" "github.com/gin-gonic/gin"
) func StatCost() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now() //可以设置一些公共参数,
c.Set("example", "12345")
//等其他中间件先执行
c.Next()
//获取耗时
latency := time.Since(t)
//打印花费的时间 319微秒
log.Printf("total cost time:%d us", latency/1000)
}
} func main() {
//新建一个路由 gin.New(),没有中间件
// gin.Default()最常用,包含了中间件
//r := gin.New()
r := gin.Default()
//Use是全局中间件,传入一个
r.Use(StatCost()) r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string) // it would print: "12345"
log.Println(example) //
c.JSON(http.StatusOK, gin.H{
"message": "success",
})
}) // Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
1.12. Gin框架路由原理
gin路由部分用的是
https://github.com/julienschmidt/httprouter

package main import "github.com/gin-gonic/gin" func index(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "index",
})
} func main() {
//Defatult返回一个默认的路由引擎
router := gin.Default()
router.POST("/", index)
router.POST("/search", index)
router.POST("/support", index)
router.POST("/blog/:post", index)
router.POST("/about", index)
router.POST("/contact", index)
router.POST(":8080", index)
}
共用url前缀

11.2Go gin的更多相关文章
- linux的sed命令(一)
转自:https://www.cnblogs.com/ginvip/p/6376049.html Sed 简介 sed 是一种新型的,非交互式的编辑器.它能执行与编辑器 vi 和 ex 相同的编辑任务 ...
- 【liunx】date命令总结
命令简介: date 根据给定格式显示日期或设置系统日期时间.print or set the system date and time 指令所在路径:/bin/date 命令语法: date [OP ...
- tr命令详解
基础命令学习目录 原文链接:https://www.cnblogs.com/ginvip/p/6354440.html 什么是tr命令?tr,translate的简写,translate的翻译: [t ...
- linux命令总结之date命令
命令简介: date 根据给定格式显示日期或设置系统日期时间.print or set the system date and time 指令所在路径:/bin/date 命令语法: date [OP ...
- linux---(6/27)tr命令和sed命令详解
Tr命令: tr是简单的单个“字符”处理工具,而sed是功能非常强大的“字符串”处理工具. 用于查询,字符串2用于处理各种转换.tr刚执行时,字符串1中的字符被映射到字符串2中的字符,然后转换操作开始 ...
- sed命令用法
Sed 简介 sed 是一种新型的,非交互式的编辑器.它能执行与编辑器 vi 和 ex 相同的编辑任务.sed 编辑器没有提供交互式使用方式,使用者只能在命令行输入编辑命令.指定文件名,然后在屏幕上查 ...
- linux sed命令(擅长输出行)(转)
linux命令总结sed命令详解 Sed 简介 sed 是一种新型的,非交互式的编辑器.它能执行与编辑器 vi 和 ex 相同的编辑任务.sed 编辑器没有提供交互式使用方式,使用者只能在命令行输入编 ...
- 地区sql
/*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : lo ...
- Introdution to 3D Game Programming With DirectX11 第11章 习题解答
11.1 这道题要注意使用了line strip,由于曾经一直用triangle list,所以在几何渲染的时候easy算错定点描绘的顺序. 贴一些代码,大概就能把这个问题解释清楚了,由于框架还不是特 ...
随机推荐
- php静态变量的销毁
什么都不说,先上代码: public function _childrenids($data,$cate_id,$clear=false) { static $arr = array(); if ($ ...
- beego微信网页授权
beego.Get("MP_verify_Rj3QAbcdU0MRsyS.txt", func(context *context.Context) { context.Respon ...
- git在用https进行push时候免输账密的方法
先新建一个文件 $ touch ~/.git-credentials $ vim ~/.git-credentials 进去添加内容(github为github.com,码云为gitee.com) h ...
- Golang快速入门:从菜鸟变大佬
最近写了不少Go代码,但是写着写着,还是容易忘,尤其是再写点Python代码后.所以找了一篇不错的Golang基础教程,翻译一下,时常看看. 原文链接: 「Learning Go - from zer ...
- 2019-2020-1 20199328《Linux内核原理与分析》第八周作业
笔记部分 2019/11/4 17:55:22 elf文件代码默认加载到0x8048000,然后是一段首部信息,然后到达程序的真实入口 正常的系统调用会先进入内核态->用户态->系统调用下 ...
- [Qt] 默认的槽函数 例如 on_pushButton_clicked()
在 setupUI 函数里有一句: QMetaObject::connectSlotsByName(QWDialog); 它假设槽函数的名称是 void on_<object name>_ ...
- varnish4.0缓存代理配置
防伪码:你必须非常努力,才能看起来毫不费力. 一.varnish原理: 1)Varnish简介: varnish缓存是web应用加速器,同时也作为http反向缓存代理.你可以安装varnish在任何h ...
- 在CentOS 7中安装配置JDK8
为什么80%的码农都做不了架构师?>>> ###说明 参考博客:http://blog.csdn.net/czmchen/article/details/41047187 系统环 ...
- vue element select多选回显
我们经常在使用 Element组件里面的 select多选 场景:添加账号的时候需要选择可见分公司(分公司为多选),添加成功之后可以编辑,需要回显添加时所提交的分公司 代码如下: 多选框: data( ...
- C# 基础知识系列- 16 开发工具篇
0. 前言 这是C# 基础知识系列的最后一个内容讲解篇,下一篇是基础知识-实战篇.这一篇主要讲解一下C#程序的结构和主要编程工具. 1. 工具 工欲善其事必先利其器,在实际动手之前我们先来看看想要编写 ...