安装

  1. go get -u github.com/gin-gonic/gin
  1. package main
  2. import (
  3. "net/http"
  4. "github.com/gin-gonic/gin"
  5. )
  6. func pong(c *gin.Context) {
  7. c.JSON(http.StatusOK, gin.H{
  8. "message": "pong",
  9. })
  10. }
  11. func main() {
  12. //实例化一个gin的server对象
  13. r := gin.Default()
  14. r.GET("/ping", pong)
  15. r.Run(":8083") // listen and serve on 0.0.0.0:8080
  16. }

使用get、post、put等http方法

  1. func main() {
  2. // 使用默认中间件创建一个gin路由器
  3. // logger(打印日志) and recovery (crash-free) 中间件
  4. router := gin.Default()
  5. //router := gin.New()去掉了上面两个中间件
  6. router.GET("/someGet", getting)
  7. router.POST("/somePost", posting)
  8. router.PUT("/somePut", putting)
  9. router.DELETE("/someDelete", deleting)
  10. router.PATCH("/somePatch", patching)
  11. router.HEAD("/someHead", head)
  12. router.OPTIONS("/someOptions", options)
  13. // 默认启动的是 8080端口,也可以自己定义启动端口
  14. router.Run()
  15. // router.Run(":3000") for a hard coded port
  16. }

url和路由分组

  1. func main() {
  2. router := gin.Default()
  3. // Simple group: v1
  4. v1 := router.Group("/v1")
  5. {
  6. v1.POST("/login", loginEndpoint)
  7. v1.POST("/submit", submitEndpoint)
  8. v1.POST("/read", readEndpoint)
  9. }
  10. // Simple group: v2
  11. v2 := router.Group("/v2")
  12. {
  13. v2.POST("/login", loginEndpoint)
  14. v2.POST("/submit", submitEndpoint)
  15. v2.POST("/read", readEndpoint)
  16. }
  17. router.Run(":8082")
  18. }

带参数的url

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "net/http"
  5. )
  6. func main() {
  7. r := gin.Default()
  8. r.GET("/ping", func(c *gin.Context) {
  9. c.JSON(200, gin.H{
  10. "message": "pong",
  11. })
  12. })
  13. r.GET("/user/:name/:action/", func(c *gin.Context) {
  14. name := c.Param("name")
  15. action := c.Param("action")
  16. c.String(http.StatusOK, "%s is %s", name, action)
  17. })
  18. r.GET("/user/:name/*action", func(c *gin.Context) {
  19. name := c.Param("name")
  20. action := c.Param("action")
  21. c.String(http.StatusOK, "%s is %s", name, action)
  22. })
  23. r.Run(":8082")
  24. }

获取路由分组的参数

  1. package main
  2. import "github.com/gin-gonic/gin"
  3. type Person struct {
  4. ID string `uri:"id" binding:"required,uuid"`
  5. Name string `uri:"name" binding:"required"`
  6. }
  7. func main() {
  8. route := gin.Default()
  9. route.GET("/:name/:id", func(c *gin.Context) {
  10. var person Person
  11. if err := c.ShouldBindUri(&person); err != nil {
  12. c.JSON(400, gin.H{"msg": err})
  13. return
  14. }
  15. c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
  16. })
  17. route.Run(":8088")
  18. }

获取参数

  1. func main() {
  2. router := gin.Default()
  3. //url中添加值,在?后面
  4. // 匹配的url格式: /welcome?firstname=Jane&lastname=Doe
  5. router.GET("/welcome", func(c *gin.Context) {
  6. firstname := c.DefaultQuery("firstname", "Guest")//获取firstname的值,没有值就得默认值
  7. lastname := c.Query("lastname") // 是 c.Request.URL.Query().Get("lastname") 的简写
  8. c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
  9. })
  10. router.Run(":8080")
  11. }
  1. func main() {
  2. router := gin.Default()
  3. router.POST("/form_post", func(c *gin.Context) {
  4. message := c.PostForm("message")//url中是Query,post是PostForm
  5. nick := c.DefaultPostForm("nick", "anonymous") // 此方法可以设置默认值
  6. c.JSON(200, gin.H{
  7. "status": "posted",
  8. "message": message,
  9. "nick": nick,
  10. })
  11. })
  12. router.Run(":8080")
  13. }
  1. POST /post?id=1234&page=1 HTTP/1.1
  2. Content-Type: application/x-www-form-urlencoded
  3. name=manu&message=this_is_great
  4. func main() {
  5. router := gin.Default()
  6. router.POST("/post", func(c *gin.Context) {
  7. id := c.Query("id")//获取的是url中的参数
  8. page := c.DefaultQuery("page", "0")
  9. name := c.PostForm("name")//获取的是表单中的参数
  10. message := c.PostForm("message")
  11. fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
  12. })
  13. router.Run(":8080")
  14. }

