Go Web(gin框架)---day2

沉下心慢慢来,别好高骛远。

文章目录

        • 1 模板函数的使用
          • 1.1 自定义模板函数
          • 1.2 模板嵌套
        • 2 静态文件服务
        • 3 路由详解
          • 3.1 GET POST 以及获取 GET POST 传值
          • 3.2 简单的路由组
          • 3.3 Gin路由文件 分组
        • 4 Gin中自定义控制器
          • 4.1 控制器分组
          • 4.2 控制器的继承
        • 5 Gin中间件
          • 5.1.1 初识中间件
          • 5.1.2 ctx.Next()调用该请求的剩余处理程序
          • 5.1.3 一个路由配置多个中间件的执行顺序
          • 5.1.4 c.Abort()
          • 5.2 全局中间件
          • 5.3 在路由分组中配置中间件
          • 5.4 中间件和对应控制器之间共享数据
          • 5.5、中间件注意事项
        • 6 Gin中自定义Model
          • 6.1 关于Model
          • 6.2 Model里面封装公共的方法
          • 6.3 控制器中调用Model
          • 6.4 调用Model注册全局模板函数
          • 6.5 Golang Md5 加密
        • 7 Gin文件上传
          • 7.1 单文件上传
          • 7.2 多文件上传--不同名字的多个文件
          • 7.3 多文件上传--相同名字的多个文件
          • 7.4 文件上传 按照日期存储
        • 8 Gin中的Cookie
          • 8.1 Cookie 介绍
          • 8.2 Cookie能实现的功能
          • 8.3 设置和获取 Cookie
          • 8.4 多个二级域名共享cookie
        • 9 Gin 中的Session
          • 9.1 Session简单介绍
          • 9.2 Session的工作流程
          • 9.3 Gin中使用Session
          • 9.4 基于Cookie存储Session
          • 9.5 基于Redis 存储 Session

1 模板函数的使用

我们使用以下函数来解析一个文件夹下的所有template

r.LoadHTMLGlob("templates/**/*")

模板放在不同目录里面的配置方法,我们使用define来给模板定义名称

{{define "模板名称"}}
{{end}}
1.1 自定义模板函数

可以用来对特定的数据进行特定的处理

router.SetFuncMap{
	"模板调用名":"自定义函数名",
}
1.2 模板嵌套
{{template "模板名称" .}}

2 静态文件服务

引用静态文件时,我们需要配置静态web服务

//形成路由映射本地文件
r.Static("路由地址","文件路径")
3 路由详解
3.1 GET POST 以及获取 GET POST 传值
//GET请求传值
c.Query("参数名")
//如果没有获取,则使用默认值
c.DefaultQuery("参数名","默认值")

//动态路由传值(域名/user/20)
c.Param("uid")

//Post请求传值 获取form表单数据
c.PostForm("参数名(和form表单的name要一致)")

//获取GET POST 传递的数据绑定到结构体
//基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中Querystring、from表单、JSON、XML等参数到结构体中
type Userinfo struct{
	Username string `form:"username" json:"user"`
	Passowrd string `form:"password"json:"password"`
}
//使用一个err来接收,然后判断数据接收是否成功
err:=c.Shouldbind(&Userinfo)
//根据不同的请求方法以不同的形式绑定到结构体
r.Get()
r.Post()

//获取Post Xml 数据
b,_:=c.GetRawData()
//互获取到的数据之后使用xml.Unmarshal将其解析到对应的结构体
xml.Unmarshal(b,&article)   
3.2 简单的路由组
//使用group函数对路由进行分组
router.Group("路由组名")
3.3 Gin路由文件 分组

目前就是直接独立出来一个路由部分,单独建立一个路由的文件夹,里面放路由函数

4 Gin中自定义控制器
4.1 控制器分组

控制器函数中我们定义了空结构体来对处理函数进行分类

4.2 控制器的继承

GO语言中没有继承这一概念,说白了就是使用匿名组合来实现继承的效果

然后我们就可以将控制器里面的公共方法抽离出来形成一个单独控制器类

