• 1.go web之gin框架


    Gin框架

    一、准备

    1.下载依赖

     go get -u github.com/gin-gonic/gin
    
    • 1

    2.引入依赖

    import "github.com/gin-gonic/gin"
    
    • 1

    3. (可选)如果使用诸如 http.StatusOK 之类的常量,则需要引入 net/http 包

    import "net/http"
    
    • 1

    二、基本使用

    1. 配置路由

    package main
    
    import "github.com/gin-gonic/gin"
    
    func main() {
    	// 创建一个默认的路由引擎
    	r := gin.Default()
    	// 配置路由
    	r.GET("/getInfo", func(c *gin.Context) {
    		c.JSON(200, gin.H{
    			"msg": "成功",
    		})
    	})
    	//启动 HTTP 服务,在8088端口监听
    	r.Run(":8088")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    三、Gin中的路由

    1.路由概述

    在 RESTful 架构中,每个网址代表一种资源,不同的请求方式表示执行不同的操作:

    请求方式一般对应操作
    GET(SELECT)从服务器取出资源(一项或多项)
    POST(CREATE))在服务器新建一个资源
    PUT(UPDATE)在服务器更新资源(客户端提供改变后的完整资源)
    DELETE(DELETE))从服务器删除资源

    2.简单路由

    GET请求
    r.GET("网址", func(c *gin.Context) {
    c.String(200, "Get")
    })
    
    • 1
    • 2
    • 3
    POST请求
    r.POST("网址", func(c *gin.Context) {
    c.String(200, "POST")
    })
    
    • 1
    • 2
    • 3
    PUT请求
    r.PUT("网址", func(c *gin.Context) {
    c.String(200, "PUT")
    })
    
    • 1
    • 2
    • 3
    DELETE请求
    r.DELETE("网址", func(c *gin.Context) {
    c.String(200, "DELETE")
    })
    
    • 1
    • 2
    • 3
    动态路由
    	r.GET("/getUser/:id", func(c *gin.Context) {
    		id := c.Param("id")
    		c.JSON(200, gin.H{
    			"id":  id,
    			"msg": "成功",
    		})
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    四、 响应格式

    这里主要介绍使用比较多的字符串格式和json格式

    c.String()

    	r.GET("/getStr", func(c *gin.Context) {
    		c.String(200, "成功")
    
    	})
    
    • 1
    • 2
    • 3
    • 4

    响应结果为字符串
    在这里插入图片描述

    c.JSON()

    	r.GET("/getInfo", func(c *gin.Context) {
    		c.JSON(200, gin.H{
    			"msg": "成功",
    		})
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5

    响应结果为json格式
    在这里插入图片描述

    五、路由传参

    1.GET请求传值

    请求路径: /user?uid=20&page=1

    后端接收

    router.GET("/user", func(c *gin.Context) {
    //c.Query()接收请求GET请求路径参数
    uid := c.Query("uid")
    //c.DefaultQuery()接收请求GET请求路径参数,接收不到时,采用默认参数
    page := c.DefaultQuery("page", "0")
    c.String(200, "uid=%v page=%v", uid, page)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.Post 请求传值(获取 form 表单)

    请求路径:

    DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    head>
    <body>
    <form action="/doAddUser" method="post">
    用户名:<input type="text" name="username" />
    密码: <input type="password" name="password" />
    <input type="submit" value="提交">
    form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    后端接收

    router.POST("/doAddUser", func(c *gin.Context) {
    //c.PostForm()接收form表单数据,key要与form表单name属性对应
    username := c.PostForm("username")
    password := c.PostForm("password")
    //c.PostForm()接收form表单数据,接收不到采用默认值,key要与form表单name属性对应
    age := c.DefaultPostForm("age", "20")
    c.JSON(200, gin.H{ "usernmae": username, "password": password, "age": age, })
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.动态路由传值

    请求路径:/user/20

    后端接收

    r.GET("/user/:uid", func(c *gin.Context) {
    //c.Param()接收动态路由参数
    uid := c.Param("uid")
    c.String(200, "userID=%s", uid)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.GET,POST 传递的结构体数据

    Get 传值绑定到结构体

    请求路径: /?username=zhangsan&password=123456

    后端接收

    //注意首字母大写
    type Userinfo struct {
    Username string `form:"username" json:"user"`
    Password string `form:"password" json:"password"` }
    
    
    router.GET("/", func(c *gin.Context) {
    var userinfo Userinfo
    if err := c.ShouldBind(&userinfo); err == nil {
    c.JSON(http.StatusOK, userinfo)
    } else {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    Post 传值绑定到结构体

    请求路径:
    在这里插入图片描述

    后端接收

    router.POST("/doLogin", func(c *gin.Context) {
    var userinfo Userinfo
    if err := c.ShouldBind(&userinfo); err == nil {
    c.JSON(http.StatusOK, userinfo)
    } else {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    .ShouldBind()能够基于请求自动提
    取 JSON、form 表单和 QueryString 类型的数据,并把值绑定到指定的结构体对象

    六、路由组

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

    七、Gin路由文件分组

    新建 routes 文件夹,routes 文件下面新建 adminRoutes.goapiRoutes.go、defaultRoutes.go

    新建adminRoutes

    package routes
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func AdminRoutesInit(router *gin.Engine) {
    	adminRouter := router.Group("/admin")
    	{
    		adminRouter.GET("/user", func(c *gin.Context) {
    			c.String(http.StatusOK, "用户")
    		})
    		adminRouter.GET("/news", func(c *gin.Context) {
    			c.String(http.StatusOK, "news")
    		})
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    新建apiRoutes.go

    package routes
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    func ApiRoutesInit(router *gin.Engine) {
    	apiRoute := router.Group("/api")
    	{
    		apiRoute.GET("/user", func(c *gin.Context) {
    			c.JSON(http.StatusOK, gin.H{"username": "张三",
    				"age": 20})
    		})
    		apiRoute.GET("/news", func(c *gin.Context) {
    			c.JSON(http.StatusOK, gin.H{"title": "这是新闻"})
    		})
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    新建defaultRoutes.go

    package routes
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    func DefaultRoutesInit(router *gin.Engine) {
    	defaultRoute := router.Group("/")
    	{
    		defaultRoute.GET("/", func(c *gin.Context) {
    			c.String(200, "首页")
    		})
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    配置main.go

    package main
    
    import (
    	"gin_demo/routes"
    	"github.com/gin-gonic/gin"
    
    //注意首字母大写
    type Userinfo struct {
    	Username string `form:"username" json:"user"`
    	Password string `form:"password" json:"password"`
    }
    
    func main() {
    	r := gin.Default()
    	routes.AdminRoutesInit(r)
    	routes.ApiRoutesInit(r)
    	routes.DefaultRoutesInit(r)
    	r.Run(":8080")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    八、Gin中自定义控制器

    控制器分组

    1.新建controller/admin/NewsController.go
    package admin
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    type NewsController struct {
    }
    
    func (c NewsController) Index(ctx *gin.Context) {
    	ctx.String(http.StatusOK, "新闻首页")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    2.新建 controller/admin/UserController.go
    package admin
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    )
    
    type UserController struct {
    }
    
    func (c UserController) Index(ctx *gin.Context) {
    	ctx.String(http.StatusOK, "这是用户首页")
    }
    func (c UserController) Add(ctx *gin.Context) {
    	ctx.String(http.StatusOK, "增加用户")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    3.在路由文件分组中配置控制器(将处理中间件改为控制器的方法)
    package routes
    
    import (
    	"gin_demo/controller/admin"
    
    	"github.com/gin-gonic/gin"
    )
    
    func AdminRoutesInit(router *gin.Engine) {
    	adminRouter := router.Group("/admin")
    	{
    		adminRouter.GET("/user", admin.UserController{}.Index)
    		adminRouter.GET("/user/add", admin.UserController{}.Add)
    		adminRouter.GET("/news", admin.NewsController{}.Add)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    九、路由中间件

    通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作

    Gin 中的中间件必须是一个 gin.HandlerFunc 类型,配置路由的时候可以传递多个 func 回调函
    数,最后一个 func 回调函数前面触发的方法都可以称为中间件。

    1.路由中间件基本使用

    package main
    
    import (
    	"fmt"
    
    	"github.com/gin-gonic/gin"
    )
    
    func initMiddleware(ctx *gin.Context) {
    	fmt.Println("我是一个中间件")
    }
    func main() {
    	r := gin.Default()
    	r.GET("/", initMiddleware, func(ctx *gin.Context) {
    		ctx.String(200, "首页--中间件演示")
    	})
    	r.GET("/news", initMiddleware, func(ctx *gin.Context) {
    		ctx.String(200, "新闻页面--中间件演示")
    	})
    	r.Run(":8080")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.ctx.Next()调用该请求的剩余处理程序

    中间件里面加上 ctx.Next()可以让我们在路由匹配完成后执行一些操作
    比如我们统计一个请求的执行时间。

    package main
    
    import (
    	"fmt"
    	"time"
    
    	"github.com/gin-gonic/gin"
    )
    
    func initMiddleware(ctx *gin.Context) {
    	fmt.Println("1-执行中中间件")
    	start := time.Now().UnixNano()
    	// 调用该请求的剩余处理程序
    	ctx.Next()
    	fmt.Println("3-程序执行完成 计算时间")
    	// 计算耗时 Go 语言中的 Since()函数保留时间值,并用于评估与实际时间的差异
    	end := time.Now().UnixNano()
    	fmt.Println(end - start)
    }
    func main() {
    	r := gin.Default()
    	r.GET("/", initMiddleware, func(ctx *gin.Context) {
    		fmt.Println("2-执行首页返回数据")
    		ctx.String(200, "首页--中间件演示")
    	})
    	r.GET("/news", initMiddleware, func(ctx *gin.Context) {
    		ctx.String(200, "新闻页面--中间件演示")
    	})
    	r.Run(":8080")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    3.全局中间件

    package main
    
    import (
    	"fmt"
    
    	"github.com/gin-gonic/gin"
    )
    
    func initMiddleware(ctx *gin.Context) {
    	fmt.Println("全局中间件 通过 r.Use 配置")
    	// 调用该请求的剩余处理程序
    	ctx.Next()
    }
    func main() {
    	r := gin.Default()
    	//注册全局中间件
    	r.Use(initMiddleware)
    	r.GET("/", func(ctx *gin.Context) {
    		ctx.String(200, "首页--中间件演示")
    	})
    	r.GET("/news", func(ctx *gin.Context) {
    		ctx.String(200, "新闻页面--中间件演示")
    	})
    	r.Run(":8080")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    4.在路由分组中配置中间件

    写法一:

    shopGroup := r.Group("/shop", StatCost())
    {
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ... }
    
    • 1
    • 2
    • 3
    • 4

    写法二:

    shopGroup := r.Group("/shop")
    shopGroup.Use(StatCost())
    {
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ... }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    十、中间件和对应控制器之间共享数据

    1.设置值

    func InitAdminMiddleware(ctx *gin.Context) {
    	// 可以通过 ctx.Set 在请求上下文中设置值,后续的处理函数能够取到该值
    	ctx.Set("username", "张三")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.获取值

    func (c UserController) Index(ctx *gin.Context) {
    	username, _ := ctx.Get("username")
    }
    
    • 1
    • 2
    • 3

    十一、中间件注意事项

    gin 默认中间件
    gin.Default()默认使用了 Logger 和 Recovery 中间件,其中:
    • Logger 中间件将日志写入 gin.DefaultWriter,即使配置了 GIN_MODE=release。
    • Recovery 中间件会 recover 任何 panic。如果有 panic 的话,会写入 500 响应码。
    如果不想使用上面两个默认的中间件,可以使用 **gin.New()**新建一个没有任何默认中间件的路由

    gin 中间件中使用 goroutine
    当在中间件或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context),
    必须使用其只读副本(c.Copy())

    r.GET("/", func(c *gin.Context) {
    	//拷贝副本
    	cCp := c.Copy()
    	go func() {
    	// simulate a long task with time.Sleep(). 5 seconds
    	time.Sleep(5 * time.Second)
    	// 这里使用你创建的副本
    	fmt.Println("Done! in path " + cCp.Request.URL.Path)
    	}()
    	c.String(200, "首页")
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    十二、Gin中的Cookie

    设置cookie

    c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)
    
    • 1

    获取cookie

    cookie, err := c.Cookie("name")
    
    • 1

    完整demo

    package main
    
    import (
    	"gin_demo/models"
    	"github.com/gin-gonic/gin"
    	"html/template"
    )
    
    func main() {
    	r := gin.Default()
    	r.SetFuncMap(template.FuncMap{"unixToDate": models.UnixToDate})
    	r.GET("/", func(c *gin.Context) {
    		//设置cookie
    		c.SetCookie("usrename", "张三", 3600, "/", "localhost", false, true)
    		c.String(200, "首页")
    	})
    	r.GET("/user", func(c *gin.Context) {
    		//获取cookie
    		username, _ := c.Cookie("usrename")
    		c.String(200, "用户-"+username)
    	})
    	r.Run(":8080")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    十三、Gin中的Session

    Gin 官方没有给我们提供 Session 相关的文档,这个时候我们可以使用第三方的 Session 中间件来实现
    session

    gin-contrib/sessions 中间件支持的存储引擎:
    • cookie
    • memstore
    • redis
    • memcached
    • mongodb

    1.安装session包

    go get github.com/gin-contrib/sessions
    
    • 1

    2.基本session用法

    package main
    
    import (
    	"github.com/gin-contrib/sessions"
    	"github.com/gin-contrib/sessions/cookie"
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	r := gin.Default()
    	// 1.创建基于 cookie 的存储引擎,secret11111 参数是用于加密的秘钥
    	store := cookie.NewStore([]byte("secret11111"))
    	// 设置 session 中间件,参数 mysession,指的是 session 的名字,也是 cookie 的名字
    	// 2.store 是前面创建的存储引擎,我们可以替换成其他存储引擎
    	r.Use(sessions.Sessions("mysession", store))
    	r.GET("/", func(c *gin.Context) {
    		//初始化 session 对象
    		session := sessions.Default(c)
    		//设置过期时间
    		session.Options(sessions.Options{
    			MaxAge: 3600 * 6, // 6hrs
    		})
    		//设置 Session
    		session.Set("username", "张三")
    		session.Save()
    		c.JSON(200, gin.H{"msg": session.Get("username")})
    	})
    	r.GET("/user", func(c *gin.Context) {
    		// 初始化 session 对象
    		session := sessions.Default(c)
    		// 通过 session.Get 读取 session 值
    		username := session.Get("username")
    		c.JSON(200, gin.H{"username": username})
    	})
    	r.Run(":8000")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
  • 相关阅读:
    python+django大学生心理素质测评及咨询平台
    Anaconda3 spyder无法打开问题解决实录
    [附源码]JAVA毕业设计课程答疑系统(系统+LW)
    在vscode中使用Latex:TexLive2023
    DM 的任务前置检查功能
    [SLAM] IMU预积分推导
    Unity的WebGL平台动态加载glb/gltf测试
    C语言中 -> 和 . 的区别
    matlab——simulink学习(四)
    从简单到复杂,MVI 架构定义与封装使用总结
  • 原文地址:https://blog.csdn.net/qq_64403619/article/details/133722751