Json和protobuf渲染

  1. syntax = "proto3";
  2. option go_package = ".;proto";
  3. message Teacher {
  4. string name = 1;
  5. repeated string course = 2;
  6. }
  1. package main
  2. import (
  3. "net/http"
  4. "github.com/gin-gonic/gin"
  5. "OldPackageTest/gin_start/ch06/proto"
  6. )
  7. func main() {
  8. router := gin.Default()
  9. router.GET("/moreJSON", moreJSON)//直接返回的是json格式数据
  10. router.GET("/someProtoBuf", returnProto)//返回的是proto格式数据(二进制形式)
  11. router.Run(":8083")
  12. }
  13. func returnProto(c *gin.Context) {
  14. course := []string{"python", "go", "微服务"}
  15. user := &proto.Teacher{
  16. Name: "bobby",
  17. Course: course,
  18. }
  19. c.ProtoBuf(http.StatusOK, user)
  20. }
  21. func moreJSON(c *gin.Context) {
  22. var msg struct {
  23. Name string `json:"user"`
  24. Message string
  25. Number int
  26. }
  27. msg.Name = "bobby"
  28. msg.Message = "这是一个测试json"
  29. msg.Number = 20
  30. c.JSON(http.StatusOK, msg)
  31. }

表单验证

image.png
image.png

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "reflect"
  6. "strings"
  7. "github.com/gin-gonic/gin"
  8. "github.com/gin-gonic/gin/binding"
  9. "github.com/go-playground/locales/en"
  10. "github.com/go-playground/locales/zh"
  11. ut "github.com/go-playground/universal-translator"
  12. "github.com/go-playground/validator/v10"
  13. en_translations "github.com/go-playground/validator/v10/translations/en"
  14. zh_translations "github.com/go-playground/validator/v10/translations/zh"
  15. )
  16. var trans ut.Translator
  17. type LoginForm struct {
  18. User string `json:"user" binding:"required,min=3,max=10"`
  19. Password string `json:"password" binding:"required"`
  20. }
  21. type SignUpForm struct {
  22. Age uint8 `json:"age" binding:"gte=1,lte=130"`大于1小于130
  23. Name string `json:"name" binding:"required,min=3"`最小长度为3
  24. Email string `json:"email" binding:"required,email"`内置检测邮箱格式
  25. Password string `json:"password" binding:"required"`
  26. RePassword string `json:"re_password" binding:"required,eqfield=Password"` //跨字段保持一致
  27. }
  28. func removeTopStruct(fileds map[string]string) map[string]string {
  29. rsp := map[string]string{}
  30. for field, err := range fileds {
  31. rsp[field[strings.Index(field, ".")+1:]] = err
  32. }
  33. return rsp
  34. }
  35. //表单验证出错时翻译中文信息
  36. func InitTrans(locale string) (err error) {
  37. //修改gin框架中的validator引擎属性, 实现定制
  38. if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
  39. //注册一个获取json的tag的自定义方法
  40. v.RegisterTagNameFunc(func(fld reflect.StructField) string {
  41. name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
  42. if name == "-" {
  43. return ""
  44. }
  45. return name
  46. })
  47. zhT := zh.New() //中文翻译器
  48. enT := en.New() //英文翻译器
  49. //第一个参数是备用的语言环境,后面的参数是应该支持的语言环境
  50. uni := ut.New(enT, zhT, enT)
  51. trans, ok = uni.GetTranslator(locale)
  52. if !ok {
  53. return fmt.Errorf("uni.GetTranslator(%s)", locale)
  54. }
  55. switch locale {
  56. case "en":
  57. en_translations.RegisterDefaultTranslations(v, trans)
  58. case "zh":
  59. zh_translations.RegisterDefaultTranslations(v, trans)
  60. default:
  61. en_translations.RegisterDefaultTranslations(v, trans)
  62. }
  63. return
  64. }
  65. return
  66. }
  67. func main() {
  68. //代码侵入性很强 中间件
  69. if err := InitTrans("zh"); err != nil {
  70. fmt.Println("初始化翻译器错误")
  71. return
  72. }
  73. router := gin.Default()
  74. router.POST("/loginJSON", func(c *gin.Context) {
  75. var loginForm LoginForm
  76. if err := c.ShouldBind(&loginForm); err != nil {
  77. errs, ok := err.(validator.ValidationErrors)
  78. if !ok {
  79. c.JSON(http.StatusOK, gin.H{
  80. "msg": err.Error(),
  81. })
  82. }
  83. c.JSON(http.StatusBadRequest, gin.H{
  84. "error": removeTopStruct(errs.Translate(trans)),
  85. })
  86. return
  87. }
  88. c.JSON(http.StatusOK, gin.H{
  89. "msg": "登录成功",
  90. })
  91. })
  92. router.POST("/signup", func(c *gin.Context) {
  93. var signUpFrom SignUpForm
  94. if err := c.ShouldBind(&signUpFrom); err != nil {
  95. fmt.Println(err.Error())
  96. c.JSON(http.StatusBadRequest, gin.H{
  97. "error": err.Error(),
  98. })
  99. return
  100. }
  101. c.JSON(http.StatusOK, gin.H{
  102. "msg": "注册成功",
  103. })
  104. })
  105. _ = router.Run(":8083")
  106. }

