【Golang】GoWeb框架之Gin-简明教程

在这里插入图片描述

Gin 简介

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance – up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin 是使用 Go/golang 语言实现的 HTTP Web 框架。接口简洁,性能极高。截止 1.4.0 版本,包含测试代码,仅14K,其中测试代码 9K 左右,也就是说框架源码仅 5K 左右。

1 2$ find . -name "*_test.go" | xargs cat | wc -l 38657 4$ find . -name "*.go" | xargs cat | wc -l 514115

Gin 特性

快速:路由不使用反射,基于Radix树,内存占用少。

中间件:HTTP请求,可先经过一系列中间件处理,例如:Logger,Authorization,GZIP等。这个特性和 NodeJs 的 Koa 框架很像。中间件机制也极大地提高了框架的可扩展性。

异常处理:服务始终可用,不会宕机。Gin 可以捕获 panic,并恢复。而且有极为便利的机制处理HTTP请求过程中发生的错误。

JSON:Gin可以解析并验证请求的JSON。这个特性对Restful API的开发尤其有用。

路由分组:例如将需要授权和不需要授权的API分组,不同版本的API分组。而且分组可嵌套,且性能不受影响。

渲染内置:原生支持JSON,XML和HTML的渲染。

安装Go & Gin

初学者建议先阅读 Go 语言简明教程。 一篇文章介绍了 Go 基本类型,结构体,单元测试,并发编程,依赖管理等内容。Go 1.13 以上版本的安装推荐该教程的方式。

安装 Go (Ubuntu)
1 2$ sudo apt-get install golang-go 3$ go version 4#go version go1.6.2 linux/amd64

Ubuntu自带版本太老了,安装新版可以使用如下命令。

1 2$ sudo add-apt-repository ppa:gophers/archive 3$ sudo apt-get update 4$ sudo apt-get install golang-1.11-go

默认安装在/usr/lib/go-1.11,需要将/usr/lib/go-1.11/bin手动加入环境变量。在 .bashrc 中添加下面的配置,并 source ~/.bashrc

1export PATH=$PATH:/usr/lib/go-1.11/bin

参考:Golang Ubuntu - Github

安装 Go (Mac)

1$ brew install go 2$ go version 3# go version go1.12.5 darwin/amd64

设置环境变量

在 ~/.bashrc 中添加 GOPATH 变量

1export GOPATH=~/go 2export PATH=$PATH:$GOPATH/bin

添加完后,source ~/.bashrc

安装一些辅助的工具库

由于网络原因,不能够直接访问 golang.org,但相关的库已经镜像到 Golang - Github

例如,直接安装 go-outline 时会报网络错误,因为golang.org/x/tools是go-outline的依赖库。

1 2$ go get -u -v github.com/ramya-rao-a/go-outline 3github.com/ramya-rao-a/go-outline (download) 4Fetching https://golang.org/x/tools/go/buildutil?go-get=1 5https fetch failed: Get https://golang.org/x/tools/go/buildutil?go-get=1: 6dial tcp 216.239.37.1:443: i/o timeout

因此,可以先从 Github 手动安装好,再安装 go-outline 和 goreturns。

1git clone https://github.com/golang/tools.git $GOPATH/src/golang.org/x/tools 2go get -v github.com/ramya-rao-a/go-outline 3go get -v github.com/sqs/goreturns 4go get -v github.com/rogpeppe/godef

Go语言有大量的辅助工具,如果你使用VSCode,将会提示你将必要的工具,例如静态检查、自动补全等工具依次安装完毕。

安装 Gin

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

-v:打印出被构建的代码包的名字 -u:已存在相关的代码包,强行更新代码包及其依赖包

第一个Gin程序 在一个空文件夹里新建文件main.go。

1 2// geektutu.com 3// main.go 4package main 5 6import "github.com/gin-gonic/gin" 7 8func main() { 9 r := gin.Default() 10 r.GET("/", func(c *gin.Context) { 11 c.String(200, "Hello, Geektutu") 12 }) 13 r.Run() // listen and serve on 0.0.0.0:8080 14}

首先,我们使用了gin.Default()生成了一个实例,这个实例即 WSGI 应用程序。

接下来,我们使用r.Get("/", ...)声明了一个路由,告诉 Gin 什么样的URL 能触发传入的函数,这个函数返回我们想要显示在用户浏览器中的信息。

最后用 r.Run()函数来让应用运行在本地服务器上,默认监听端口是 8080,可以传入参数设置端口,例如r.Run(":9999")即运行在 _9999_端口。

运行

