Gin框架快速入门

Posted Baret-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gin框架快速入门相关的知识,希望对你有一定的参考价值。


参考学习教程



一. 基本介绍

Gin是一个用Go语言编写的web框架。它是一个类似于martini但拥有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍。如果你需要极好的性能,使用 Gin 吧



二. 安装与使用

首先通过go mod init 包名命令创建一个go模块作为项目环境,然后进行后序操作

1、下载并安装 gin:

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

2、将 gin 引入到代码中:

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

3、编写第一个gin实例:

package main

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

func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()
	// 当客户端通过get方式请求/hello时,会执行后面的匿名函数
	r.GET("/hello", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello Gin",
		})
	})
	// 启动http服务,默认在8080端口
    r.Run()
}

4、利用postman进行测试
image-20210527234902480
5、使用Restful API示例

package main

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

func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()
	// 当客户端通过get方式请求/hello时,会执行后面的匿名函数
	r.GET("/hello", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "Hello Gin",
		})
	})

	r.GET("/book", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "GET",
		})
	})

	r.POST("/book", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "POST",
		})
	})

	r.PUT("/book", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "PUT",
		})
	})

	r.DELETE("/book", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "DELETE",
		})
	})
	// 启动http服务,默认在8080端口
	r.Run()
}

然后利用postman进行测试,采用不同的请求方式,请求同样的路径/book,会返回不同结果

ps:浏览器默认只支持get/post请求,如果想要发put/delete请求,需要通过ajax来进行。因此这里推荐使用postman测试



三. Gin渲染

html渲染

1️⃣ 模板定义

首先创建一个存放模板文件的templates文件夹,然后在其内部按照业务分别定义一个post文件夹和一个user文件夹,分别编写对应的index.html模板文件

post/index.html文件的内容如下:

{{define "post/index.html"}}
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>post/index</title>
        </head>
        <body>
            {{.title}}
        </body>
    </html>
{{end}}

user/index.html文件的内容如下:

{{define "user/index.html"}}
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>user/index</title>
        </head>
        <body>
            {{.title}}
        </body>
    </html>
{{end}}

2️⃣ 模板解析&渲染

创建main.go编写http server代码并进行html模板解析渲染,可以使用LoadHTMLGlob()或者LoadHTMLFiles()两种方法进行HTML模板渲染

package main

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

func main() {
	//创建默认的路由引擎
	r := gin.Default()

	//模板解析
	// r.LoadHTMLFiles("./template/user/index.html", "./template/post/index.html")
	r.LoadHTMLGlob("./template/**/*")

	//以get方式发/post/index请求
	r.GET("/post/index", func(c *gin.Context) {
		//模板渲染
		c.HTML(http.StatusOK, "post/index.html", gin.H{"title": "this is post/index.html"})
	})

	//以get方式发/user/index请求
	r.GET("user/index", func(c *gin.Context) {
		//模板渲染
		c.HTML(http.StatusOK, "user/index.html", gin.H{"title": "this is user/index.html"})
	})

	//启动http服务在9090端口
	r.Run(":9090")
}

3️⃣ postman测试

分别测试/user/index/post/index查看结果
image-20210531210237356
image-20210531210257240


自定义模板函数

如果我们想传参<a href='https://bareth.blog.csdn.net/'>BaretH的博客</a>,但是不希望自动转义成字符串,此时就可以自定义一个模板函数进行相应的处理,注意自定义函数的添加要在模板解析之前

package main

import (
	"html/template"
	"net/http"

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

func main() {
	//创建默认的路由引擎
	r := gin.Default()

	//自定义函数safe
	r.SetFuncMap(template.FuncMap{
		"safe": func(str string) template.HTML {
			return template.HTML(str)
		},
	})

	//模板解析
	r.LoadHTMLFiles("./index.html")

	//以get方式发/post/index请求
	r.GET("/index", func(c *gin.Context) {
		//模板渲染
		c.HTML(http.StatusOK, "index.html", "<a href='https://bareth.blog.csdn.net/'>BaretH的博客</a>")
	})

	//启动http服务在9090端口
	r.Run(":9090")
}

这里定义了模板函数safe,然后在模板文件中进行使用

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <title>自定义函数</title>
    </head>
    <body>
        <div>{{ . | safe }}</div>
    </body>
</html>

最后测试:
image-20210531213216006


静态文件处理

当我们渲染的HTML文件中引用了静态文件时,我们只需要按照以下方式在渲染页面前调用gin.Static方法即可

这里创建static目录,然后新建index.css

body {
    background-color: burlywood;
}

然后添加gin.Static方法,该方法有两个参数,第一个为在html文件中引用的目录,第二个参数为实际的静态文件存放目录

package main

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

func main() {
	//创建默认的路由引擎
	r := gin.Default()

	//加载静态文件
	r.Static("/xxx", "./statics")

	//自定义函数safe
	r.SetFuncMap(template.FuncMap{
		"safe": func(str string) template.HTML {
			return template.HTML(str)
		},
	})

	//模板解析
	r.LoadHTMLFiles("./index.html")

	//以get方式发/post/index请求
	r.GET("/index", func(c *gin.Context) {
		//模板渲染
		c.HTML(http.StatusOK, "index.html", "<a href='https://bareth.blog.csdn.net/'>BaretH的博客</a>")
	})

	//启动http服务在9090端口
	r.Run(":9090")
}

然后在index.html文件中引用css文件

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <title>自定义函数</title>
        <link href="/xxx/index.css"></link>
    </head>
    <body>
        <div>{{ . | safe }}</div>
    </body>
</html>

测试可以看到生效:
image-20210531214659995


json渲染

目前主流的we开发方式有两种,一种是浏览器请求服务器,服务器返回完整的html页面内容;第二种就是通过前端框架如vue、react定义好一些模板文件,后端程序只需要返回给前端json格式数据,前端拿到json数据后自行渲染。那么在Gin框架中如何返回json格式数据呢?

在Go语言中,json格式数据可以以两种方式表示:mapstruct,接下来我们模拟json数据,然后请求访问并返回

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	//模拟json数据
	//方式一:map
	user1 := gin.H{
		"name": "zsr",
		"age":  21,
		"sex":  "男",
	}
	//方式二:struct
	type User struct {
		Name string
		Age  int
		Sex  string
	}
	user2 := User{
		"gcc",
		21,
		"女",
	}
	r.GET("/user1", func(c *gin.Context) {
		c.JSON(http.StatusOK, user1)
	})
	r.GET("/user2", func(c *gin.Context) {
		c.JSON(http.StatusOK, user2)
	})
	r.Run(":9090")
}

