gin框架中的路由
基本路由
- gin框架中采用的路由库是基于httrouter做的
- 地址为:https://github.com/julienschmidt/httprouter
httprouter路由库
点击查看代码
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
)
func main() {
router := httprouter.New()
router.GET("/", index)
router.POST("/hello/:name/:age", hello)
http.ListenAndServe(":8080", router)
}
func index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprintln(w, "index页面")
}
func hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// 请求地址:http://127.0.0.1:8080/hello/lisi/15
fmt.Println(ps, ps[0], ps[0].Key, ps[0].Value)
// 输出结果: [{name lisi} {age 15}] {name lisi} name lisi
fmt.Fprintf(w,"hello: %s: %s", ps.ByName("name"), ps.ByName("age"))
}
请求地址:http://127.0.0.1:8080/hello/lisi
返回结果:hello: lisi
Restful风格的API
gin支持Restful风格的API
即Representational State Transfer的缩写。直接翻译的意思是"表现层状态转化",是一种互联网应用程序的API设计理念:URL定位资源,用HTTP描述操作
1.获取文章 /blog/getXxx Get blog/Xxx
2.添加 /blog/addXxx POST blog/Xxx
3.修改 /blog/updateXxx PUT blog/Xxx
4.删除 /blog/delXxxx DELETE blog/Xxx
API参数
- 可以通过Context的Param方法来获取API参数
- localhost:8000/xxx/zhangsan
type Hello struct {}
func (h *Hello) Register(router *gin.Engine) {
// 绑定路由规则执行的函数
router.GET("/hello/:score/*action", h.Hello)
}
func (h *Hello) Hello(context *gin.Context) {
// gin.Context里面封装了request和response
// 上下文是 gin 中最重要的部分。例如,它允许我们在中间件之间传递变量、管理流程、验证请求的 JSON 并呈现 JSON 响应。
context.JSON(http.StatusOK, gin.H{
"name": "zhang",
"age": 18,
"username": context.MustGet("username"),
"score": context.Param("score"),
// strings.Trim 截取
"action": strings.Trim(context.Param("action"), "/"),
})
}
URL参数
- URL参数可以通过DefaultQuery()或Query()方法获取
- DefaultQuery()若参数不村则,返回默认值,Query()若不存在,返回空串
- API ? name=zs
type Hello struct {}
func (h *Hello) Register(router *gin.Engine) {
// 绑定路由规则执行的函数
router.GET("/hello", h.Hello)
}
func (h *Hello) Hello(context *gin.Context) {
// gin.Context里面封装了request和response
// 上下文是 gin 中最重要的部分。例如,它允许我们在中间件之间传递变量、管理流程、验证请求的 JSON 并呈现 JSON 响应。
context.JSON(http.StatusOK, gin.H{
"name": context.Query("name"),
"age": context.DefaultQuery("age", "18"),
})
}
表单参数
- 表单传输为post请求,http常见的传输格式为四种:
- application/json
- application/x-www-form-urlencoded
- application/xml
- multipart/form-data
- 表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或from-data格式的参数
func (h *Hello) Hello(context *gin.Context) {
// gin.Context里面封装了request和response
// 上下文是 gin 中最重要的部分。例如,它允许我们在中间件之间传递变量、管理流程、验证请求的 JSON 并呈现 JSON 响应。
context.JSON(http.StatusOK, gin.H{
"name": context.PostForm("name"),
"age": context.DefaultPostForm("age", "18"),
})
}
上传单个文件
- multipart/form-data格式用于文件上传
- gin文件上传与原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中
type Hello struct {}
func (h *Hello) Register(router *gin.Engine) {
// 绑定路由规则执行的函数
router.POST("/file", h.Hello)
}
func (h *Hello) Hello(context *gin.Context) {
// gin.Context里面封装了request和response
// 上下文是 gin 中最重要的部分。例如,它允许我们在中间件之间传递变量、管理流程、验证请求的 JSON 并呈现 JSON 响应。
file, err := context.FormFile("file")
if err != nil {
fmt.Println(err)
context.String(http.StatusInternalServerError, "上传图片失败")
}
context.SaveUploadedFile(file, "./test/" + file.Filename)
context.String(http.StatusOK, file.Filename)
}
上传特定文件
有的用户上传文件需要限制上传文件的类型以及上传文件的大小,但是gin框架暂时没有这些函数(也有可能是我没找到),因此基于原生的函数写法自己写了一个可以限制大小以及文件类型的上传函数
点击查看代码
type Hello struct {}
func (h *Hello) Register(router *gin.Engine) {
// 绑定路由规则执行的函数
router.POST("/file", h.Hello)
}
func (h *Hello) Hello(context *gin.Context) {
file, err := context.FormFile("file")
if err != nil {
fmt.Println(err)
return
}
// 判断文件大小
if file.Size > 1024 * 1024 {
fmt.Println("文件太大了")
return
}
// 判断文件类型
if types := file.Header.Get("Content-Type"); types != "image/jpeg" {
fmt.Println("文件类型不对,不是image/jpeg类型")
return
}
context.SaveUploadedFile(file, "./test/" + file.Filename)
context.String(http.StatusOK, file.Filename)
}
上传多个文件
点击查看代码
type Hello struct {}
func (h *Hello) Register(router *gin.Engine) {
// 绑定路由规则执行的函数
router.POST("/file", h.Hello)
}
func (h *Hello) Hello(context *gin.Context) {
form , err := context.MultipartForm()
if err != nil {
fmt.Println(err)
return
}
// 获取所有图片
files := form.File["files"]
// 遍历所有图片
for _, file := range files {
// 逐个存
if err = context.SaveUploadedFile(file, "./test/" + file.Filename); err != nil {
fmt.Println(err)
return
}
}
context.String(http.StatusOK, fmt.Sprintf("upload ok %d files", len(files)))
}
routes group
routes group是为了管理一些相同的URL
- main.go
点击查看代码
package main
import (
"common_standard_library/controller"
"github.com/gin-gonic/gin"
)
func main() {
// 创建路由
router := gin.Default()
// 注册中间件
router.Use(setUserNameHandler)
// 注册前台路由
front := router.Group("/front")
registerFrontRouter(front)
// 注册后台路由
admin := router.Group("/admin")
registerAdminRouter(admin)
router.Run()
}
// 前台路由
func registerFrontRouter(router *gin.RouterGroup) {
// 注册index路由
new(controller.Index).Register(router)
}
// 后台路由
func registerAdminRouter(router *gin.RouterGroup) {
// 注册hello路由
new(controller.Hello).Register(router)
}
// 中间件设置变量
func setUserNameHandler(context *gin.Context) {
context.Set("username", "马亚南")
}
点击查看代码
package controller
import "github.com/gin-gonic/gin"
type Index struct {}
func (i *Index) Register(router *gin.RouterGroup) {
router.GET("/index", i.index)
}
func (i *Index) index(context *gin.Context) {
context.JSON(200, "OK")
}
- hello.go
点击查看代码
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
type Hello struct {}
func (h *Hello) Register(router *gin.RouterGroup) {
// 绑定路由规则执行的函数
router.POST("/file", h.hello)
}
func (h *Hello) hello(context *gin.Context) {
form , err := context.MultipartForm()
if err != nil {
fmt.Println(err)
return
}
// 获取所有图片
files := form.File["files"]
// 遍历所有图片
for _, file := range files {
// 逐个存
if err = context.SaveUploadedFile(file, "./test/" + file.Filename); err != nil {
fmt.Println(err)
return
}
}
context.String(http.StatusOK, fmt.Sprintf("upload ok %d files", len(files)))
}
路由原理
- httproter会将所有路由规则构造一颗前缀树
- 例如有 root and as at cn com