5 Gin中间件

gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(HOOK)函数。这个钩子函数就叫中间件
中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作

5.1.1 初识中间件

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

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

中间件里面加上了ctx.Next()可以让我们在路由匹配完成后执行一些操作

比如统计一个请求的时间

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"
)
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")
}
5.1.3 一个路由配置多个中间件的执行顺序
5.1.4 c.Abort()

Abort是终止的意思,c.Abort()表示终止调用该请求的剩余处理程序

5.2 全局中间件

使用 r.Use()注册中间件到路由中

5.3 在路由分组中配置中间件

1、为路由注册中间件有以下两种写法

r.Group("/","中间件函数名")

router:=r.Group("/")
router.Use("中间件函数名")
5.4 中间件和对应控制器之间共享数据

设置值

ctx.Set("username","张三")
username,_=ctx.Get("username")

中间件设置值

func InitAdminMiddleware(ctx *gin.Context) {
	fmt.Println("路由分组中间件")
	// 可以通过 ctx.Set 在请求上下文中设置值,后续的处理函数能够取到该值
	ctx.Set("username", "张三")
	// 调用该请求的剩余处理程序
	ctx.Next()
}
//控制器获取值
func (c UserController) Index(ctx *gin.Context) {
	username, _ := ctx.Get("username")
	fmt.Println(username)
	ctx.String(http.StatusOK, "这是用户首页 111")
}
5.5、中间件注意事项

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())

6 Gin中自定义Model
6.1 关于Model

功能复用:我们可以把公共的功能单独抽取出来作为一个模块(Model)。Model 是逐步抽象的过程,一般我们会在Model里面封装一些公共的方法让不同Controller
使用,也可以在Model 中实现和数据库打交道。

6.2 Model里面封装公共的方法
6.3 控制器中调用Model
6.4 调用Model注册全局模板函数
6.5 Golang Md5 加密

打开 golang 包对应的网站:https://pkg.go.dev/,搜索 md5
方法一:

data := []byte("123456")
has := md5.Sum(data)
md5str := fmt.Sprintf("%x", has)
fmt.Println(md5str)

方法二:

h := md5.New()
io.WriteString(h, "123456")
fmt.Printf("%x\n", h.Sum(nil))
7 Gin文件上传

注意:需要在上传文件的 form 表单上面需要加入enctype="multipart/form-data"

7.1 单文件上传

https://gin-gonic.com/zh-cn/docs/examples/upload-file/single-file/

// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
// 单文件,文件名参数和HTML页面中定义的名字相同
file, _:= c.FormFile("file")
// 上传文件至指定目录
c.SaveUploadedFile(file, dst)
7.2 多文件上传–不同名字的多个文件

相同的函数,就是再写一遍然后保存

7.3 多文件上传–相同名字的多个文件

HTML页面的name属性给切片类型,函数遍历保存每个文件

7.4 文件上传 按照日期存储
func (c UserController) DoAdd(ctx *gin.Context) {
	username := ctx.PostForm("username")
	//1、获取上传的文件
	file, err1 := ctx.FormFile("face")
	if err1 == nil {
		//2、获取后缀名 判断类型是否正确 .jpg .png .gif .jpeg
		extName := path.Ext(file.Filename)
		allowExtMap := map[string]bool{".jpg": true, ".png": true, ".gif": true, ".jpeg": true}
		if _, ok := allowExtMap[extName]; !ok {
			ctx.String(200, "文件类型不合法")
			return
		}
		//3、创建图片保存目录 static/upload/20200623
		day := models.GetDay()
		dir := "./static/upload/" + day
		//os.MkdirAll创建多级目录
		if err := os.MkdirAll(dir, 0666); err != nil {
			log.Error(err)
		}
		//4、生成文件名称 144325235235.png
		fileUnixName := strconv.FormatInt(models.GetUnix(), 10)
		//static/upload/20200623/144325235235.png
		saveDir := path.Join(dir, fileUnixName+extName)
		ctx.SaveUploadedFile(file, saveDir)
	}
	ctx.JSON(http.StatusOK, gin.H{"message": "文件上传成功", "username": username})
	// ctx.String(200, username)
}
8 Gin中的Cookie
8.1 Cookie 介绍
  • HTTP 是无状态协议。简单地说,当你浏览了一个页面,然后转到同一个网站的另一个页面,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次的访问,都是没有任何关系的。如果我们要实现多个页面之间共享数据的话我们就可以使用 Cookie 或者 Session 实现
  • cookie 是存储于访问者计算机的浏览器中。可以让我们用同一个浏览器访问同一个域名的时候共享数据
