沉下心慢慢来,别好高骛远。
我们使用以下函数来解析一个文件夹下的所有template
r.LoadHTMLGlob("templates/**/*")
模板放在不同目录里面的配置方法,我们使用define来给模板定义名称
{{define "模板名称"}}
{{end}}
可以用来对特定的数据进行特定的处理
router.SetFuncMap{
"模板调用名":"自定义函数名",
}
{{template "模板名称" .}}
引用静态文件时,我们需要配置静态web服务
//形成路由映射本地文件
r.Static("路由地址","文件路径")
//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)
//使用group函数对路由进行分组
router.Group("路由组名")
目前就是直接独立出来一个路由部分,单独建立一个路由的文件夹,里面放路由函数
控制器函数中我们定义了空结构体来对处理函数进行分类
GO语言中没有继承这一概念,说白了就是使用匿名组合来实现继承的效果
然后我们就可以将控制器里面的公共方法抽离出来形成一个单独控制器类
gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(HOOK)函数
。这个钩子函数就叫中间件
中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
通俗的讲:中间件就是匹配路由前和匹配路由完成后执行的一系列操作
gin中的中间件必须是一个gin.HandlerFunc类型
,匹配路由的时候可以传递多个func回调函数,
最后一个func回调函数前面触发的方法都可以称为中间件
中间件里面加上了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")
}
Abort是终止的意思,c.Abort()
表示终止调用该请求的剩余处理程序
使用 r.Use()
注册中间件到路由中
1、为路由注册中间件有以下两种写法
r.Group("/","中间件函数名")
router:=r.Group("/")
router.Use("中间件函数名")
设置值
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")
}
gin 默认中间件
gin.Default()
默认使用了 Logger 和 Recovery 中间件,其中:
gin.DefaultWriter
,即使配置了 GIN_MODE=release
。如果不想使用上面两个默认的中间件,可以使用 gin.New()新建一个没有任何默认中间件的路由。
gin 中间件中使用 goroutine
当在中间件或 handler 中启动新的 goroutine 时,不能使用原始的上下文(c *gin.Context)
,必须使用其只读副本(c.Copy())
功能复用:我们可以把公共的功能单独抽取出来作为一个模块(Model)。Model 是逐步抽象的过程,一般我们会在Model里面封装一些公共的方法让不同Controller
使用,也可以在Model 中实现和数据库打交道。
打开 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))
注意:需要在上传文件的 form 表单上面需要加入enctype="multipart/form-data"
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)
相同的函数,就是再写一遍然后保存
HTML页面的name属性给切片类型,函数遍历保存每个文件
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)
}
1、保持用户登录状态
2、保存用户浏览的历史记录
3、猜你喜欢,智能推荐
4、电商网站的加入购物车
设置 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")
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)
session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session保存在服务器上。
当客户端浏览器第一次访问服务器并发送请求时,服务器端会创建一个 session 对象,生成一个类似于 key,value 的键值对, 然后将 key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带 key(cookie),找到对应的 session(value)。
Gin 官方没有给我们提供 Session 相关的文档,这个时候我们可以使用第三方的 Session 中间件来实现
gin-contrib/sessions 中间件支持的存储引擎:
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")
}
如果我们想将 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")
}