Gin框架上传文件、重定向和路由组 | 青训营笔记

348 阅读3分钟

文章第一句话为“这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天

一、总览

  • Gin文件上传

    • 单个文件上传
    • 多个文件上传
  • 重定向

    • HTTP重定向
    • 路由重定向
  • Gin路由

    • 路由组

二、知识点详解

2.1 Gin文件上传

假设现在需要编写一个作业提交页面,学生将自己的实验报告以.pdf的形式提交然后保存在服务器本地。这个场景只涉及单个文件上传,首先我们编写一个上传文件的html代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>上传文件示例</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="f1">
    <input type="submit" value="上传">
</form>
</body>
</html>

使用Gin框架编写后端代码:

func UploadFiles() {
   router := gin.Default()
   router.LoadHTMLFiles("C:\Users\周俊宇\GolandProjects\gin_demo\UploadFiles\index.html")
   router.GET("/upload", func(c *gin.Context) {
      c.HTML(http.StatusOK, "index.html", nil)
   })

```
//从请求中读取单个文件
file, err := c.FormFile("f1") // 类似于从前请求中获取参数
if err != nil {
   c.JSON(http.StatusBadRequest, gin.H{
      "Status Code":         http.StatusBadRequest,
      "Problem Description": err.Error(),
   })
} else {
   // 将读取到的文件保存在本地(服务器本地).
   FilePath := path.Join("C:\Users\周俊宇\GolandProjects\gin_demo\UploadFiles\", file.Filename)
   c.SaveUploadedFile(file, FilePath)
   c.JSON(http.StatusOK, gin.H{
      "status": "保存成功",
   })
}
   router.Run(":9090")
}

用户使用GET请求"/upload"时,服务器会将刚刚我们编写的html返回给客户端,form表单中需要填入的类型为file,其namef1,我们可以调用fromfile()将用户上传的文件用变量存储起来,之后设置保存路径,调用SaveUploadedFile()将文件保存到指定位置。

2.2 多个文件上传

func main() {
	router := gin.Default()
	// 处理multipart forms提交文件时默认的内存限制是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("C:/tmp/%s_%d", file.Filename, index)
			// 上传文件到指定的目录
			c.SaveUploadedFile(file, dst)
		}
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("%d files uploaded!", len(files)),
		})
	})
	router.Run()
}

只需调用方法MultipartForm(),它可以解析有多个部分组成的表单,包括文件。

2.3 HTTP重定向

HTTP重定向很简单,内部外部重定向均支持,当然可以将下面的示例代码中的sogo网址换成你自己定义的路由路径。

r.GET("/test", func(c *gin.Context) {
	c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
})

2.4 路由重定向

路由重定向不同于HTTP重定向,HTTP重定向会将页面跳转至重定向的URL处,下面的代码演示了路由重定向:

r.GET("/test", func(c *gin.Context) {
    // 指定重定向的URL
    c.Request.URL.Path = "/test2"
    r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"hello": "world"})
})

可以看到路由"/test"响应函数并没有编写返回信息,而是将响应交给了路由"/test2"

2.5 路由组

一个路由组里的所有路由都拥有共同的前缀,在web开发时,常常分模块进行开发,比如前缀为"/user"的负责处理用户模块,我们可以对路由进行分组,习惯性第用{}包裹一组路由,当然不加也是一样的:

func main() {
	r := gin.Default()
	userGroup := r.Group("/user")
	{
		userGroup.GET("/index", func(c *gin.Context) {...})
		userGroup.GET("/login", func(c *gin.Context) {...})
		userGroup.POST("/login", func(c *gin.Context) {...})

	}
	shopGroup := r.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {...})
		shopGroup.GET("/cart", func(c *gin.Context) {...})
		shopGroup.POST("/checkout", func(c *gin.Context) {...})
	}
	r.Run()
}

路由组里也支持嵌套:

shopGroup := r.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {...})
		shopGroup.GET("/cart", func(c *gin.Context) {...})
		shopGroup.POST("/checkout", func(c *gin.Context) {...})
		// 嵌套路由组
		xx := shopGroup.Group("xx")
		xx.GET("/oo", func(c *gin.Context) {...})
	}

通常我们将路由分组用在划分业务逻辑或划分API版本时,路由组的基本原理其实就是构造一个路由地址的前缀树。