介绍

01【Gin框架】Gin环境搭建 Gin程序的热加载 Gin路由 GET POST PUT DELETE | 55 Gin是一个Golang编写的轻量级http web框架,运行速度非常快,如果你是性能和搞笑的追求者,我们推荐你使用Gin框架。 Gin最擅长的就是Api接口的高并发,如果项目的规模不大,业务相对简单,这个时候我们也推荐您使用Gin。 https://gin-gonic.com/zh-cn https://github.com/gin-gonic/gin

Gin环境

01【Gin框架】Gin环境搭建 Gin程序的热加载 Gin路由 GET POST PUT DELETE | 05:59

package main
 
import (
	"github.com/gin-gonic/gin" // 引入gin
	"net/http"
) 
 
func main() {
 
	r := gin.Default() // 创建默认路由引擎
	// GET /test
	r.GET("/test", func(context *gin.Context) {
		context.String(http.StatusOK, "测试")
	})
 
	r.Run(":8000") // 启动一个web服务,监听8000端口
}

默认路由

	r.GET("/", func(context *gin.Context) {
		context.String(http.StatusOK, "首页")
	})

返回JSON数据

02 【Gin框架】Gin路由中响应数据 c.String() c.JSON() c.JSONP() c.XML() c.HTML() | 04:25

// 返回json数据
	r.GET("/json", func(context *gin.Context) {
		context.JSON(http.StatusOK, map[string]interface{}{
			"success": true,
			"msg":     "你好",
		})
	})
 
	// 返回json数据
	r.GET("/json2", func(context *gin.Context) {
		context.JSON(http.StatusOK, gin.H{
			"success": true,
			"msg":     "你好",
		})
	})

使用结构体

02 【Gin框架】Gin路由中响应数据 c.String() c.JSON() c.JSONP() c.XML() c.HTML() | 07:21

type Article struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}
 
func main() {
 
	r := gin.Default()
 
	a := Article{
		Name: "张三",
		Age:  18,
	}
 
	// 返回json数据
	r.GET("/json", func(context *gin.Context) {
		context.JSON(http.StatusOK, a)
	})
}

JSONP

02 【Gin框架】Gin路由中响应数据 c.String() c.JSON() c.JSONP() c.XML() c.HTML() | 10:38 jsonp主要用来解决跨域问题,url后加?callback=xxx,可以处理回调函数

	r.GET("/jsonp", func(context *gin.Context) {
		context.JSONP(http.StatusOK, Article{
			Name: "张三",
			Age:  20,
		})
	})

XML数据

02 【Gin框架】Gin路由中响应数据 c.String() c.JSON() c.JSONP() c.XML() c.HTML() | 13:17

r.GET("/xml", func(context *gin.Context) {
		context.XML(http.StatusOK, Article{
			Name: "张三",
			Age:  20,
		})
	})

渲染模板

02 【Gin框架】Gin路由中响应数据 c.String() c.JSON() c.JSONP() c.XML() c.HTML() | 15:38 模板(template/goods.html) 使用{{.xxx}}获取数据变量 头尾增加:{{ define "default/index.html" }}{{ end }} 赋予模板自定义名称

{{ define "default/index.html" }}
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>商品页面</title>
</head>
<body>
<h2>{{.title}}</h2>
</body>
</html>
{{ end }}

