文章第一句话为“这是我参与「第五届青训营 」伴学笔记创作活动的第 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,其name为f1,我们可以调用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版本时,路由组的基本原理其实就是构造一个路由地址的前缀树。