8.2 Cookie能实现的功能

1、保持用户登录状态
2、保存用户浏览的历史记录
3、猜你喜欢,智能推荐
4、电商网站的加入购物车

8.3 设置和获取 Cookie

设置 Cookie
c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)
第一个参数 key
第二个参数 value
第三个参数 过期时间.如果只想设置 Cookie 的保存路径而不想设置存活时间,可以在第三个参数中传递 nil
第四个参数 cookie 的路径
第五个参数 cookie 的路径 Domain 作用域 本地调试配置成 localhost , 正式上线配置成域名
第六个参数是 secure ,当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效
第七个参数 httpOnly,是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了“httpOnly”属性,
则通过程序(JS 脚本、applet 等)将无法读取到 COOKIE 信息,防止 XSS 攻击产生

//获取 Cookie
cookie, err := c.Cookie("name")
8.4 多个二级域名共享cookie

1、分别把 a.itying.com 和 b.itying.com 解析到我们的服务器
2、我们想的是用户在 a.itying.com 中设置 Cookie 信息后在 b.itying.com 中获取刚才设置的cookie,也就是实现多个二级域名共享 cookie这时候的话我们就可以这样设置 cookie
c.SetCookie(“usrename”, “张三”, 3600, “/”, “.itying.com”, false, true)

9 Gin 中的Session
9.1 Session简单介绍

session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session保存在服务器上。

9.2 Session的工作流程

当客户端浏览器第一次访问服务器并发送请求时,服务器端会创建一个 session 对象,生成一个类似于 key,value 的键值对, 然后将 key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带 key(cookie),找到对应的 session(value)。

9.3 Gin中使用Session

Gin 官方没有给我们提供 Session 相关的文档,这个时候我们可以使用第三方的 Session 中间件来实现
gin-contrib/sessions 中间件支持的存储引擎:

  • cookie
  • memstore
  • redis
  • memcached
  • mongodb
9.4 基于Cookie存储Session

1、安装 session 包
go get github.com/gin-contrib/sessions

package main

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// 创建基于 cookie 的存储引擎,secret11111 参数是用于加密的密钥
	store := cookie.NewStore([]byte("secret11111"))
	// 设置 session 中间件,参数 mysession,指的是 session 的名字,也是 cookie 的名字
	// 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")
}
9.5 基于Redis 存储 Session

如果我们想将 session 数据保存到 redis 中,只要将 session 的存储引擎改成 redis 即可。
使用 redis 作为存储引擎的例子:
首先安装 redis 存储引擎的包
go get github.com/gin-contrib/sessions/redis

package main
import ( "github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/redis"
	"github.com/gin-gonic/gin"
)
func main() {
	r := gin.Default()
	// 初始化基于 redis 的存储引擎
	// 参数说明:
	// 第 1 个参数 - redis 最大的空闲连接数
	// 第 2 个参数 - 数通信协议 tcp 或者 udp
	// 第 3 个参数 - redis 地址, 格式,host:port
	// 第 4 个参数 - redis 密码
	// 第 5 个参数 - session 加密密钥
	store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("secret"))
	r.Use(sessions.Sessions("mysession", store))
	r.GET("/", func(c *gin.Context) {
		session := sessions.Default(c)
		session.Set("username", "李四")
		session.Save()
		c.JSON(200, gin.H{"username": 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")
}

你可能感兴趣的:(Go,Web(gin框架),golang,前端,gin,html)