1.什么是Gin
Gin是go编写的一个web应用框架。git
2.Gin安装github
go get github.com/gin-gonic/gin
3.Gin使用示例web
package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { // 初始化引擎 engine := gin.Default() // 注册一个路由和处理函数 engine.Any("/", WebRoot) // 绑定端口,而后启动应用 engine.Run(":9205") } /** * 根请求处理函数 * 全部本次请求相关的方法都在 context 中,完美 * 输出响应 hello, world */ func WebRoot(context *gin.Context) { context.String(http.StatusOK, "hello, world") }
运行结果:
json
4.路由(Router)
1)restful api
注册路由方法有GET,POST,PUT,PATCH,DELETE,OPTIONSapi
// 省略的代码 ... func main() { router := gin.Default() 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) // 默认绑定 :8080 router.Run() }
2)动态路由(参数路由)
如/user/:idrestful
// 省略的代码 ... func main() { router := gin.Default() // 注册一个动态路由 // 能够匹配 /user/joy // 不能匹配 /user 和 /user/ router.GET("/user/:name", func(c *gin.Context) { // 使用 c.Param(key) 获取 url 参数 name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // 注册一个高级的动态路由 // 该路由会匹配 /user/john/ 和 /user/john/send // 若是没有任何路由匹配到 /user/john, 那么他就会重定向到 /user/john/,从而被该方法匹配到 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) }) router.Run(":8080") } // 省略的代码 ...
3)路由组
url统一前缀app
// 省略的代码 ... func main() { router := gin.Default() // 定义一个组前缀 // /v1/login 就会匹配到这个组 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) v1.POST("/read", readEndpoint) } // 定义一个组前缀 // 不用花括号包起来也是能够的。上面那种只是看起来会统一一点。看你我的喜爱 v2 := router.Group("/v2") v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) router.Run(":8080") } // 省略的代码 ...
5.中间件(middleware)
如验证Auth,身份鉴别,集中处理返回的数据等等。
1)单个路由中间件框架
// 省略的代码 ... func main() { router := gin.Default() // 注册一个路由,使用了 middleware1,middleware2 两个中间件 router.GET("/someGet", middleware1, middleware2, handler) // 默认绑定 :8080 router.Run() } func handler(c *gin.Context) { log.Println("exec handler") } func middleware1(c *gin.Context) { log.Println("exec middleware1") //你能够写一些逻辑代码 // 执行该中间件以后的逻辑 c.Next() } // 省略的代码 ...
c.Next()控制调用逻辑curl
2)路由组使用中间件
中间件放到路由组Group中函数
// 省略的代码 ... func main() { router := gin.Default() // 定义一个组前缀, 并使用 middleware1 中间件 // 访问 /v2/login 就会执行 middleware1 函数 v2 := router.Group("/v2", middleware1) v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) router.Run(":8080") } // 省略的代码 ...
6.参数
1)Url查询参数
使用c.Query方法,该方法始终返回一个string类型的数据。
// 省略的代码 ... func main() { router := gin.Default() // 注册路由和Handler // url为 /welcome?firstname=Jane&lastname=Doe router.GET("/welcome", func(c *gin.Context) { // 获取参数内容 // 获取的全部参数内容的类型都是 string // 若是不存在,使用第二个当作默认内容 firstname := c.DefaultQuery("firstname", "Guest") // 获取参数内容,没有则返回空字符串 lastname := c.Query("lastname") c.String(http.StatusOK, "Hello %s %s", firstname, lastname) }) router.Run(":8080") }
2)表单和body参数(Multipart/Urlencoded Form)
对于POST请求,不管是multipart/form-data,仍是application/x-www-form-urlencoded格式,均可以使用c.PostForm获取到参数,该方法始终返回一个string类型的数据
// 省略的代码 ... func main() { router := gin.Default() router.POST("/form_post", func(c *gin.Context) { // 获取post过来的message内容 // 获取的全部参数内容的类型都是 string message := c.PostForm("message") // 若是不存在,使用第二个当作默认内容 nick := c.DefaultPostForm("nick", "anonymous") c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) }) router.Run(":8080") }
3)上传文件
使用c.FormFile获取文件
// 省略的代码 ... func main() { router := gin.Default() // 设置文件上传大小 router.MaxMultipartMemory = 8 << 20 // 8 MiB // 处理单一的文件上传 router.POST("/upload", func(c *gin.Context) { // 拿到这个文件 file, _ := c.FormFile("file") log.Println(file.Filename) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) // 处理多个文件的上传 router.POST("/uploads", func(c *gin.Context) { form, _ := c.MultipartForm() // 拿到集合 files := form.File["upload[]"] for _, file := range files { log.Println(file.Filename) } c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) }) router.Run(":8080") }
使用curl工具测试一下:
# 单一文件上传 $ curl -X POST http://localhost:8080/upload \ -F "file=@/Users/appleboy/test.zip" \ -H "Content-Type: multipart/form-data" # 多文件上传 $ curl -X POST http://localhost:8080/uploads \ -F "upload[]=@/Users/appleboy/test1.zip" \ -F "upload[]=@/Users/appleboy/test2.zip" \ -H "Content-Type: multipart/form-data"
4)JSON参数(application/json)
使用c.GetRawData
// 省略的代码 ... func main() { router := gin.Default() router.POST("/post", func(c *gin.Context) { // 获取原始字节 d, err := c.GetRawData() if err!=nil { log.Fatalln(err) } log.Println(string(d)) c.String(200, "ok") }) router.Run(":8080") }
curl请求示例:
$ curl -v -X POST \ http://localhost:8080/post \ -H 'content-type: application/json' \ -d '{ "user": "manu" }'
7.数据绑定
将用户传来的参数自动跟咱们定义的结构体绑定在一块儿
1)绑定Url查询参数
使用c.ShouldBindQuery方法
package main import ( "log" "github.com/gin-gonic/gin" ) // 定义一个 Person 结构体,用来绑定 url query type Person struct { Name string `form:"name"` // 使用成员变量标签订义对应的参数名 Address string `form:"address"` } func main() { route := gin.Default() route.Any("/testing", startPage) route.Run(":8085") } func startPage(c *gin.Context) { var person Person // 将 url 查询参数和person绑定在一块儿 if c.ShouldBindQuery(&person) == nil { log.Println("====== Only Bind By Query String ======") log.Println(person.Name) log.Println(person.Address) } c.String(200, "Success") }
2)绑定url查询参数和POST参数
使用c.ShouldBind方法,该方法会检查url查询参数和POST参数,而且会根据content-type类型,优先匹配JSON或XML,以后才是Form
package main import "log" import "github.com/gin-gonic/gin" import "time" // 定义一个 Person 结构体,用来绑定数据 type Person struct { Name string `form:"name"` Address string `form:"address"` Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"` } func main() { route := gin.Default() route.GET("/testing", startPage) route.Run(":8085") } func startPage(c *gin.Context) { var person Person // 绑定到 person if c.ShouldBind(&person) == nil { log.Println(person.Name) log.Println(person.Address) log.Println(person.Birthday) } c.String(200, "Success") }
8.数据验证
Gin提供了数据检验的方法,Gin的数据验证是和数据绑定结合在一块儿的,只须要在数据绑定的结构体成员变量的标签添加bingding规则便可。
// 省略的代码 ... // 定义的 Login 结构体 // 该 struct 能够绑定在 Form 和 JSON 中 // binding:"required" 意思是必要参数。若是未提供,Bind 会返回 error type Login struct { User string `form:"user" json:"user" binding:"required"` Password string `form:"password" json:"password" binding:"required"` } func main() { router := gin.Default() // POST 到这个路由一段 JSON, 如 ({"user": "manu", "password": "123"}) router.POST("/loginJSON", func(c *gin.Context) { var json Login // 验证数据并绑定 if err := c.ShouldBindJSON(&json); err == nil { if json.User == "manu" && json.Password == "123" { c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) } else { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) } } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) // POST 到这个路由一个 Form 表单 (user=manu&password=123) router.POST("/loginForm", func(c *gin.Context) { var form Login // 验证数据并绑定 if err := c.ShouldBind(&form); err == nil { if form.User == "manu" && form.Password == "123" { c.JSON(http.StatusOK, gin.H{"status": "you are logged in"}) } else { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) } } else { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } }) router.Run(":8080") }
9.输出响应
Gin提供了多种常见格式的输出,包括HTML, String, JSON, XML, YAML
1)String
// 省略的代码 ... func Handler(c *gin.Context) { // 使用 String 方法便可 c.String(200, "Success") } // 省略的代码 ...
2)JSON, XML, YAML
gin.H表示实例化一个json对象
// 省略的代码 ... func main() { r := gin.Default() // gin.H 本质是 map[string]interface{} r.GET("/someJSON", func(c *gin.Context) { // 会输出头格式为 application/json; charset=UTF-8 的 json 字符串 c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/moreJSON", func(c *gin.Context) { // 直接使用结构体定义 var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "Lena" msg.Message = "hey" msg.Number = 123 // 会输出 {"user": "Lena", "Message": "hey", "Number": 123} c.JSON(http.StatusOK, msg) }) r.GET("/someXML", func(c *gin.Context) { // 会输出头格式为 text/xml; charset=UTF-8 的 xml 字符串 c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/someYAML", func(c *gin.Context) { // 会输出头格式为 text/yaml; charset=UTF-8 的 yaml 字符串 c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) r.Run(":8080") } // 省略的代码 ...
3)HTML
待实现
10.其余 Gin没有提供ORM,CONFIG组件,能够由开发者本身选择。