既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
}
## 3 个人笔记
### 3.1 加入网站图标ICON
**下载依赖**:`github.com/thinkerou/favicon`
**图标位置**:`templates/favicon.ico`
**代码配置**:
router := gin.Default()
router.Use(favicon.New("templates/favicon.ico"))
### 3.2 文件上传功能
**多文件上传**:
put\_file.html:
后端代码:
package main
import (
“fmt”
“github.com/gin-gonic/gin”
“github.com/satori/go.uuid”
“net/http”
“path”
“strings”
)
func Upload(c *gin.Context) {
单文件
//file, _ := c.FormFile(“file”)
//log.Println(file.Filename)
//
上传文件到项目根目录,使用原文件名
//c.SaveUploadedFile(file, file.Filename)
//
//c.String(http.StatusOK, fmt.Sprintf(“‘%s’ upload!”, file.Filename))
//多个文件
form, err := c.MultipartForm()
if err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("get err %s", err.Error()))
}
// 获取所有图片
files := form.File["files"]
// 遍历所有图片
for \_, file := range files {
//获取文件名称带后缀
fileNameWithSuffix := path.Base(file.Filename)
//获取文件的后缀(文件类型)
fileType := path.Ext(fileNameWithSuffix)
//获取文件名称(不带后缀)
fileNameOnly := strings.TrimSuffix(fileNameWithSuffix, fileType)
fmt.Printf("fileNameWithSuffix==%s\n fileType==%s;\n fileNameOnly==%s;",
fileNameWithSuffix, fileType, fileNameOnly)
//生成UUID防止文件被覆盖
fileUUID := uuid.NewV4().String()
uuidName := strings.Replace(fileUUID, "-", "", -1)
dst := "F:\\project\\files\\" + uuidName + fileType
// 逐个存
if err := c.SaveUploadedFile(file, dst); err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("upload err %s", err.Error()))
return
}
}
c.String(http.StatusOK, fmt.Sprintf("upload ok %d files", len(files)))
}
func GoUpload(c *gin.Context) {
c.HTML(200, “put_file.html”, nil)
}
func main() {
r := gin.Default()
r.MaxMultipartMemory = 1024 << 20 //设置上传文件的最大内存1024MB
r.LoadHTMLGlob(“templates/*”)
r.GET(“/upload”, GoUpload)
r.POST(“/upload”, Upload)
r.Run()
}
**文件的上传地址**:直接复制`WINDOWS`或`LIUNX`下的文件路径即可。
示例:
1. WINDOWS系统路径`F:\project\files`,代码中的路径`F:\\project\\files\\`,注意在最后也要加`\\`。
2. LINUX系统路径:待操作。
### 3.3 文件下载
**注意:在测试下载功能时,浏览器需要清缓存,否则会异常!!!!**
视频、图片、音频,这三种既可以实现在浏览器端直接播放(预览),也可以改为直接下载。其他的文件类型都只能下载。
文件的本地路径和 `1.5.2` 一致。
代码:
package main
import (
“github.com/gin-gonic/gin”
)
//注意:在测试下载功能时,浏览器需要清缓存,否则会异常!!!!
func main() {
router := gin.Default()
//1、视频在线查看及下载
router.GET("/video", func(c \*gin.Context) {
//1、如果是下载,则需要在Header中设置这两个参数
//c.Header("Content-Type", "application/octet-stream")
//c.Header("Content-Disposition", "attachment; filename=Gin框架一小时上手.mp4")
c.File("F:\\project\\files\\Gin框架一小时上手.mp4")
})
//2、图片在线查看及下载
router.GET("/image", func(c \*gin.Context) {
//1、如果是下载,则需要在Header中设置这两个参数
//c.Header("Content-Type", "application/octet-stream")
//c.Header("Content-Disposition", "attachment; filename=IMG\_20211004\_113834.jpg")
c.File("F:\\project\\files\\IMG\_20211004\_113834.jpg")
})
//3、音频在线查看及下载
router.GET("/mp3", func(c \*gin.Context) {
//1、如果是下载,则需要在Header中设置这两个参数
//c.Header("Content-Type", "application/octet-stream")
//c.Header("Content-Disposition", "attachment; filename=吴景军 - 午后 (纯音乐) [mqms2].mp3")
c.File("F:\\project\\files\\吴景军 - 午后 (纯音乐) [mqms2].mp3")
})
//4、压缩包只能下载
router.GET("/zip", func(c \*gin.Context) {
//1、如果是下载,则需要在Header中设置这两个参数
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename=nginx-1.19.2.zip")
c.File("F:\\project\\files\\nginx-1.19.2.zip")
})
//5、office文档下载(xlsx)
router.GET("/xlsx", func(c \*gin.Context) {
//1、如果是下载,则需要在Header中设置这两个参数
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename=更新记录.xlsx")
c.File("F:\\project\\files\\更新记录.xlsx")
})
router.Run(":8080")
}
## 4 Gorm
### 4.1 Gorm文档
**对于Gorm的学习,推荐看官网 [https://gorm.io]( ) 文档。**
### 4.2 Gorm版本区别
目前网上有两个地址在提供Gorm,分别是 `github.com/jinzhu/gorm` 和 `gorm.io/gorm`。这两个有什么区别呢?
**省流解释:**
1. `gorm.io/gorm`:是 `GORM 2.0`版本库的地址;
2. `github.com/jinzhu/gorm` :`GORM 1.0`版本库的地址;
3. `gorm.io/gorm` 使用的数据库驱动被拆分为独立的项目,例如:`github.com/go-gorm/mysql`,且它的 import 路径也变更为 `gorm.io/driver/mysql`。
---
**具体解释:**
访问 Gorm官网:<https://gorm.io>(语言可以更换成中文),可以看到官方推荐的拉取Gorm的命令是:`go get -u gorm.io/gorm`,同时注意到在下放的推介中出现了`JINZHU`标签(红圈中),但此时我们仍然没有讲解两者的区别。
![Gorm官网](https://img-blog.csdnimg.cn/ebb34dae717e40ba94f46fcddfc6f578.png)
上图中,可以看到除了红圈,我还标注了`V2 RELEASE NOTE`(黄圈),它是 `Gorm 2.0` 版本的文档,点进去查看`GORM 2.0 发布说明`(语言切换成中文)。
![GORM 2.0 发布说明](https://img-blog.csdnimg.cn/7195e87ccd1a49e9ab9a9fd3588b1df8.png)
在如何升级这一部分终于看到两者的区别了:
1. `gorm.io/gorm`:是 `GORM 2.0`版本库的地址;
2. `github.com/jinzhu/gorm` :`GORM 1.0`版本库的地址;
3. `gorm.io/gorm` 使用的数据库驱动被拆分为独立的项目,例如:`github.com/go-gorm/mysql`,且它的 import 路径也变更为 `gorm.io/driver/mysql`。
### 4.3 Gorm使用示例
package main
import (
“fmt”
“gorm.io/driver/mysql”
“gorm.io/gorm”
“gorm.io/gorm/schema”
“time”
)
type USocial struct {
ID string
SocialName string
SocialUrl string
IconUrl string
CreateUser string
CreateTime time.Time
UpdateUser string
UpdateTime time.Time
DelFlag string
}
func main() {
db, err := gorm.Open(mysql.Open(“root:root@tcp(localhost:3306)/blog?parseTime=true&loc=Asia%2FShanghai”), &gorm.Config{
//解决Gorm结构体和数据表映射时加 ”s”的问题
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
if err != nil {
panic(“failed to connect database”)
}
sqlDb, _ := db.DB()
sqlDb.SetMaxOpenConns(5)
sqlDb.SetMaxIdleConns(2)
sqlDb.SetConnMaxIdleTime(time.Minute)
// 迁移 schema
db.AutoMigrate(&USocial{})
// Read
var user USocial
db.First(&user, "id = ?", "77a1daa8e26b49329c02c12bd3502edd") // 查找 social\_name 字段值为 微博 的记录
fmt.Println(user)
}
#### 4.3.1 Gorm结构体和数据表映射时出现复数 “s”的问题
参考1:[gorm的mysql表名带s的约定问题]( )
db, err := gorm.Open(mysql.Open("root:root@tcp(localhost:3306)/blog?parseTime=true&loc=Asia%2FShanghai"), &gorm.Config{
//解决Gorm结构体和数据表映射时加 ”s”的问题
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
## 5 Gorm面试问题
### 5.1 查询一条数据,如果没查到会怎样
描述:使用Gorm里如果只想查一条数据,比如通过用户ID去查询用户表,一般只会查到一条,如果没查到会怎么样?
参考1:[GORM查询数据]( )
当 First、Last、Take 方法找不到记录时,GORM 会返回 ErrRecordNotFound 错误。
在实际开发中查询不到数据,我们不一定会当成错误处理, gorm库通过下面办法检测Error是不是查询不到数据。
err := db.Take(&food).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
fmt.Println(“查询不到数据”)
} else if err != nil {
//如果err不等于record not found错误,又不等于nil,那说明sql执行失败了。
fmt.Println(“查询失败”, err)
}
### 5.2 网络连接失败也会报错,如何与5.1区分开
待查。
### 5.3 gorm遇到过的坑
参考1:[如何解决Go gorm踩过的坑]( )
1. 使用gorm.Model后无法查询数据
Scan error on column index 1, name “created_at”
//提示:
Scan error on column index 1, name “created_at”: unsupported Scan, storing driver.Value type []uint8
//解决办法:打开数据库的时候加上parseTime=true
root:123456@tcp(127.0.0.1:3306)/mapdb?charset=utf8&parseTime=true
2. Gorm结构体和数据表映射时出现复数 “s”的问题:看5.1
### 5.4 Gorm更新数据为零值问题
参考1:[Gorm 更新零值问题]( )
通过结构体变量更新字段值, gorm库会忽略零值字段。就是字段值等于0, nil, “”, false这些值会被忽略掉,不会更新。如果想更新零值,可以使用map类型替代结构体。
### 5.5 Gorm的自动建表有使用过吗
参考1:[(十三)GORM 自动建表(Migration特性)]( )
GORM支持Migration特性,支持根据Go Struct结构自动生成对应的表结构。如果表已经存在不会重复创建。
**注意:GORM 的AutoMigrate函数,仅支持建表,不支持修改字段和删除字段,避免意外导致丢失数据。**
### 5.6 Gorm和原生的相比有什么优势
1. **支持多种数据库**:`Gorm`支持多种关系型数据库,包括`MySQL`、`PostgreSQL`、`SQLite`和`Microsoft SQL Server`等,这使得它成为一个非常灵活的`ORM`库。
2. **提供强大的查询功能**:`Gorm`提供了许多强大的查询功能,如条件查询、排序、分组、连接查询和原始`SQL`查询等。这些功能使得开发人员可以轻松地执行复杂的数据库查询操作。
3. **支持事务处理**:`Gorm`支持事务处理,这意味着开发人员可以将一系列数据库操作放在同一个事务中,并且在任何一个操作失败时,事务会自动回滚,保证数据的完整性。
4. **支持模型关系映射**:`Gorm`支持模型之间的关系映射,包括一对一、一对多和多对多关系。这使得开发人员可以轻松地在不同的数据表之间建立关联。
5. **可扩展性强**:`Gorm`的可扩展性非常强,可以通过插件机制来扩展其功能。例如,可以通过插件来添加缓存、日志记录和自定义数据类型等功能。
![img](https://img-blog.csdnimg.cn/img_convert/9bc1b714da7c0cefda978b22cb898f3d.png)
![img](https://img-blog.csdnimg.cn/img_convert/07157469d2b855d0433010f9e558f7fa.png)
![img](https://img-blog.csdnimg.cn/img_convert/3a6865f76a4aab9b09bb24548570e633.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**
联。
5. **可扩展性强**:`Gorm`的可扩展性非常强,可以通过插件机制来扩展其功能。例如,可以通过插件来添加缓存、日志记录和自定义数据类型等功能。
[外链图片转存中...(img-3C7mhYOT-1715736761304)]
[外链图片转存中...(img-BsiA1bHA-1715736761304)]
[外链图片转存中...(img-UhyiVEjH-1715736761305)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**