1$ go run main.go 2[GIN-debug] GET / --> main.main.func1 (3 handlers) 3[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default 4[GIN-debug] Listening and serving HTTP on :8080

浏览器访问 http://localhost:8080

路由(Route)

路由方法有 GET, POST, PUT, PATCH, DELETE 和 OPTIONS,还有Any,可匹配以上任意类型的请求。

无参数

1// 无参数 2r.GET("/", func(c *gin.Context) { 3 c.String(http.StatusOK, "Who are you?") 4})

解析路径参数

有时候我们需要动态的路由,如 /user/:name,通过调用不同的 url 来传入不同的 name。/user/:name/role, 代表可选。

1// 匹配 /user/geektutu 2r.GET("/user/:name", func(c *gin.Context) { 3 name := c.Param("name") 4 c.String(http.StatusOK, "Hello %s", name) 5})
1$ curl http://localhost:9999/user/geektutu 2Hello geektutu

获取Query参数

1// 匹配users?name=xxx&role=xxx,role可选 2r.GET("/users", func(c *gin.Context) { 3 name := c.Query("name") 4 role := c.DefaultQuery("role", "teacher") 5 c.String(http.StatusOK, "%s is a %s", name, role) 6})
1$ curl "http://localhost:9999/users?name=Tom&role=student" 2Tom is a student

获取POST参数

1// POST 2r.POST("/form", func(c *gin.Context) { 3 username := c.PostForm("username") 4 password := c.DefaultPostForm("password", "000000") // 可设置默认值 5 6 c.JSON(http.StatusOK, gin.H{ 7 "username": username, 8 "password": password, 9 }) 10})
1 2$ curl http://localhost:9999/form -X POST -d 'username=geektutu&password=1234' 3{"password":"1234","username":"geektutu"}

Query和POST混合参数

1// GET 和 POST 混合 2r.POST("/posts", func(c *gin.Context) { 3 id := c.Query("id") 4 page := c.DefaultQuery("page", "0") 5 username := c.PostForm("username") 6 password := c.DefaultPostForm("username", "000000") // 可设置默认值 7 8 c.JSON(http.StatusOK, gin.H{ 9 "id": id, 10 "page": page, 11 "username": username, 12 "password": password, 13 }) 14})
1$ curl "http://localhost:9999/posts?id=9876&page=7" -X POST -d 'username=geektutu&password=1234' 2{"id":"9876","page":"7","password":"1234","username":"geektutu"}

Map参数(字典参数)

1r.POST("/post", func(c *gin.Context) { 2 ids := c.QueryMap("ids") 3 names := c.PostFormMap("names") 4 5 c.JSON(http.StatusOK, gin.H{ 6 "ids": ids, 7 "names": names, 8 }) 9})
1$ curl -g "http://localhost:9999/post?ids[Jack]=001&ids[Tom]=002" -X POST -d 'names[a]=Sam&names[b]=David' 2{"ids":{"Jack":"001","Tom":"002"},"names":{"a":"Sam","b":"David"}}

重定向(Redirect)

1r.GET("/redirect", func(c *gin.Context) { 2 c.Redirect(http.StatusMovedPermanently, "/index") 3}) 4 5r.GET("/goindex", func(c *gin.Context) { 6 c.Request.URL.Path = "/" 7 r.HandleContext(c) 8})
1$ curl -i http://localhost:9999/redirect 2HTTP/1.1 301 Moved Permanently 3Content-Type: text/html; charset=utf-8 4Location: / 5Date: Thu, 08 Aug 2019 17:22:14 GMT 6Content-Length: 36 7 8<a href="/">Moved Permanently</a>.

$ curl "http://localhost:9999/goindex" Who are you?

分组路由(Grouping Routes)

如果有一组路由,前缀都是/api/v1开头,是否每个路由都需要加上/api/v1这个前缀呢?答案是不需要,分组路由可以解决这个问题。利用分组路由还可以更好地实现权限控制,例如将需要登录鉴权的路由放到同一分组中去,简化权限控制。

1// group routes 分组路由 2defaultHandler := func(c *gin.Context) { 3 c.JSON(http.StatusOK, gin.H{ 4 "path": c.FullPath(), 5 }) 6} 7// group: v1 8v1 := r.Group("/v1") 9{ 10 v1.GET("/posts", defaultHandler) 11 v1.GET("/series", defaultHandler) 12} 13// group: v2 14v2 := r.Group("/v2") 15{ 16 v2.GET("/posts", defaultHandler) 17 v2.GET("/series", defaultHandler) 18}
1$ curl http://localhost:9999/v1/posts 2{"path":"/v1/posts"} 3$ curl http://localhost:9999/v2/posts 4{"path":"/v2/posts"}

上传文件

单个文件
1r.POST("/upload1", func(c *gin.Context) { 2 file, _ := c.FormFile("file") 3 // c.SaveUploadedFile(file, dst) 4 c.String(http.StatusOK, "%s uploaded!", file.Filename) 5})
多个文件
1r.POST("/upload2", func(c *gin.Context) { 2 // Multipart form 3 form, _ := c.MultipartForm() 4 files := form.File["upload[]"] 5 6 for _, file := range files { 7 log.Println(file.Filename) 8 // c.SaveUploadedFile(file, dst) 9 } 10 c.String(http.StatusOK, "%d files uploaded!", len(files)) 11})

HTML模板(Template)

1type student struct { 2 Name string 3 Age int8 4} 5 6r.LoadHTMLGlob("templates/*") 7 8stu1 := &student{Name: "Geektutu", Age: 20} 9stu2 := &student{Name: "Jack", Age: 22} 10r.GET("/arr", func(c *gin.Context) { 11 c.HTML(http.StatusOK, "arr.tmpl", gin.H{ 12 "title": "Gin", 13 "stuArr": [2]*student{stu1, stu2}, 14 }) 15})
1<!-- templates/arr.tmpl --> 2<html> 3<body> 4 <p>hello, {{.title}}</p> 5 {{range $index, $ele := .stuArr }} 6 <p>{{ $index }}: {{ $ele.Name }} is {{ $ele.Age }} years old</p> 7 {{ end }} 8</body> 9</html>
1$ curl http://localhost:9999/arr 2 3<html> 4<body> 5 <p>hello, Gin</p> 6 <p>0: Geektutu is 20 years old</p> 7 <p>1: Jack is 22 years old</p> 8</body> 9</html>

Gin默认使用模板Go语言标准库的模板text/template和html/template,语法与标准库一致,支持各种复杂场景的渲染。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )