Gin框架

RESTful API

以前写网站

  • get /user

  • post /create_user

  • post /update_user

  • post /delete_user

RESTful API

  • get /user 获取

  • post /user 新建

  • put /user 更新

  • patch /user 更新部分

  • delete /user 删除

  • REST与技术无关,代表的是一种软件架构风格只要API程序遵循了REST风格,那就可以称其为RESTful API

  • REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的4个请求方法代表不同的动作

    • get

    • post

    • put

    • patch

    • delete

  • Gin框架支持开发RESTful API的开发

  • package main
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 创建一个服务
    	ginServer := gin.Default()
    	// 访问地址,处理请求 Request Response
    	ginServer.GET("/hello", func(context *gin.Context) {
    		context.JSON(200, gin.H{"msg": "hello,world"})
    	})
    	ginServer.POST("/user", func(ctx *gin.Context) {
    		ctx.JSON(http.StatusOK, gin.H{"msg": "post请求"})
    	})
    	ginServer.PUT("/user")
    	ginServer.DELETE("/user")
    
    	// 服务器端口
    	err := ginServer.Run(":8082")
    	if err != nil {
    		return
    	}
    }

第一个Gin示例

// cmd
go get -u github.com/gin-gonic/gin
package main
​
import (
    "github.com/gin-gonic/gin"
)
​
func main() {
    // 创建一个服务
    ginServer := gin.Default()
    // 访问地址,处理请求 Request Response
    ginServer.GET("/hello", func(context *gin.Context) {
        context.JSON(200, gin.H{"msg": "hello,world"})
        // http.StatusOK就是请求已经成功的200的状态码
    })
​
    // 服务器端口
    err := ginServer.Run(":8082")
    if err != nil {
        return
    }
}
  • 想要更改左上角的图标

    • package main
      ​
      import (
          "github.com/gin-gonic/gin"
          "github.com/thinkerou/favicon" // go get
      )
      ​
      func main() {
          // 创建一个服务
          ginServer := gin.Default()
          ginServer.Use(favicon.New("./favicon.ico"))
          // 访问地址,处理请求 Request Response
          ginServer.GET("/hello", func(context *gin.Context) {
              context.JSON(200, gin.H{"msg": "hello,world"})
          })
      ​
          // 服务器端口
          ginServer.Run(":8082")
      }

加载静态页面

  • package main
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 创建一个服务
    	ginServer := gin.Default()
    	// ginServer.Use(favicon.New("./favicon.ico"))
    
    	// 加载静态页面
    	ginServer.LoadHTMLGlob("templates/*")
    	// ginServer.LoadHTMLFiles("templates/index.html")
    	// LoadHTMLGlob是全局加载Files是指定文件
    
    	// 响应一个页面给前端
    	ginServer.GET("/index", func(context *gin.Context) {
    		// context.JSON() json数据
    		context.HTML(http.StatusOK, "index.html", gin.H{
    			"msg": "这是go后台传入的数据",
    		})
    	})
    
    	// 服务器端口
    	err := ginServer.Run(":8082")
    	if err != nil {
    		return
    	}
    }

  • 新建一个文件夹templates,在其下面创建index.html文件

  • <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>一个GoWeb页面</title>
    </head>
    <body>
        <h1>感谢大家支持江小年的博客</h1>
        获取后端的数据为:
        {{.msg}}
    </body>
    </html>

加载资源包

  • 创建static文件夹

    • 在其中创建css文件夹

      • style.css

    • js文件夹

      • common.js

  • package main
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 创建一个服务
    	ginServer := gin.Default()
    	// ginServer.Use(favicon.New("./favicon.ico"))
    
    	// 加载静态页面
    	ginServer.LoadHTMLGlob("templates/*")
    	// ginServer.LoadHTMLFiles("templates/index.html")
    	// LoadHTMLGlob是全局加载Files是指定文件
    
    	//加载资源文件
    	ginServer.Static("/static", "./static")
    
    	// 响应一个页面给前端
    	ginServer.GET("/index", func(context *gin.Context) {
    		// context.JSON() json数据
    		context.HTML(http.StatusOK, "index.html", gin.H{
    			"msg": "这是go后台传入的数据",
    		})
    	})
    
    	// 服务器端口
    	err := ginServer.Run(":8082")
    	if err != nil {
    		return
    	}
    }

  • <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>一个GoWeb页面</title>
        <link rel="stylesheet" href="/static/css/style.css">
        <script src="/static/js/common.js"></script>
    </head>
    <body>
        <h1>感谢大家支持江小年的博客</h1>
        获取后端的数据为:
        {{.msg}}
    </body>
    </html>

获取参数

获取请求参数

  • // usl?userid=XXX&username=jaingxionian
    // /user/info/1/jiangxiaonian

  • // main.go
    package main
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 创建一个服务
    	ginServer := gin.Default()
    	// ginServer.Use(favicon.New("./favicon.ico"))
    
    	// 加载静态页面
    	ginServer.LoadHTMLGlob("templates/*")
    	// ginServer.LoadHTMLFiles("templates/index.html")
    	// LoadHTMLGlob是全局加载Files是指定文件
    
    	//加载资源文件
    	ginServer.Static("/static", "./static")
    
    	// 响应一个页面给前端
    	ginServer.GET("/index", func(context *gin.Context) {
    		// context.JSON() json数据
    		context.HTML(http.StatusOK, "index.html", gin.H{
    			"msg": "这是go后台传入的数据",
    		})
    	})
    
    	// usl?userid=XXX&username=jaingxionian
    	ginServer.GET("/user/info", func(context *gin.Context) {
    		userid := context.Query("userid")
    		username := context.Query("username")
    		context.JSON(http.StatusOK, gin.H{
    			"userid":   userid,
    			"username": username,
    		})
    	})
    
    	// /user/info/1/jiangxiaonian
    	// 只要:后名字正确就能匹配上
    	ginServer.GET("/user/info/:userid/:username", func(context *gin.Context) {
    		userid := context.Param("userid")
    		username := context.Param("username")
    		context.JSON(http.StatusOK, gin.H{
    			"userid":   userid,
    			"username": username,
    		})
    	})
    
    	// 服务器端口
    	err := ginServer.Run(":8082")
    	if err != nil {
    		return
    	}
    }
    // 运行后访问 http://localhost:8082/user/info?userid=1&username=jaingxiaonain

获取前端给后端传递的json(序列化)参数

// gin 优化过的BindJSON
package controllers
​
import "github.com/gin-gonic/gin"
​
type OrderController struct{}
​
func (o OrderController) GetList(c *gin.Context) {
    m := make(map[string]interface{})
    err := c.BindJSON(&m)
    if err == nil {
        c.JSON(http.StatusOK, m)
        return
    }
    c.JSON(4001, gin.H{"err": err})
}
// 结构体
package controllers
​
import "github.com/gin-gonic/gin"
​
type OrderController struct{}
​
type Search struct {
    Name string `json:"name"`
    Cid  int    `json:"cid"`
}
​
func (o OrderController) GetList(c *gin.Context) {
    search := &Search{}
    err := c.BindJSON(&search)
    if err == nil {
        ReturnSuccess(c, 0, search.Name, search.Cid, 1)
        return
    }
    ReturnErrer(c, 4001, gin.H{"err": err})
}

// 结构体
package controllers
​
import "github.com/gin-gonic/gin"
​
type OrderController struct{}
​
type Search struct {
    Name string `json:"name"`
    Cid  int    `json:"cid"`
}
​
func (o OrderController) GetList(c *gin.Context) {
    search := &Search{}
    err := c.BindJSON(&search)
    if err == nil {
        ReturnSuccess(c, 0, search.Name, search.Cid, 1)
        return
    }
    ReturnErrer(c, 4001, gin.H{"err": err})
}

获取表单中的参数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>一个GoWeb页面</title>
    <link rel="stylesheet" href="/static/css/style.css">
    <script src="/static/js/common.js"></script>
</head>
<body>
    <h1>感谢大家支持江小年的博客</h1>
    <form action="/user/add" method="post">
        <p>username: <input type="text" name="username"></p>
        <p>password: <input type="password" name="password"></p>
        <button type="submit"> 提交 </button>
    </form>
</body>
</html>
// .DefaultPostForm()  .PostForm()
package main

import (
	"encoding/json"
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	// 创建一个服务
	ginServer := gin.Default()
	// ginServer.Use(favicon.New("./favicon.ico"))
	// 加载静态页面
	ginServer.LoadHTMLGlob("templates/*")
	// ginServer.LoadHTMLFiles("templates/index.html")
	// LoadHTMLGlob是全局加载Files是指定文件
	//加载资源文件
	ginServer.Static("/static", "./static")
	// 响应一个页面给前端
	ginServer.GET("/index", func(context *gin.Context) {
		// context.JSON() json数据
		context.HTML(http.StatusOK, "index.html", gin.H{
			"msg": "这是go后台传入的数据",
		})
	})

	// 表单
	ginServer.POST("/user/add", func(context *gin.Context) {
		username := context.PostForm("username")
		password := context.PostForm("password")
        // password := context.DefaultPostForm("password", 12345)第二个参数为默认值

		// 加判断逻辑代码

		context.JSON(http.StatusOK, gin.H{
			"msg":      "ok",
			"username": username,
			"password": password,
		})
	})

	// 服务器端口
	err := ginServer.Run(":8082")
	if err != nil {
		return
	}
}

路由

HTTP重定向

  • package main
    
    import (
    	"encoding/json"
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 创建一个服务
    	ginServer := gin.Default()
    	// 响应一个页面给前端
    	ginServer.GET("/index", func(context *gin.Context) {
    		// context.JSON() json数据
    		context.HTML(http.StatusOK, "index.html", gin.H{
    			"msg": "这是go后台传入的数据",
    		})
    	})
    
    	// 路由
    	ginServer.GET("/test", func(context *gin.Context) {
    		// 重定向    StatusMovedPermanently 301
    		context.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
    	})
    
    	// 服务器端口
    	err := ginServer.Run(":8082")
    	if err != nil {
    		return
    	}
    }

路由重定向

路由重定向,使用HandleContext

package main
​
import (
    "github.com/gin-gonic/gin"
    "net/http"
)
​
func main() {
    r := gin.Default()
    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"})
    })
    // Listen and serve on 0.0.0.0:8080
    err := r.Run(":8080")
    if err != nil {
        return
    }
}

404 NoRoute()

  • <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>404</title>
    </head>
    <body>
        
        <h1>江小年的404页面</h1>
        
    </body>
    </html>

  • package main
    
    import (
    	"encoding/json"
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	// 创建一个服务
    	ginServer := gin.Default()
    	// 路由
    	ginServer.GET("/test", func(context *gin.Context) {
    		// 重定向    StatusMovedPermanently 301
    		context.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
    	})
    
    	// 404 NoRoute
    	ginServer.NoRoute(func(context *gin.Context) {
    		context.HTML(http.StatusNotFound, "404.html", nil)
    	})
    
    	// 服务器端口
    	err := ginServer.Run(":8082")
    	if err != nil {
    		return
    	}
    }

路由组

package main

import (
	"encoding/json"
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	// 创建一个服务
	ginServer := gin.Default()
	// ginServer.Use(favicon.New("./favicon.ico"))

	// 加载静态页面
	ginServer.LoadHTMLGlob("templates/*")
	// ginServer.LoadHTMLFiles("templates/index.html")
	// LoadHTMLGlob是全局加载Files是指定文件

	//加载资源文件
	ginServer.Static("/static", "./static")

	// 响应一个页面给前端
	ginServer.GET("/index", func(context *gin.Context) {
		// context.JSON() json数据
		context.HTML(http.StatusOK, "index.html", gin.H{
			"msg": "这是go后台传入的数据",
		})
	})

	// usl?userid=XXX&username=jaingxionian
	ginServer.GET("/user/info", func(context *gin.Context) {
		userid := context.Query("userid")
		username := context.Query("username")
		context.JSON(http.StatusOK, gin.H{
			"userid":   userid,
			"username": username,
		})
	})

	// /user/info/1/jiangxiaonian
	// 只要:后名字正确就能匹配上
	ginServer.GET("/user/info/:userid/:username", func(context *gin.Context) {
		userid := context.Param("userid")
		username := context.Param("username")
		context.JSON(http.StatusOK, gin.H{
			"userid":   userid,
			"username": username,
		})
	})

	// 前段给后端传JSON
	ginServer.POST("/json", func(context *gin.Context) {
		// GetRawData() 从请求体(request.body)里获取对象
		b, _ := context.GetRawData()
		var m map[string]interface{}
		// 包装为json数据 []byte
		_ = json.Unmarshal(b, &m)
		context.JSON(http.StatusOK, m)
	})

	// 表单
	ginServer.POST("/user/add", func(context *gin.Context) {
		username := context.PostForm("username")
		password := context.PostForm("password")

		// 加判断逻辑代码

		context.JSON(http.StatusOK, gin.H{
			"msg":      "ok",
			"username": username,
			"password": password,
		})
	})

	// 路由
	ginServer.GET("/test", func(context *gin.Context) {
		// 重定向    StatusMovedPermanently 301
		context.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
	})

	// 404 NoRoute
	ginServer.NoRoute(func(context *gin.Context) {
		context.HTML(http.StatusNotFound, "404.html", nil)
	})

	// 路由组
	userGroup := ginServer.Group("/user")
	{
		userGroup.GET("/add")    // /user/add
		userGroup.GET("/login")  // /user/add
		userGroup.GET("/logout") // /user/add
	}

	orderGroup := ginServer.Group("/order")
	{
		orderGroup.GET("add")
		orderGroup.GET("delte")

	}

	// 服务器端口
	err := ginServer.Run(":8082")
	if err != nil {
		return
	}
}

路由嵌套

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) {...})
    }

中间件(Java中为拦截器)

package main

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/gin-gonic/gin"
)

