go-gin

前置

gin是go的一个web框架,我们简单介绍一下gin的使用

导入gin :"github.com/gin-gonic/gin" 我们使用import导入gin的包

简单示例:

package main

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


func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello world",
		})
	})
    r.Run(":8080")
}

这里定义了一个简单gin-web。我们可以在浏览器中通过访问:localhost:8080/这个url,它会显示

{
  "message": "hello world"
}

创建路由引擎以及设置路由

创建引擎

创建路由引擎的方式有两种

r := gin.Default()  //默认的,内置logger recovery这两个中间件
r := gin.New()      //空的,没有内置中间件

中间件:假设后端是a,前端是b。中间件就是在a和b之间的一个东西,我们根据中间件可以做很多东西。关于中间件的部分我们后面会讲到

 设置路由

设置路由也有两种方法,第一种是一个一个的设置路由

func main() {
	r := gin.Default()
	r.GET("/u/a", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello a",
		})
	})
	r.GET("/u/b", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello b",
		})
	})
	r.GET("/u/c", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello c",
		})
	})
	r.GET("/u/d", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello d",
		})
	})
	r.Run(":8080")
}

这样一个一个的设置虽然简单,但是看起来会很臃肿。而且我们发现它们前面都是 /u的路由,这样设置还容易看错。那我们来看第二种方法:路由分组

路由分组

我们通过 Group方法来设置分组,它的参数就是这个组的前置路由,它会返回一个routergroup的指针,我们通过这个指针来设置后续的子路由

func main() {
	r := gin.Default()
	group := r.Group("/u")//设置路由组
	{
		group.GET("/a", func(c *gin.Context) {//添加组员a
			c.JSON(200, gin.H{
				"message": "hello world",
			})
		})
		group.GET("/b", func(c *gin.Context) {//添加组员b
			c.JSON(200, gin.H{
				"message": "hello world",
			})
		})
		group.GET("/c", func(c *gin.Context) {//添加组员c
			c.JSON(200, gin.H{
				"message": "hello world",
			})
		})
		group.GET("/d", func(c *gin.Context) {//添加组员d
			c.JSON(200, gin.H{
				"message": "hello world",
			})
		})
	}
	r.Run(":8080")//启动
}

这样分组方便我们后续阅读代码以及中间件设置。

数据获取

获取url中的变量

路径参数

group.POST("/c/:name", func(c *gin.Context) {//这里的请求也可以是get或其他请求
			name := c.Param("name")
			c.JSON(200, gin.H{
				"message": name,
			})
		})

我们使用c.Param("name")获取到变量,然后返回数据。

一个路由可以携带多个变量,如 /c/:name/:age 这样我们访问的时候就可以携带两个变量了

查询参数

查询参数的设置如下

group := r.Group("/u")
	{

		group.POST("/c", func(c *gin.Context) {//路由设置没有改变
			name := c.Query("name")//使用Query查询
			c.JSON(200, gin.H{
				"message": name,
			})
		})

	}

这种方式传参的时候需要用 /u/c?name=xxx 这种方式传参,路由后面加个 ?key=value多个参数用&连接

获取表单数据

前端有时候会返回一个表单的数据,我们需要从表单中获取我们需要的数据。这里我们一般都使用post请求,因为它不会把信息显示在url中。get请求也可以但是我们只有在特定的情况下才会使用get请求(因为url的长度有限制)

这里的请求方法取决于表单的method
form表单有两个属性,一个method指定请求方法,一个action指定请求的url。

post请求获取表单数据

<form action="http://localhost:8080/u/c" method="POST">
        <input type="text" name="name">
        <input type="text" name="pass">
        <input type="submit" value="submittt">
</form>

这是一个简单的表单,里面包含name、id还有一个提交按钮。请求方法为post,提交到http://localhost:8080/u/c这个url

我们如果要获取它的表单数据,需要知道提交过来的数据的 name 属性是什么,然后使用PostForm获取

func main() {
	r := gin.Default()
	group := r.Group("/u")
	{

		group.POST("/c", func(c *gin.Context) {
			name := c.PostForm("name")//对应表单name属性为name的文本域
			pass := c.PostForm("pass")//对应表单name属性为pass的文本域
			fmt.Println(name, pass)
			c.JSON(http.StatusOK, gin.H{
				"name": name,
				"pass": pass,
			})
		})

	}
	r.Run(":8080")
}

如果要获取单选框也是使用PostForm。多选框则是PostFormArray,而且返回的是一个string类型的切片
多选框内,多个相同的name属性的选择是一组,value属性对应获取到的值是什么

html代码

<form action="http://localhost:8080/u/c" method="POST" >
        <input type="checkbox" name="remember" value="1">
        <input type="checkbox" name="remember" value="2">
        <input type="checkbox" name="remember" value="3">
        <input type="checkbox" name="remember" value="4">
        <input type="submit" value="submittt">
</form>

go代码

func main() {
	r := gin.Default()
	group := r.Group("/u")
	{

		group.POST("/c", func(c *gin.Context) {
			arr := c.PostFormArray("remember")
			fmt.Println(reflect.TypeOf(arr))
			c.JSON(http.StatusOK, gin.H{
				"arr": arr,
			})
		})

	}
	r.Run(":8080")
}

post请求获取表单文件

有的时候表单也是需要上传一些文件的,这时候就需要我们获取文件信息了

