首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
Gin框架简介
Gin框架_Router
Gin框架_Model
Gin框架_响应
Gin框架_中间件
Gin框架_数据库
项目实战-项目介绍和项目搭建
项目实战_注册用户信息功能
项目实战-登录功能
项目实战-处理session
项目实战-添加新文章
项目实战-首页设计
项目实战-显示文章详情
项目实战-修改文章
项目实战-删除文章
项目实战-标签功能
项目实战-首页功能扩展
项目实战-文件上传和图片展示功能
项目实战-关于我
当前位置:
首页>>
技术小册>>
Gin框架入门教程
小册名称:Gin框架入门教程
Gin框架的路由 ###一、服务器 1.1 默认服务器 router.Run() ###1.2 Http服务器 除了默认服务器中router.Run()的方式外,还可以用http.ListenAndServe(),比如 ``` func main() { router := gin.Default() http.ListenAndServe(":8080", router) } ``` 运行: ![](/uploads/images/20230707/1b934d85933415b3badc0a5e9c6074a7.png) 浏览器效果: ![](/uploads/images/20230707/a3ad1c1647070c795ebd6db8b37efc33.png) 或者自定义HTTP服务器的配置: ``` func main() { router := gin.Default() s := &http.Server{ Addr: ":8080", Handler: router, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } s.ListenAndServe() } ``` ###二、路由 2.1 基本路由 基本路由 gin 框架中采用的路由库是 httprouter。 ``` // 创建带有默认中间件的路由: // 日志与恢复中间件 router := gin.Default() //创建不带中间件的路由: //r := gin.New() router.GET("/someGet", getting) router.POST("/somePost", posting) router.PUT("/somePut", putting) router.DELETE("/someDelete", deleting) router.PATCH("/somePatch", patching) router.HEAD("/someHead", head) router.OPTIONS("/someOptions", options) ``` ###2.2 路由参数 gin的路由来自httprouter库。因此httprouter具有的功能,gin也具有,不过gin不支持路由正则表达式。 ###2.2.1 API参数 api 参数通过Context的Param方法来获取。 ``` router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, name) }) ``` 运行后浏览器输入:http://127.0.0.1:8000/user/hanru ![](/uploads/images/20230707/6d61907de284acbbbe991c09bf53abe8.png) 冒号:加上一个参数名组成路由参数。可以使用c.Params的方法读取其值。当然这个值是字串string。诸如/user/hanru,和/user/hello都可以匹配,而/user/和/user/hanru/不会被匹配。 ``` router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) ``` 浏览器中输入:http://127.0.0.1:8000/user/hanru/send ![](/uploads/images/20230707/d7c64602de2454948aaa7fecc1b9d15a.png) 除了:,gin还提供了*号处理参数,*号能匹配的规则就更多。 ###2.2.2 URL参数 web提供的服务通常是client和server的交互。其中客户端向服务器发送请求,除了路由参数,其他的参数无非两种,查询字符串query string和报文体body参数。所谓query string,即路由用,用?以后连接的key1=value2&key2=value2的形式的参数。当然这个key-value是经过urlencode编码。 URL 参数通过 DefaultQuery 或 Query 方法获取。 对于参数的处理,经常会出现参数不存在的情况,对于是否提供默认值,gin也考虑了,并且给出了一个优雅的方案,使用c.DefaultQuery方法读取参数,其中当参数不存在的时候,提供一个默认值。使用Query方法读取正常参数,当参数不存在的时候,返回空字串。 ``` func main() { router := gin.Default() router.GET("/welcome", func(c *gin.Context) { name := c.DefaultQuery("name", "Guest") //可设置默认值 //nickname := c.Query("nickname") // 是 c.Request.URL.Query().Get("nickname") 的简写 c.String(http.StatusOK, fmt.Sprintf("Hello %s ", name)) }) router.Run(":9527") } ``` 当浏览器输入的url为:http://127.0.0.1:9527/welcom?name=hanru ![](/uploads/images/20230707/5452dfa893eb3e954edc1ac4f0202f1c.png) 我们可以看到能够显示我们的参数数据,如果没有传递参数,那么就会显示默认值,url为:http://127.0.0.1:9527/welcom ![](/uploads/images/20230707/12a1c30af8a8e758f1c69cfceb578e35.png) ###2.2.3 表单参数 http的报文体传输数据就比query string稍微复杂一点,常见的格式就有四种。例如application/json,application/x-www-form-urlencoded,application/xml和multipart/form-data。后面一个主要用于图片上传。json格式的很好理解,urlencode其实也不难,无非就是把query string的内容,放到了body体里,同样也需要urlencode。默认情况下,c.PostFROM解析的是x-www-form-urlencoded或from-data的参数。 表单参数通过 PostForm 方法获取: ``` func main() { router := gin.Default() //form router.POST("/form", func(c *gin.Context) { type1 := c.DefaultPostForm("type", "alert") //可设置默认值 username := c.PostForm("username") password := c.PostForm("password") //hobbys := c.PostFormMap("hobby") //hobbys := c.QueryArray("hobby") hobbys := c.PostFormArray("hobby") c.String(http.StatusOK, fmt.Sprintf("type is %s, username is %s, password is %s,hobby is %v", type1, username, password,hobbys)) }) router.Run(":9527") } ``` 我们还需要提供一个html页面(login.html),来进行post请求: ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <form action="http://127.0.0.1:9527/form" method="post" enctype="application/x-www-form-urlencoded"> 用户名:<input type="text" name="username"> <br> 密   码:<input type="password" name="password"> <br> 兴   趣: <input type="checkbox" value="girl" name="hobby">女人 <input type="checkbox" value="game" name="hobby">游戏 <input type="checkbox" value="money" name="hobby">金钱 <br> <input type="submit" value="登录"> </form> </body> </html> ``` 然后运行程序后,通过浏览器访问页面: ![](/uploads/images/20230707/d02c03ae5fa0e1e74dec3d58acddeb45.png) 输入用户名和密码后,点击按钮进行登录: ![](/uploads/images/20230707/bca83a66bad4b6c13a40520298feed71.png) username和password数据我们可以获取,type获取不到就使用默认值。 使用PostForm形式,注意必须要设置Post的type,同时此方法中忽略URL中带的参数,所有的参数需要从Body中获得。 ###2.2.4 文件上传 上传单个文件 前面介绍了基本的发送数据,其中multipart/form-data转用于文件上传。gin文件上传也很方便,和原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中了。 首先我们创建一个go文件,demo06_file.go: ``` func main() { router := gin.Default() // Set a lower memory limit for multipart forms (default is 32 MiB) // router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { // single file file, _ := c.FormFile("file") log.Println(file.Filename) // Upload the file to specific dst. c.SaveUploadedFile(file, file.Filename) /* 也可以直接使用io操作,拷贝文件数据。 out, err := os.Create(filename) defer out.Close() _, err = io.Copy(out, file) */ c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) router.Run(":8080") } ``` 使用c.Request.FormFile解析客户端文件name属性。如果不传文件,则会抛错,因此需要处理这个错误。此处我们略写了错误处理。一种是直接用c.SaveUploadedFile()保存文件。另一种方式是使用os的操作,把文件数据复制到硬盘上。 然后我们创建一个html页面,file.html: ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>文件</title> </head> <body> <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data"> 头像: <input type="file" name="file"> <br> <input type="submit" value="提交"> </form> </body> </html> ``` 运行程序后,打开浏览器传递文件: ![](/uploads/images/20230707/f557f5bd00a46bfa206bdf022de42242.png) 点击按钮后进行提交上传: ![](/uploads/images/20230707/6409fc5238f5f83c545ab40ccec9ac73.png) 显示已经上传,我们可以在项目目录下查看文件: ![](/uploads/images/20230707/10201415183d697a50b33f027775ef4b.png) 我们可以看到已经上传成功了一张图片。 我们也可以使用终端命令访问http,上传文件,我们打算传这个视频: ![](/uploads/images/20230707/2201b22406eec63ee95e7e9b4d17ccb8.png) 打开终端,并输入以下命令: ``` hanru:~ ruby$ curl -X POST http://127.0.0.1:8080/upload -F "file=@/Users/ruby/Documents/pro/momo.mp4" -H "Content-Type: multipart/form-data" ``` ![](/uploads/images/20230707/85512943c787edcf0277f1c1abe817f3.png) 我们可以看到这个视频文件已经上传到了项目的目录下。 ###上传多个文件 所谓多个文件,无非就是多一次遍历文件,然后一次copy数据存储即可。 ``` package main import ( "github.com/gin-gonic/gin" "net/http" "fmt" ) func main() { router := gin.Default() // Set a lower memory limit for multipart forms (default is 32 MiB) router.MaxMultipartMemory = 8 << 20 // 8 MiB //router.Static("/", "./public") router.POST("/upload", func(c *gin.Context) { // Multipart form form, err := c.MultipartForm() if err != nil { c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error())) return } files := form.File["files"] for _, file := range files { if err := c.SaveUploadedFile(file, file.Filename); err != nil { c.String(http.StatusBadRequest, fmt.Sprintf("upload file err: %s", err.Error())) return } } c.String(http.StatusOK, fmt.Sprintf("Uploaded successfully %d files ", len(files))) }) router.Run(":8080") } ``` 然后我们提供一个html页面,当然也可以使用终端命令: ``` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>文件s</title> </head> <body> <h1>上传多个文件</h1> <form action="http://127.0.0.1:8080/upload" method="post" enctype="multipart/form-data"> Files: <input type="file" name="files" multiple><br><br> <input type="submit" value="提交"> </form> </body> </html> ``` 然后启动程序后,打开浏览器: ![](/uploads/images/20230707/e505ed4845ff2e005dfa412a46701476.png) 然后进行上传: ![](/uploads/images/20230707/0dde4f89b4c9f67ecfd5506dd61eaf4a.png) 最后打开一下项目目录,查看刚刚上传的文件: ![](/uploads/images/20230707/919b6ce27f56ab58294bf94159999e7c.png) 使用终端命令也可以: ``` curl -X POST http://localhost:8080/upload \ -F "upload[]=@/Users/ruby/Documents/pro/aa.jpeg" \ -F "upload[]=@/Users/ruby/Documents/pro/ad.txt" \ -H "Content-Type: multipart/form-data" ``` 与单个文件上传类似,只不过使用了c.Request.MultipartForm得到文件句柄,再获取文件数据,然后遍历读写。 ###2.2.5 Grouping routes router group是为了方便一部分相同的URL的管理,新建一个go文件(demo08_group.go), ``` package main import ( "github.com/gin-gonic/gin" "net/http" "fmt" ) func main() { router := gin.Default() // Simple group: v1 v1 := router.Group("/v1") { v1.GET("/login", loginEndpoint) v1.GET("/submit", submitEndpoint) v1.POST("/read", readEndpoint) } // Simple group: v2 v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) } router.Run(":8080") } func loginEndpoint(c *gin.Context) { name := c.DefaultQuery("name", "Guest") //可设置默认值 c.String(http.StatusOK, fmt.Sprintf("Hello %s \n", name)) } func submitEndpoint(c *gin.Context) { name := c.DefaultQuery("name", "Guest") //可设置默认值 c.String(http.StatusOK, fmt.Sprintf("Hello %s \n", name)) } func readEndpoint(c *gin.Context) { name := c.DefaultQuery("name", "Guest") //可设置默认值 c.String(http.StatusOK, fmt.Sprintf("Hello %s \n", name)) } ``` 运行程序后,可以通过一个html页面访问,也可以通过终端使用命令直接访问,此处我们使用终端: hanru:~ ruby$ curl http://127.0.0.1:8080/v1/login?name=hanru 运行结果如下: ![](/uploads/images/20230707/188ad68fd52c75303b0267a26b8e7bcc.png)
上一篇:
Gin框架简介
下一篇:
Gin框架_Model
该分类下的相关小册推荐:
gin框架入门指南