go代码: 使用r.LoadHTMLGlob("template/*")加载静态资源 /**/**/* 表示多层

	r := gin.Default()
	r.LoadHTMLGlob("template/*") // 加载静态资源 /**/**/* 表示多层
 
	r.GET("/goods", func(context *gin.Context) {
		context.HTML(http.StatusOK, "default/index.html", gin.H{ //default/index.html html{{define}}中配置的模板名称
			"title": "我是后台数据",
		})
	})
 
	r.Run(":8000") // 启动一个web服务

模板语法

变量

03【Gin框架】Gin HTML模板渲染以及模板语法 (上) | 14:49 在模板中把数据赋值给变量

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>商品页面</title>
</head>
<body>
{{$t := .title}} //定义变量
<h2>{{$t}}</h2>// 使用变量
</body>
</html>
条件判断、比较函数

03【Gin框架】Gin HTML模板渲染以及模板语法 (上) | 16:38

条件解释
eq如果 arg1 == arg2 则返回真
ne如果 arg1 != arg2 则返回真
lt如果 arg1 < arg2 则返回真
le如果 arg1 arg2 则返回真
gt如果 arg1 > arg2 则返回真
ge如果 arg1 >= arg2 则返回真
{{if ge .a 60}}
<p>及格</p>
{{else if ge .a 90}}
<p>优秀</p>
{{else}}
<p>不及格</p>
循环range

03【Gin框架】Gin HTML模板渲染以及模板语法 (上) | 21:23

{{range $key,$value := .xList}}
<li>{{$key}}=={{$value}}</li>
{{range}}
Width赋值结构体

03【Gin框架】Gin HTML模板渲染以及模板语法 (上) | 27:19

{{with .object}}
	{{.name}}
	{{.age}}
{{end}}
预设函数

04【Gin框架】Gin HTML模板渲染以及模板语法 自定义模板函数 静态文件服务(下) | 50

  • and 函数返回它的第一个empty参数或者最后一个参数; 就是说”and x y”等价于”if x then y else x”;所有参数都会执行;
  • or 返回第一个非empty参数或者最后一个参数; 亦即”or x y”等价于”if x then x else y”;所有参数都会执行;
  • not 返回它的单个参数的布尔值的否定
  • len 返回它的参数的整数类型长度
  • index 执行结果为第一个参数以剩下的参数为索引/键指向的值;
{{len .xxx}}
自定义模板函数

04【Gin框架】Gin HTML模板渲染以及模板语法 自定义模板函数 静态文件服务(下) | 03:21 注册函数:

func UnixToTime (timestamp int) string{
	t := time.Unix(int64(timestamp),0)
	return t.Format("2006-01-02 15:04:05")
}
 
func main() {
	r := gin.Default()
	r.SetFuncMap(template.FuncMap{
		"UnixToTime": UnixToTime,
	})
}

使用函数:

{{UnixToTime .date}}
嵌套模板

04【Gin框架】Gin HTML模板渲染以及模板语法 自定义模板函数 静态文件服务(下) | 13:18 在某个模板中加载其他模板:

{{template "xxx/xxxx.html" .}}
静态文件服务
	r := gin.Default()
	r.LoadHTMLGlob("template/*")
	r.Static("/staticUrl", "./static") // static目录,通过/staticUrl/xxx.xx访问

路由传值

05【Gin框架】Get Post以及动态路由传值、Get Post数据解析到结构体、Post Xml数据解析到结构体 | 02:41

GET

  • context.Query获取参数值
  • context.DefaultQuery获取参数值,为空则使用默认值
func main() {
 
	r := gin.Default()
	r.GET("/", func(context *gin.Context) {
		username := context.Query("username")
		age := context.Query("age")
		page := context.DefaultQuery("page", "1")
 
		context.JSONP(http.StatusOK, gin.H{
			"username": username,
			"age":      age,
			"page":     page,
		})
	})
 
	r.Run(":8000") // 启动一个web服务
}

POST

使用context.PostForm

r.POST("/addUser", func(context *gin.Context) {
		username := context.PostForm("username")
		password := context.PostForm("password")
		age := context.DefaultPostForm("age", "20")
		context.JSONP(http.StatusOK, gin.H{
			"username": username,
			"password": password,
			"age":      age,
		})
	})

绑定到结构体

结构体需要使用form标签指定参数名

type User struct {
	Username string `form:"username" json:"username"`
	Password string `form:"password" json:"password"`
	Age      int    `form:"age" json:"age"`
}
 
func main() {
 
	r := gin.Default()
 
	r.POST("/addUser", func(context *gin.Context) {
		user := &User{}
		err := context.ShouldBind(user)
		if err != nil {
			context.JSON(http.StatusOK, gin.H{
				"error": err.Error(),
			})
		} else {
			context.JSON(http.StatusOK, user)
		}
	})
 
	r.Run(":8000") // 启动一个web服务
}

路由分组

06 【Gin框架】Gin路由分组 Gin路由文件抽离 | 38 使用r.Group()来分组路由,即加url前缀

	r := gin.Default()
 
	defaultRouters := r.Group("/")
	{
		defaultRouters.GET("/", func(context *gin.Context) {
			context.String(http.StatusOK, "首页")
		})
	}
 
	apiRouters := r.Group("/api")
	{
		apiRouters.GET("/test", func(context *gin.Context) {
			context.JSON(http.StatusOK, gin.H{
				"test": "api",
			})
		})
	}
 
	r.Run(":8000") // 启动一个web服务

路由抽离

新建包用来存放路由代码,调用方法加载路由

func main() {
 
	r := gin.Default()
	routers.DefaultRouters(r)
	routers.Test(r)
	r.Run(":8000") // 启动一个web服务
}
 

routers/apiRouters.go

package routers
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
func Test(r *gin.Engine) {
	apiRouters := r.Group("/api")
	{
		apiRouters.GET("/test", func(context *gin.Context) {
			context.JSON(http.StatusOK, gin.H{
				"test": "api",
			})
		})
	}
}

自定义控制器

07 【Gin框架】Gin中自定义控制器以及实现控制器的继承 | 32 另建Controller包,定义结构体,写入业务函数,路由时指向结构体函数 controller/admin/userController.go

package admin
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
type UserController struct {
}
 
func (con UserController) Index(context *gin.Context) {
	context.String(http.StatusOK, "用户index")
}
 
func (con UserController) Add(context *gin.Context) {
	context.String(http.StatusOK, "用户ADD")
}
 

routers/userRouters.go

package routers
 
import (
	"github.com/gin-gonic/gin"
	"go_demo/controller/admin"
)
 
func UserRoutersInit(r *gin.Engine) {
	apiRouters := r.Group("/api")
	{
		apiRouters.GET("/userIndex", admin.UserController{}.Index)
		apiRouters.POST("/userAdd", admin.UserController{}.Add)
	}
}
 

中间件

08【Gin框架】Gin中间件详解 路由中间件 全局中间件 路由分组中间件 | 15 GET、POST等方法可以传入多个回调函数,执行最终函数之前执行的函数就称为中间件

  • context.Next() 函数中context.Next()可以先执行后面的函数,按顺序或规则执行
  • context.Abort() 终止请求剩余处理程序 只执行完当前的函数

全局中间件

默认路由
r := gin.Default()
routers.DefaultRouters(r)
routers.Test(r)
r.GET("/test", func(context *gin.Context) {
		fmt.Println("test")
	})
r.Use(func(context *gin.Context) {
	fmt.Println("全局中间件")
})
 
路由分组

两种方式:1和2 定义group全局中间件必须在使用路由之前

func Test(r *gin.Engine) {
	apiRouters := r.Group("/api", func(context *gin.Context) {
		fmt.Println("group全局中间件1")
	})
	apiRouters.Use(func(context *gin.Context) {
		fmt.Println("group全局中间件2")
	})
	{
		apiRouters.GET("/userIndex", func(context *gin.Context) {
			fmt.Println("1-我是一个中间件")
			fmt.Println("2-我是一个中间件")
		}, func(context *gin.Context) {
			fmt.Println("下一个方法")
		}, admin.UserController{}.Index)
		apiRouters.POST("/userAdd", admin.UserController{}.Add)
	}
 
}
 

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

context.get(“xxx”)返回(数据,是否有数据(t/f)) 返回的数据是空接口类型,需要类型断言

apiRouters := r.Group("/api", func(context *gin.Context) {
		context.Set("username", "张三")
		fmt.Println("group全局中间件1")
	})
	apiRouters.Use(func(context *gin.Context) {
		fmt.Println("group全局中间件2")
		fmt.Println(context.Get("username")) // 张三 true
	})

默认中间件

gin.Default()默认使用了Logger和Recovery中间件

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

使用goroutine

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

自定义Model

09【Gin框架】Gin框架中自定义Model | 16 把公共的功能单独抽取出来作为一个模块(Model)。Model是逐步抽象的过程,一般我们会在Model里面封装一些公共的方法让不同的Controller使用,也可以在Model中实现与数据库交互

  • 新建包(models)
  • 使用的地方引入models

文件上传

10【Gin框架】Gin中实现单文件上传 多文件上传 | 16 file,err := c.FromFile()接收文件 c.SaveUploadedFile(file,"./static/upload/xxx.xxx")保存文件

同名多文件上传

from,_ := c.MultipartForm() 获取相同名字文件表单 然后循环遍历files := form.File("upload[]")

11【Gin框架】Gin中的Cookie 多个二级域名共享 Cookie | 24 用于多个页面数据共享:Cookie、Seesion 是存储在浏览器中的,同一个浏览器中访问同一个域实现共享 c.SetCookie(name,value string,maxAge int,path domain string,secure,httpOnly bool) 设置cookie

  • key
  • value
  • 过期时间
  • cookie保存路劲
  • 作用域(域名)
  • secure:为true时仅https有效
  • 扩展httpOnly,为true时js脚本、applet等无法读取cookie c.Cookie(name)获取cookie

二级域名共享cookie

设置1级作用域,点开头(.baidu.com)

Session

12【Gin框架】Gin Session 设置获取 以及分布式Session | 32 session是另一种记录客户状态的机制,不同的是cookie保存在浏览器,session保存在服务 客户端访问服务器时,服务器会创建session对象,生成类似key-value的键值对,将value保存到服务器,key保存到浏览器作为cookie 浏览器下次访问会携带key,找到对应的session

gin中使用session

gin-contrib/session

store := cookie.newStore([]byte("secret111")) // 创建基于cookie的存储引擎,secret111是用于加密的密钥
r.Use(sessions.Sessions("mysession",store)) //store是前面的存储引擎,配置session的中间键,mysession就是上文的key,用于保存在浏览器的cookie中
 

在控制器中:

session := sessions.Default(context)
session.set("key","value") // 设置session
session.Save() // 保存session,设置session必须调用
 
// 获取session
a := session.Get("key")

redis配置session

store,_ redis.NewStore(10,"tcp","localhost:6379","password",[]byte("secret"))
r.Use(sessions.Sessions("myredissession",store))

修改session过期时间

session.Options(sessions.Options{
	MaxAge: 3600 * 6,// 6hrs
})
session.Set("xx","xx")