首先是表单部分,在表单的头部我们需要添加  enctype="multipart/form-data"这个属性来说明是含文件的上传

<form action="http://localhost:8080/u/c" method="POST" enctype="multipart/form-data" >
        <input type="file" name="file">
        <input type="submit" value="submittt">
</form>

后端获取的时候需要使用c.FormFile()

group.POST("/c", func(c *gin.Context) {
			file, err := c.FormFile("file")//返回文件和错误信息
			if err != nil {
				fmt.Println("err:", err)
				return
			} else {
				fmt.Println(file.Filename)//文件名
				fmt.Println(file.Size)//文件大小
				os.MkdirAll("./tmp", os.ModePerm)//新建一个目录,如果目录存在就不会报错,而是直接跳过
				err := c.SaveUploadedFile(file, "./tmp/"+file.Filename)//保存
                if err!= nil {
                错误处理
                }
			}
		})

我们如果需要保存文件就要使用 c.SaveUploadedFile(file, "保存路径"+file.Filename),这个路径需要我们提前创建好。它会返回一个错误信息,我们可以根据错误信息来判断是否存储成功

gin的中间件

中间件的本质就是一个函数,该函数的作用是检查某些数据是否是正常数据,从而决定是否继续执行

设置中间件的方法主要有以下几种

  1. 全局设置         --   设置到路由引擎上
  2. 单个路由设置  --   设置到单个的路由上
  3. 路由组设置      --    设置到一个路由组上
func main() {
	r := gin.New()
	r.Use()//全局引用中间件
	group := r.Group("/u").Use()//路由组引用中间件
	{
		group.GET("/a", func(c *gin.Context) {
			c.JSON(200, gin.H{
				"message": "hello world",
			})
		})

	}
	r.GET("/b", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "hello world",
		})
	}).Use()//单个路由引用中间件
	r.Run(":8080")
}

中间件执行的顺序是和引用的顺序有关

.Use(中间件a,b,c,d)这里引用了四个中间件,当我访问对应的路由的时候这四个中间件会按照abcd的顺序挨个执行

var str string

func A() gin.HandlerFunc {
	return func(c *gin.Context) {
		str = str + "a "
	}
}
func B() gin.HandlerFunc {
	return func(c *gin.Context) {
		str = str + "b "
	}
}
func C() gin.HandlerFunc {
	return func(c *gin.Context) {
		str = str + "c "
	}
}
func D() gin.HandlerFunc {
	return func(c *gin.Context) {
		str = str + "d "
	}
}

func main() {
	r := gin.New()
	r.Use(A(), B(), C(), D()) //全局引用中间件
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"str:": str,
		})
	})
	r.Run(":8080")
}

我们访问http://localhost:8080/这个路由的时候网页上显示的就是{"str:":"a b c d "}

这就是基础的中间件使用,假设abcd是四个不同的验证件,其中一个出错就不能继续执行后面的了,而是返回错误信息。这里我们要使用的是c.Abrot() c.Next()两个流程控制函数

c.Next()这个函数的作用就是允许执行后续中间件以及最终处理函数
c.Abrot()这个函数就是不执行后续的中间件和最终处理函数
无论是abrot还是next,它们所在的中间件都会完整的执行,除非return了。

var str string

func A() gin.HandlerFunc {
	return func(c *gin.Context) {
		if str == "" {//判断是否正确,正确则拼接字符串,否则报错
			str = str + "a "
			c.Next()
		} else {
			c.AbortWithStatus(http.StatusNotAcceptable)		}
	}
}
func B() gin.HandlerFunc {
	return func(c *gin.Context) {
		if str == "a " {
			str = str + "b "
			c.Next()
		} else {
			c.AbortWithStatus(http.StatusNotAcceptable)		}
	}
}
func C() gin.HandlerFunc {
	return func(c *gin.Context) {
		if str == "a b " {
			str = str + "c "
			c.Next()
		} else {
			c.AbortWithStatus(http.StatusNotAcceptable)
		}
	}
}
func D() gin.HandlerFunc {
	return func(c *gin.Context) {
		if str == "a b c " {
			str = str + "d "
			c.Next()
		} else {
			c.AbortWithStatus(http.StatusNotAcceptable)		}
	}
}
func main() {
	r := gin.New()
	r.Use(A(), B(), C(), D()) //全局引用中间件
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"str:": str,
		})
	})
	r.Run(":8080")
}

这里的abort有多个版本

  1. Abort()
  2. AbortWithStatus(状态码)
  3. AbortWithStatusJSON(状态码,gin.H{key:value})

前两个访问的时候浏览器都是访问错误,后面的会返回我们的json数据到浏览器上

gin加载HTML

gin设置静态资源目录

r.Static("/static", "./static")
当我们访问/static的时候就是访问的项目中的./static,也就是说可以在浏览器访问一些文件。

加载HTML模板

r.LoadHTMLGlob("templates/*")         加载templates下的所有.html文件
 

返回HTML文件

使用c.HTML(状态码,“html文件”,gin.H{})

这里要注意的是我们如果使用r.LoadHTMLGlob("templates/*") 之后,单独的一个index.html文件其实就是加载的templates/index.html文件

最后的gin.H{}是传入模板的数据,它传递的是key:value的形式,前端html文件可以通过{{.key}}来访问这个value

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值