// 自定义Go中间件 拦截器
func myHandler() gin.HandlerFunc {
	return func(context *gin.Context) {
		// Set一些值用作全局变量
		// 通过自定义的中间件,设置的值,在后续处理只要调用了这个中间件的都可以拿到这里的参数
		context.Set("usersession", "userid-1")
		context.Next() // 放形
		/* if XXX {
			context.Next() // 放形
		}
		context.Abort() // 阻止
		// 注册未指定就是全局使用
		*/
	}
	/* 46行加入中间件 */
}

func main() {
	// 创建一个服务
	ginServer := gin.Default()
	// ginServer.Use(favicon.New("./favicon.ico"))

	// 加载静态页面
	ginServer.LoadHTMLGlob("templates/*")
	// ginServer.LoadHTMLFiles("templates/index.html")
	// LoadHTMLGlob是全局加载Files是指定文件

	//加载资源文件
	ginServer.Static("/static", "./static")

	// 响应一个页面给前端
	ginServer.GET("/index", func(context *gin.Context) {
		// context.JSON() json数据
		context.HTML(http.StatusOK, "index.html", gin.H{
			"msg": "这是go后台传入的数据",
		})
	})

	// usl?userid=XXX&username=jaingxionian
	ginServer.GET("/user/info", myHandler(), func(context *gin.Context) {

		// 取出中间件中的值
		usersession := context.MustGet("usersession").(string)
		log.Println("========>", usersession) // 前端控制台输出

		userid := context.Query("userid")
		username := context.Query("username")
		context.JSON(http.StatusOK, gin.H{
			"userid":   userid,
			"username": username,
		})
	})

	// /user/info/1/jiangxiaonian
	// 只要:后名字正确就能匹配上
	ginServer.GET("/user/info/:userid/:username", func(context *gin.Context) {
		userid := context.Param("userid")
		username := context.Param("username")
		context.JSON(http.StatusOK, gin.H{
			"userid":   userid,
			"username": username,
		})
	})

	// 前段给后端传JSON
	ginServer.POST("/json", func(context *gin.Context) {
		// GetRawData() 从请求体(request.body)里获取对象
		b, _ := context.GetRawData()
		var m map[string]interface{}
		// 包装为json数据 []byte
		_ = json.Unmarshal(b, &m)
		context.JSON(http.StatusOK, m)
	})

	// 表单
	ginServer.POST("/user/add", func(context *gin.Context) {
		username := context.PostForm("username")
		password := context.PostForm("password")

		// 加判断逻辑代码

		context.JSON(http.StatusOK, gin.H{
			"msg":      "ok",
			"username": username,
			"password": password,
		})
	})

	// 路由
	ginServer.GET("/test", func(context *gin.Context) {
		// 重定向    StatusMovedPermanently 301
		context.Redirect(http.StatusMovedPermanently, "https://www.baidu.com")
	})

	// 404 NoRoute
	ginServer.NoRoute(func(context *gin.Context) {
		context.HTML(http.StatusNotFound, "404.html", nil)
	})

	// 路由组
	userGroup := ginServer.Group("/user")
	{
		userGroup.GET("/add")    // /user/add
		userGroup.GET("/login")  // /user/add
		userGroup.GET("/logout") // /user/add
	}

	orderGroup := ginServer.Group("/order")
	{
		orderGroup.GET("add")
		orderGroup.GET("delte")

	}

	// 服务器端口
	err := ginServer.Run(":8082")
	if err != nil {
		return
	}
}
// StatCost 是一个统计耗时请求耗时的中间件
func StatCost() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        c.Set("name", "wxy") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值
        // 调用该请求的剩余处理程序
        c.Next()
        // 不调用该请求的剩余处理程序
        // c.Abort()
        // 计算耗时
        cost := time.Since(start)
        log.Println(cost)
    }
}

文件上传

单个文件上传

文件上传前端页面代码:

<!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 main() {
    router := gin.Default()
    // 处理multipart forms提交文件时默认的内存限制是32 MiB
    // 可以通过下面的方式修改
    // router.MaxMultipartMemory = 8 << 20  // 8 MiB
    router.POST("/upload", func(c *gin.Context) {
        // 单个文件
        file, err := c.FormFile("f1")
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{
                "message": err.Error(),
            })
            return
        }
​
        log.Println(file.Filename)
        dst := fmt.Sprintf("C:/tmp/%s", file.Filename)
        // 上传文件到指定的目录
        c.SaveUploadedFile(file, dst)
        c.JSON(http.StatusOK, gin.H{
            "message": fmt.Sprintf("'%s' uploaded!", file.Filename),
        })
    })
    router.Run()
}

多个文件上传

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("./upload/%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()
}

异常捕获

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("./upload/%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()
}

日志打印

自己搞哟,很重要的,输出错误,前段是看不到的

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江小年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值