其中gin.H本质上就是一个map

// H is a shortcut for map[string]interface{}
type H map[string]interface{}

测试结果:
image-20210531223309337
image-20210531235503647
注意这里的c.JSON本质上就是json数据的序列化,默认就是通过Go语言中json包使用反射机制读取数据的,而在Go语言中,首字母小写表示是不可导出的,因此结构体中字段首字母要大写,让json包读取到结构体中的字段,那如过就想要结构体中字段的首字母小写呢?我们可以通过结构体tag来解决,给结构体字段做一些自定制操作

例如下述Name字段后加的json:name表示当使用json包操作Name字段时,名字为小写的name

type User struct {
    Name string	`json:"name"`
    Age  int
    Sex  string
}

image-20210531235606118



四. 获取参数

获取querystring参数

querystring指的是URL中?后面携带的参数,是键值对的形式,例如:localhost:8080?name=zsr&age=21

我们可以通过c.DefaultQuery(可指定默认值获取不到就返回默认值)、c.Query(获取不到返回空)、c.GetQuery(有两个返回值,一个是获取的值,一个是bool类型的表示是否获取成功)三种方法来获取:

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.GET("/hello", func(c *gin.Context) {
		name := c.DefaultQuery("name", "用户名")
		age := c.Query("age")
		c.JSON(http.StatusOK, gin.H{
			"name": name,
			"age":  age,
		})
	})
	r.Run(":9090")
}

然后我们发起一个请求测试,可以看到成功返回请求参数
image-20210601001559328
如果不传name和adreess参数,则返回指定的默认值
image-20210601001428750


获取form表单参数

当前端请求的数据通过form表单提交时,如何获取数据呢?以下是一个小案例

首先是登录页login.html,其中包含form表单有两个待提交参数usernamepassword,提交时发起/home请求

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>login</title>
    </head>
    <body>
        <form action="/home" method="post">
            用户名:<input type="text" name="username"><br>
            密码:<input type="text" name="password"><br>
            <input type="submit" value="登录">
        </form>
    </body>
</html>

然后是主页home.html,接收显示参数usernamepassword

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>login</title>
    </head>
    <body>
        <h1>您的用户名为:{{.username}}</h1>
        <h1>您的密码为:{{.password}}</h1>
    </body>
</html>

最后是main.go

package main

import (
	"net/http"

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

func main() {
	r := gin.Default()
	r.LoadHTMLFiles("./login.html", "./home.html")
    //处理/login的get请求
	r.GET("/login", func(c *gin.Context) {
		c.HTML(http.StatusOK, "login.html", nil)
	})
    //处理/home的post请求
	r.POST("/home", func(c *gin.Context) {
        //获取表单提交的数据
		username := c.PostForm("username")
		password := c.PostForm("password")
		c.HTML(http.StatusOK, "home.html", gin.H{
			"username": username,
			"password": password,
		})
	})
	r.Run(":9090")
}

其中获取参数时同样还有以下写法

//包含默认值
username := c.DefaultPostForm("username", "未知用户名")
password := c.DefaultPostForm("password", "未知密码")

//包含是否获取到结果的bool值
username, nameOk := c.GetPostForm("username")
if !nameOk {
    username = "未知用户名"
}
password, pwdOk := c.GetPostForm("password")
if !pwdOk {
    password = "未知密码"
}

访问测试:首先访问localhost:9090/login,填写用户名和密码
image-20210601004734725
点击登录,然后就会跳转到home.html
image-20210601004822770


获取path参数

请求的参数通过URL路径传递,例如:/user/zsr/18; 获取请求URL路径中的参数的方式如下

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(http.StatusOK, gin.H{
            "message":  "ok",
            "username": username,
            "address":  address,
        })
    })

    r.Run(":8080")
}

测试访问:localhost:9090/user/zsr/18
image-20210601074831848

注意:匹配的url不要冲突,比如现在新增以下请求处理,则会报错,因为路径冲突

r.GET("/user/:year/:month", func(c *gin.Context) 以上是关于Gin框架快速入门的主要内容,如果未能解决你的问题,请参考以下文章

Golang Gin 实战| 快速安装入门

Gin框架

Go fiber 框架快速入门

10gin快速入门

Gin框架入门系列1:基本框架

带你入门gin框架