**Gin **框架入门实战系列教程
主讲教师:(大地)
在线文档:https://www.itying.com/gin
我的专栏:https://www.itying.com/category-79-b0.html
十、**Gin **中自定义 Model
10.1 、关于 Model
:::tips
如果我们的应用非常简单的话,我们可以在 Controller 里面处理常见的业务逻辑。但是如果 我们有一个功能想在多个控制器、或者多个模板里面复用的话,那么我们就可以把公共的功 能单独抽取出来作为一个模块(Model)。 Model 是逐步抽象的过程,一般我们会在 Model 里面封装一些公共的方法让不同 Controller 使用,也可以在 Model 中实现和数据库打交道
:::
10.2 、Model 里面封装公共的方法
**1 **、新建 models/ tools.go
package models
import (
"crypto/md5"
"fmt"
"time"
"github.com/astaxie/beego"
)
//时间戳间戳转换成日期
func UnixToDate(timestamp int) string {
t := time.Unix(int64(timestamp), 0)
return t.Format("2006-01-02 15:04:05")
}
//日期转换成时间戳 2020-05-02 15:04:05
func DateToUnix(str string) int64 {
template := "2006-01-02 15:04:05"
t, err := time.ParseInLocation(template, str, time.Local)
if err != nil {
return 0
}
return t.Unix()
}
func GetUnix() int64 {
return time.Now().Unix()
}
func GetDate() string {
template := "2006-01-02 15:04:05"
return time.Now().Format(template)
}
func GetDay() string {
template := "20060102"
return time.Now().Format(template)
}
func Md5(str string) string {
data := []byte(str)
return fmt.Sprintf("%x\n", md5.Sum(data))
}
10.3 、控制器中调用 Model
package controllers
import (
"gin_demo/models"
)
day := models.GetDay()
10.4 、调用 Model 注册全局模板函数
models/tools.go
//时间戳间戳转换成日期
func UnixToDate(timestamp int64) string {
t := time.Unix(timestamp, 0)
return t.Format("2006-01-02 15:04:05")
}
main.go
//注册全局模板函数 注意顺序,注册模板函数需要在加载模板上面
r := gin.Default()
r.SetFuncMap(template.FuncMap{
"unixToDate" : models.UnixToDate,
})
控制器
func (c UserController) Add(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "admin/user/add.html", gin.H{
"now" : models.GetUnix(),
})
}
模板
<h2>{{.now | unixToDate}}</h2>
10.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)) |
---|
十一、**Gin **文件上传
注意:需要在上传文件的 form 表单上面需要加入 enctype=“multipart/form-data”
11.1 、单文件上传
https://gin-gonic.com/zh-cn/docs/examples/upload-file/single-file/
官方示例:
func main() {
router := gin.Default()
// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// 单文件
file, _ := c.FormFile("file")
log.Println(file.Filename)
// 上传文件至指定目录
c.SaveUploadedFile(file, dst)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) })
router.Run(" :8080")
}
项目中实现文件上传:
**1 **、定义模板 需要在上传文件的 form 表单上面需要加入 enctype=“multipart/form-data”
<!-- 相当于给模板定义一个名字 define end 成对出现-->
{{ define "admin/user/add.html" }}
<!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>Document</title>
</head>
<body>
<form action="/admin/user/doAdd" method=" post" enctype="multipart/form-data">
用户名: <input type="text" name="username" placeholder="用户名"> <br> <br> 头 像:<input type="file" name="face"><br> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
{{ end }}
**2 **、定义业务逻辑
func (c UserController) DoAdd(ctx *gin.Context) {
username := ctx.PostForm("username")
file, err := ctx.FormFile("face")
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{
"message" : err.Error(),
})
return
}
// 上传文件到指定的目录
dst := path.Join("./static/upload", file.Filename)
fmt.Println(dst)
ctx.SaveUploadedFile(file, dst)
ctx.JSON(http.StatusOK, gin.H{
"message" : fmt.Sprintf("'%s' uploaded!", file.Filename),
" "
username : username,
})
}
11.2 、多文件上传–不同名字的多个文件
1 、定义模板 需要在上传文件的 form 表单上面需要加入 enctype=“multipart/form-data”
<!-- 相当于给模板定义一个名字 define end 成对出现-->
{{ define "admin/user/add.html" }}
<!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>Document</title>
</head>
<body>
<form action="/admin/user/doAdd" method=" post" enctype="multipart/form-data">
用户名: <input type="text" name="username" placeholder="用户名"> <br> <br>
头 像 1:<input type="file" name="face1"><br> <br>
头 像 2:<input type="file" name="face2"><br> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
{{ end }}
**2 **、定义业务逻辑
func (c UserController) DoAdd(ctx *gin.Context) {
username := ctx.PostForm("username")
face1, err1 := ctx.FormFile("face1")
face2, err2 := ctx.FormFile("face2")
// 上传文件到指定的目录
if err1 == nil {
dst1 := path.Join("./static/upload", face1.Filename)
ctx.SaveUploadedFile(face1, dst1)
}
if err2 == nil {
dst2 := path.Join("./static/upload", face2.Filename)
ctx.SaveUploadedFile(face2, dst2)
}
ctx.JSON(http.StatusOK, gin.H{
"message" : "文件上传成功",
" "
username : username,
})
// ctx.String(200, username)
}
11.3 、多文件上传–相同名字的多个文件
参考:https://gin-gonic.com/zh-cn/docs/examples/upload-file/multiple-file/
**1 **、定义模板 需要在上传文件的 form 表单上面需要加入 enctype=“multipart/form-data”
<!-- 相当于给模板定义一个名字 define end 成对出现-->
{{ define "admin/user/add.html" }}
<!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>Document</title>
</head>
<body>
<form action="/admin/user/doAdd" method=" post" enctype="multipart/form-data">
用户名: <input type="text" name="username" placeholder="用户名"> <br> <br>
头 像 1:<input type="file" name="face[]"><br> <br>
头 像 2:<input type="file" name="face[]"><br> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
{{ end }}
**2 **、定义业务逻辑
func (c UserController) DoAdd(ctx *gin.Context) {
username := ctx.PostForm("username")
// Multipart form
form, _ := ctx.MultipartForm()
files := form.File["face[]"]
// var dst;
for _, file := range files {
// 上传文件至指定目录
dst := path.Join("./static/upload", file.Filename)
ctx.SaveUploadedFile(file, dst)
}
ctx.JSON(http.StatusOK, gin.H{
"message" : "文件上传成功",
" "
username : username,
})
}
11.4 、文件上传 按照日期存储
**1 **、定义模板 需要在上传文件的 form 表单上面需要加入 enctype=“multipart/form-data”
<!-- 相当于给模板定义一个名字 define end 成对出现-->
{{ define "admin/user/add.html" }}
<!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>Document</title>
</head>
<body>
<form action="/admin/user/doAdd" method=" post" enctype="multipart/form-data">
用户名: <input type="text" name="username" placeholder="用户名"> <br> <br> 头 像: <input type="file" name="face"><br> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
{{ end }}
**2 **、定义业务逻辑
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
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)
}
**3 **、models/tools.go
package models
import (
"crypto/md5"
"fmt"
"time"
)
//时间戳间戳转换成日期
func UnixToDate(timestamp int) string {
t := time.Unix(int64(timestamp), 0)
return t.Format("2006-01-02 15:04:05")
}
//日期转换成时间戳 2020-05-02 15:04:05
func DateToUnix(str string) int64 {
template := "2006-01-02 15:04:05"
t, err := time.ParseInLocation(template, str, time.Local)
if err != nil {
beego.Info(err)
return 0
}
return t.Unix()
}
func GetUnix() int64 {
return time.Now().Unix()
}
func GetDate() string {
template := "2006-01-02 15:04:05"
return time.Now().Format(template)
}
func GetDay() string {
template := "20060102"
return time.Now().Format(template)
}
func Md5(str string) string {
data := []byte(str)
return fmt.Sprintf("%x\n", md5.Sum(data))
}
func Hello(in string) (out string) {
out = in + "world"
return
}
十二、Gin 中的 Cookie
12.1 、Cookie 介绍
:::tips
● HTTP 是无状态协议。简单地说,当你浏览了一个页面,然后转到同一个网站的另一个页 面,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次的访问,都是没有任何 关系的。如果我们要实现多个页面之间共享数据的话我们就可以使用 Cookie 或者 Session 实 现
● cookie 是存储于访问者计算机的浏览器中。可以让我们用同一个浏览器访问同一个域名 的时候共享数据。
:::
12.2 、Cookie 能实现的功能
:::tips
1 、保持用户登录状态
2 、保存用户浏览的历史记录
3 、猜你喜欢,智能推荐
4 、电商网站的加入购物车
:::
12.3 、设置和获取 Cookie
https://gin-gonic.com/zh-cn/docs/examples/cookie/
设置 Cookie
c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)
第一个参数 第二个参数
第三个参
:::info
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")
完整 **demo
**
package main
import (
"gin_demo/models"
"html/template"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.SetFuncMap(template.FuncMap{
"unixToDate" : models.UnixToDate,
})
r.GET("/", func(c *gin.Context) {
c.SetCookie("usrename", "张三", 3600, "/", "localhost", false, true)
c.String(200, "首页")
})
r.GET("/user", func(c *gin.Context) {
username, _ := c.Cookie("usrename")
c.String(200, "用户-"+username)
})
r.Run(" :8080")
}
12.4 、多个二级域名共享 cookie
:::info
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)