• Gin简单明了的教程---上



    Gin官网


    Gin 环境搭建

    1.下载并安装 gin:

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

    注意: 如果直接从github拉取失败,可以尝试更换代理,重新设置GOPROXY为国内代理源,然后再次尝试

    go env -w GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy,https://goproxy.io,direct
    
    • 1

    2.将 gin 引入到代码中:

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

    3.测试

    package main
    
    import "github.com/gin-gonic/gin"
    
    func main() {
    	//创建一个默认的路由引擎
    	router := gin.Default()
    	//配置路由
    	router.GET("/", func(c *gin.Context) {
    		//返回JSON数据
    		c.JSON(200, gin.H{
    			"status": 200,
    			"data":   "SUCCESS",
    		})
    	})
    	//启动HTTP服务,默认8080端口
    	router.Run()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    	//改变默认启动端口--如果是localhost可以省略
    	router.Run(":8000")
    
    • 1
    • 2

    golang 程序的热加载

    热加载就是当我们对代码进行修改时,程序能够自动重新加载并执行,这在我们开发中 是非常便利的,可以快速进行代码测试,省去了每次手动重新编译。

    beego 中我们可以使用官方给我们提供的 bee 工具来热加载项目,但是 gin 中并没有官方提 供的热加载工具,这个时候我们要实现热加载就可以借助第三方的工具。

    go get github.com/pilu/fresh 
    D:\gin_demo>fresh
    
    • 1
    • 2

    先查看GOPATH下bin目录下有无fresh.exe,没有的话,采用下面方式进行安装和下载:

    git clone https://github.com/gravityblast/fresh.git
    go install github.com/pilu/fresh@latest
    
    • 1
    • 2

    在这里插入图片描述

    • 如果是linux系统,出现命令找不到的情况,需要设置软链接或者将对应可执行程序路径加入环境变量。
    • 如果是win系统,也是同理,加入环境变量。

    在对应的项目文件下,打开命令行,执行fresh命令,会自动去寻找项目文件下的main文件,然后启动程序,然后一直监控当前目录下的文件是否被修改,如果是的话,就重启项目。
    在这里插入图片描述

    GoLand只有在电脑启动的时候才会去读取环境变量,因此如果不重启电脑,那么GoLand终端使用fresh命令,会报错


    go get github.com/codegangsta/gin
    gin run main.go
    
    • 1
    • 2

    Gin 框架中的路由

    看例子学习:

    package main
    
    import "github.com/gin-gonic/gin"
    
    func main() {
    	//创建一个默认的路由引擎
    	router := gin.Default()
    	//配置路由--支持RestFul API
    
    	//增
    	router.POST("/", func(c *gin.Context) {
    	    //?name=dhy&age=18
    		name := c.Query("name")
    		age := c.Query("age")
    		//H类型为: map[string]interface{} 等同于Java中的Map
    		c.JSON(200, gin.H{
    			"name": name,
    			"age":  age,
    		})
    	})
    
    	//删
    	router.DELETE("/", func(c *gin.Context) {
    		c.String(200, "delete")
    	})
    
    	//改
    	router.PUT("/", func(c *gin.Context) {
    		c.String(200, "put")
    	})
    
    	//查
    	router.GET("/", func(c *gin.Context) {
    		c.String(200, "this is Get query!")
    	})
    
    	//改变默认启动端口
    	router.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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    动态路由

    	//查
    	router.GET("/:id", func(c *gin.Context) {
    		id := c.Param("id")
    		//可以格式化字符串
    		c.String(200, "get id= %v", id)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    响应结果

    返回一个字符串

    	//查
    	router.GET("/", func(c *gin.Context) {
    		id := c.Query("id")
    		//可以格式化字符串
    		c.String(200, "get id= %v", id)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    返回一个 JSON 数据

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func main() {
    	//创建一个默认的路由引擎
    	r := gin.Default()
    
    	r.GET("/json", func(c *gin.Context) {
    		aid := c.Query("aid")
    		// 方式一:自己拼接 JSON
    		c.JSON(http.StatusOK, gin.H{
    			"msg": aid,
    		})
    	})
    
    	r.GET("/structJson", func(c *gin.Context) {
    		// 结构体方式
    		//通过json备注,可以指定key名
    		//未导出的字段不会被序列化(小写属性名)
    		var msg struct {
    			Username string
    			Msg      string `json:"msg"`
    			Age      string `json:"age"`
    		}
    		msg.Username = "name1"
    		msg.Msg = "msg1"
    		msg.Age = "18"
    		c.JSON(200, msg)
    	})
    
    	//改变默认启动端口
    	r.Run(":5200")
    }
    
    • 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

    对于JSON序列化而言,在go语言中会忽略小写的属性名,并且默认key都是属性名大写的,可以通过在结构体属性名后面添加备注,指定显示的key名:
    在这里插入图片描述


    返回JSONP

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func main() {
    	//创建一个默认的路由引擎
    	r := gin.Default()
    
    	r.GET("/JSONP", func(c *gin.Context) {
    		data := map[string]interface{}{
    			"foo": "bar",
    		}
    		// /JSONP?callback=x
    		// 将输出:x({\"foo\":\"bar\"})
    		c.JSONP(http.StatusOK, data)
    	})
    
    	//改变默认启动端口
    	r.Run(":5200")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    JSONP跨域主要用于跨域解决,具体可参考下面这篇文章:

    Golang Gin 实战(九)| JSONP跨域和劫持


    渲染文件

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	//创建一个默认的路由引擎
    	r := gin.Default()
    
    	r.GET("/", func(c *gin.Context) {
    		//直接将文件内容写回显示在浏览器上
    		c.File("main.go")
    		//将文件以附件形式进行下载,参数是是文件路径,参数二是下载时显示的文件名
    		c.FileAttachment("main.go", "神秘文件.txt")
    	})
    
    	//改变默认启动端口
    	r.Run(":5200")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    渲染html模板

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    func main() {
    	//创建一个默认的路由引擎
    	r := gin.Default()
        //需要先加载模板文件
    	r.LoadHTMLGlob("templates/*")
    
    	r.GET("/", func(c *gin.Context) {
    		//渲染,然后响应渲染后的模板文件
    		c.HTML(
    			http.StatusOK, "index.html",
    			map[string]interface{}{"title": "前台首页"})
    	})
    
    	//改变默认启动端口
    	r.Run(":5200")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>indextitle>
    head>
    <body>
     {{.title}}
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述


    Gin HTML 模板渲染

    最简单的步骤就两步:

    • 加载模板文件
    • 渲染时传入模型数据,将最终渲染结果响应到浏览器
    	//创建一个默认的路由引擎
    	r := gin.Default()
    	//template目录下面所有文件都是模板文件
    	r.LoadHTMLGlob("templates/*")
    
    	r.GET("/", func(c *gin.Context) {
    		//渲染,然后响应渲染后的模板文件
    		c.HTML(
    			http.StatusOK, 
                //去template目录下寻找index.html模板文件
                "index.html",
    			//模型数据
    			map[string]interface{}{"title": "前台首页"})
    	})
    
    	//改变默认启动端口
    	r.Run(":5200")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    关于模板文件中的相关语法和使用,这里不展开了,如果有做单体应用需要用到模板文件支持的,可以自行查阅相关资料。


    静态文件服务

    当我们渲染的 HTML 文件中引用了静态文件时,我们需要配置静态 web 服务 r.Static(“/static”, “./static”) 前面的/static 表示路由 后面的./static 表示路径

    	r := gin.Default()
    	//将请求映射到一个静态资源目录下
    	r.Static("/static", "./static")
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    在这里插入图片描述


    路由详解

    Get 请求传值

    GET /user?uid=20&page=1

    	r.GET("/user", func(c *gin.Context) { 
    		uid := c.Query("uid")
    		//如果请求参数中没有携带page参数,则返回默认值
    		page := c.DefaultQuery("page", "0") 
    		c.String(200, "uid=%v page=%v", uid, page)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    动态路由传值

    get /user/20

    	r.GET("/user/:id", func(c *gin.Context) {
    		id := c.Param("id")
    		c.JSON(200, gin.H{
    			"news": id, //id 20
    		})
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Post 请求传值 获取 form 表单数据

    • 通过 c.PostForm 接收表单传过来的数据
    	r.POST("/doAddUser", func(c *gin.Context) {
    		username := c.PostForm("username")
    		password := c.PostForm("password")
    		age := c.DefaultPostForm("age", "20")
    		c.JSON(200, gin.H{
    			"usernmae": username, "password": password, "age": age,
    		})
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • postman进行数据提交

    在这里插入图片描述


    Get 传值绑定到结构体

    /?username=zhangsan&password=123456

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    //注意首字母大写,以及暴露给表单和json时的属性名
    type Userinfo struct {
    	Username string `form:"username" json:"user"`
    	Password string `form:"password" json:"pwd"`
    }
    
    func main() {
    	// 创建一个默认的路由引擎
    	r := gin.Default()
    	// 配置路由
    	r.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()})
    		}
    	})
    	r.Run()
    }
    
    • 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

    在这里插入图片描述


    Post 传值绑定到结构体

    	r.POST("/", 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

    和get数据绑定一样。


    Xml数据绑定

    如果请求提交的是xml形式的数据,该怎么完成数据绑定呢?

    	type Article struct {
    		Title   string `json:"title" xml:"title"`
    		Content string `json:"content" xml:"content"`
    	}
    
    	r.POST("/xml", func(ctx *gin.Context) {
    		var article Article
    		if err := ctx.ShouldBindXML(&article); err == nil {
    			ctx.JSON(http.StatusOK, article)
    		}else {
    			ctx.JSON(http.StatusBadRequest, gin.H {
    				"err": err.Error()})
    		}
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    关于xml数据绑定,还有一种原始方式,如下:

    	r.POST("/xml", func(ctx *gin.Context) {
    		//获取请求体中原始的字节流
    		data, _ := ctx.GetRawData()
    		var article Article
    		 //使用go官方提供的xml反序列化方式
    		if err := xml.Unmarshal(data, &article); err == nil {
    			ctx.JSON(http.StatusOK, article)
    		} else {
    			ctx.JSON(http.StatusBadRequest, gin.H{
    				"err": err.Error()})
    		}
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    还有JSON数据绑定,YML数据绑定等,都是一样的套路,这里不多展开,大家自行探索


    路由分组

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	r := gin.Default()
    
    	userRouter := r.Group("/user")
    	{
    		userRouter.GET("/id", func(ctx *gin.Context) {
    			ctx.String(200, "getUserById")
    		})
    
    		userRouter.POST("/", func(ctx *gin.Context) {
    			ctx.String(200, "post one user")
    		})
    	}
    
    	adminRouter := r.Group("/admin")
    	{
    		adminRouter.GET("/id", func(ctx *gin.Context) {
    			ctx.String(200, "getAdminById")
    		})
    
    		adminRouter.POST("/", func(ctx *gin.Context) {
    			ctx.String(200, "post one admin")
    		})
    	}
    
    	r.Run()
    }
    
    • 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

    这里的路由分组和java中spring框架在controller类上面标注@RequestMapping注解的请求域隔离功能类似


    路由分离

    如何将不同的路由放入不同的文件进行管理,就像spring不同的请求域由不同的controller处理类似。

    • 在项目新建文件夹router,然后在router目录下创建userRouter.go 和adminRouter.go,内容如下:
    package router
    
    import "github.com/gin-gonic/gin"
    
    func UserRouter(r *gin.Engine) {
    	userRouter := r.Group("/user")
    	{
    		userRouter.GET("/id", func(ctx *gin.Context) {
    			ctx.String(200, "getUserById")
    		})
    
    		userRouter.POST("/", func(ctx *gin.Context) {
    			ctx.String(200, "post one user")
    		})
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    package router
    
    import "github.com/gin-gonic/gin"
    
    func AdminRouter(r *gin.Engine) {
    	adminRouter := r.Group("/admin")
    	{
    		adminRouter.GET("/id", func(ctx *gin.Context) {
    			ctx.String(200, "getAdminById")
    		})
    
    		adminRouter.POST("/", func(ctx *gin.Context) {
    			ctx.String(200, "post one admin")
    		})
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在main.go中引入路由模块

    package main
    
    import (
    	"socket/router"
    
    	"github.com/gin-gonic/gin"
    )
    func main() {
    	// 创建一个默认的路由引擎
    	r := gin.Default()
    	// 引入路由模块
    	router.AdminRouter(r)
    	router.ApiRouter(r)
    	// 启动 HTTP 服务,默认在 0.0.0.0:8080 启动服务
    	r.Run()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Gin 中自定义控制器

    控制器分组

    当我们的项目比较大的时候有必要对我们的控制器进行分组 , 业务逻辑放在控制器中

    在项目文件夹下面新建controller文件夹,创建userController.go

    package controller
    
    import "github.com/gin-gonic/gin"
    
    func UserGet(c *gin.Context) {
    	c.String(200, "get user")
    }
    
    func UserPost(c *gin.Context) {
    	c.String(200, "post user")
    }
    
    func UserPut(c *gin.Context) {
    	c.String(200, "put user")
    }
    
    func UserDelete(c *gin.Context) {
    	c.String(200, "delete user")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在UserRouter.go中调用userController.go 的函数

    package router
    
    import (
    	"GinStudy/controller"
    	"github.com/gin-gonic/gin"
    )
    
    func UserRouter(r *gin.Engine) {
    	userRouter := r.Group("/user")
    	{
    		userRouter.GET("/", controller.UserGet)
    		userRouter.POST("/", controller.UserPost)
    		userRouter.DELETE("/", controller.UserDelete)
    		userRouter.PUT("/", controller.UserPut)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    为了使方法能够继承,我们修改userController.go 内容

    package controller
    
    import "github.com/gin-gonic/gin"
    
    type UserController struct {
    
    }
    
    func (u *UserController) UserGet(c *gin.Context) {
    	c.String(200, "get user")
    }
    
    func  (u *UserController) UserPost(c *gin.Context) {
    	c.String(200, "post user")
    }
    
    func  (u *UserController) UserPut(c *gin.Context) {
    	c.String(200, "put user")
    }
    
    func  (u *UserController) UserDelete(c *gin.Context) {
    	c.String(200, "delete user")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    继续修改UserRouter.go

    package router
    
    import (
    	"GinStudy/controller"
    	"github.com/gin-gonic/gin"
    )
    
    func UserRouter(r *gin.Engine) {
    	userRouter := r.Group("/user")
    	{
    		u := new(controller.UserController)
    		userRouter.GET("/", u.UserGet)
    		userRouter.POST("/", u.UserPost)
    		userRouter.DELETE("/", u.UserDelete)
    		userRouter.PUT("/", u.UserPut)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    控制器的继承

    在controller目录下新建baseController.go,内容如下:

    package controller
    
    import "github.com/gin-gonic/gin"
    
    type BaseController struct{}
    
    func (con BaseController) success(c *gin.Context) {
    	c.String(200, "success")
    }
    
    func (con BaseController) error(c *gin.Context) {
    	c.String(200, "failed")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    继续修改userController.go

    package controller
    
    import "github.com/gin-gonic/gin"
    
    type UserController struct {
    	// 继承BaseController
    	BaseController
    }
    
    func (u *UserController) UserGet(c *gin.Context) {
    	c.String(200, "get user")
    }
    
    func (u *UserController) UserPost(c *gin.Context) {
    	c.String(200, "post user")
    }
    
    func (u *UserController) UserPut(c *gin.Context) {
    	c.String(200, "put user")
    }
    
    func (u *UserController) UserDelete(c *gin.Context) {
    	c.String(200, "delete user")
    }
    
    
    • 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

  • 相关阅读:
    在物理机内的虚机创建进入容器,执行命令时提示权限不够
    MySQL安装及初始密码设置
    【VUE3】保姆级基础讲解(一):初体验与指令
    js 图片路径转换base64格式
    【大数据入门核心技术-Hive】MySQL5.7安装
    【OpenAI Triton】理解矩阵乘法中的super-grouping 21a649eddf854db5ad4c7753afb7cb72
    数据结构系列学习(五) - 双向链表(Double_Linked_List)
    react create-react-app 配置less
    ​JAVA设计模式(十)——装饰模式
    闪烁霓虹灯文字动画
  • 原文地址:https://blog.csdn.net/m0_53157173/article/details/126439353