gin中间件

  1. #使用
  2. r := gin.New()
  3. #替代
  4. // 默认启动方式,包含 Logger、Recovery 中间件
  5. r := gin.Default()
  1. func main() {
  2. // 创建一个不包含中间件的路由器
  3. r := gin.New()
  4. // 全局中间件
  5. // 使用 Logger 中间件
  6. r.Use(gin.Logger())
  7. // 使用 Recovery 中间件
  8. r.Use(gin.Recovery())
  9. // 路由添加中间件,可以添加任意多个
  10. r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
  11. // 路由组中添加中间件
  12. // authorized := r.Group("/", AuthRequired())
  13. // exactly the same as:
  14. authorized := r.Group("/")
  15. // per group middleware! in this case we use the custom created
  16. // AuthRequired() middleware just in the "authorized" group.
  17. authorized.Use(AuthRequired())
  18. {
  19. authorized.POST("/login", loginEndpoint)
  20. authorized.POST("/submit", submitEndpoint)
  21. authorized.POST("/read", readEndpoint)
  22. // nested group
  23. testing := authorized.Group("testing")
  24. testing.GET("/analytics", analyticsEndpoint)
  25. }
  26. // Listen and serve on 0.0.0.0:8080
  27. r.Run(":8080")
  28. }
  1. func Logger() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. t := time.Now()
  4. // Set example variable
  5. c.Set("example", "12345")
  6. // before request
  7. c.Next()
  8. // after request
  9. latency := time.Since(t)
  10. log.Print(latency)
  11. // access the status we are sending
  12. status := c.Writer.Status()
  13. log.Println(status)
  14. }
  15. }
  16. func main() {
  17. r := gin.New()
  18. r.Use(Logger())
  19. r.GET("/test", func(c *gin.Context) {
  20. example := c.MustGet("example").(string)
  21. // it would print: "12345"
  22. log.Println(example)
  23. })
  24. // Listen and serve on 0.0.0.0:8080
  25. r.Run(":8080")
  26. }

设置静态文件路径和html文件

  1. package main
  2. import (
  3. "net/http"
  4. "github.com/gin-gonic/gin"
  5. )
  6. func main() {
  7. // 创建一个默认的路由引擎
  8. r := gin.Default()
  9. // 配置模板
  10. r.LoadHTMLGlob("templates/**/*")
  11. //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
  12. // 配置静态文件夹路径 第一个参数是api,第二个是文件夹路径
  13. r.StaticFS("/static", http.Dir("./static"))
  14. // GET:请求方式;/hello:请求的路径
  15. // 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数
  16. r.GET("/posts/index", func(c *gin.Context) {
  17. // c.JSON:返回JSON格式的数据
  18. c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
  19. "title": "posts/index",
  20. })
  21. })
  22. r.GET("gets/login", func(c *gin.Context) {
  23. c.HTML(http.StatusOK, "posts/login.tmpl", gin.H{
  24. "title": "gets/login",
  25. })
  26. })
  27. // 启动HTTP服务,默认在0.0.0.0:8080启动服务
  28. r.Run()
  29. }
  1. <html>
  2. <h1>
  3. {{ .title }}
  4. </h1>
  5. </html>
  1. {{ define "posts/index.tmpl" }}
  2. <html><h1>
  3. {{ .title }}
  4. </h1>
  5. <p>Using posts/index.tmpl</p>
  6. </html>
  7. {{ end }}
  1. {{ define "users/index.tmpl" }}
  2. <html><h1>
  3. {{ .title }}
  4. </h1>
  5. <p>Using users/index.tmpl</p>
  6. </html>
  7. {{ end }}

优雅重启或停止

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "net/http"
  6. "os"
  7. "os/signal"
  8. "syscall"
  9. "time"
  10. "github.com/gin-gonic/gin"
  11. )
  12. func main() {
  13. router := gin.Default()
  14. router.GET("/", func(c *gin.Context) {
  15. time.Sleep(5 * time.Second)
  16. c.String(http.StatusOK, "Welcome Gin Server")
  17. })
  18. srv := &http.Server{
  19. Addr: ":8080",
  20. Handler: router,
  21. }
  22. go func() {
  23. // service connections
  24. if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
  25. log.Fatalf("listen: %s\n", err)
  26. }
  27. }()
  28. // Wait for interrupt signal to gracefully shutdown the server with
  29. // a timeout of 5 seconds.
  30. quit := make(chan os.Signal)
  31. // kill (no param) default send syscanll.SIGTERM
  32. // kill -2 is syscall.SIGINT
  33. // kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it
  34. signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
  35. <-quit
  36. log.Println("Shutdown Server ...")
  37. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  38. defer cancel()
  39. if err := srv.Shutdown(ctx); err != nil {
  40. log.Fatal("Server Shutdown:", err)
  41. }
  42. // catching ctx.Done(). timeout of 5 seconds.
  43. select {
  44. case <-ctx.Done():
  45. log.Println("timeout of 5 seconds.")
  46. }
  47. log.Println("Server exiting")
  48. }