Gin和Gorm常见面试题及解答_gorm面试题

  1. 内置渲染:Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。
  2. 可扩展性:新建一个中间件非常简单。
1.2.2 Gin的使用

其他文档1:Golang gin框架

2 Gin面试问题

2.1 Gin里的路由转发都用到什么功能了

参考1:Gin路由

Gin中的路由系统的用于接收请求,并将请求转发给注册的中间件或请求处理器来处理。核心功能如下:

  1. 路由系统可根据请求方法,请求路径,和路径参数来识别转发。
  2. 可设置一个或多个中间件用于在请求处理器前后,处理特殊的事件。
  3. 可以分组设置,将一个或多个中间件作用在一组多个路由上。

2.2 鉴权的中间件是在Gin里写的还是怎么处理的

可以使用 gin-jwt:gin框架学习-JWT认证

2.3 Gin里面的中间件

参考1:Gin框架—中间件
参考2:gin中间件

Gin中的中间件实际上还是一个Gin中的 gin.HandlerFunc。中间都是需要注册后才能启用的。
中间件分类
全局中间件:全局中间件设置之后对全局的路由都起作用。
路由组中间件:路由组中间件仅对该路由组下面的路由起作用。
单个路由中间件:单个路由中间件仅对一个路由起作用。

2.4 Gin怎么对某些接口做日志记录

2.1 Gin里的路由转发都用到什么功能了?
参考1:Gin路由

核心功能:

  • 路由系统可根据请求方法,请求路径,和路径参数来识别转发。
  • 可设置一个或多个中间件用于在请求处理器前后,处理特殊的事件。
  • 可以分组设置,将一个或多个中间件作用在一组多个路由上。

可以使用Gin路由的中间件功能,把要记录的接口封装到一个接口组中,然后注册中间件【方法】来处理。

2.5 为什么选择使用Gin框架

参考1:Gin框架介绍与基本使用

  1. Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点;
  2. 对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错;
  3. 借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范;
  4. 由于使用了http router,速度提高了近40倍。 如果你是性能和高效的追求者, 你会爱上Gin;

2.6 Gin都有哪些包,这些包分别能处理哪些内容

参考1:golang入门笔记——Gin
参考2:浅谈Gin框架中bind
参考3:浅谈go语言renderer包代码分析

  1. binding包
    Gin框架中的binding包,有bind函数可以非常方便的将url的查询参数query parameter、http的Header,body中提交上来的数据格式,如form,json,xml等,绑定到go中的结构体中去。
  2. render包
    renderer是Go语言的一个简单的、轻量的、快速响应的呈现包,它可以支持JSON、JSONP、XML、HYAML、HTML、File等类型的响应。在开发web应用或RESTFul API的时候,这个包是非常方便的工具包。

2.7 实现了Gin里的哪些方法,往Gin里注册的是路由还是回调

注册的是路由。

2.8 Gin里对goroutine的处理模式有了解吗,或者说goroutine的处理是在Gin还是在外面的程序里?

Gin里,因为一个请求过来后,是可以再开一个协程来处理请求的,这个需要在Gin里才能启用协程。

2.9 Gin框架实现请求地址映射到方法的过程

  1. 创建Gin引擎

router := gin.Default()

  1. 定义路由和处理程序方法:在Gin中,路由定义使用HTTP请求方法(GET、POST、PUT、DELETE等)和URL模式来匹配请求的URL。每个路由都映射到一个处理程序方法(通常是一个闭包函数)。
  2. 启动Gin服务。
  3. 请求映射到处理程序方法:当收到HTTP请求时,Gin会根据请求的HTTP方法和URL路径来查找匹配的路由定义,并将请求映射到相应的处理程序方法。处理程序方法接收一个*gin.Context参数,该参数包含有关请求和响应的信息,可以用来读取请求参数、设置响应头、返回JSON数据等。

2.10 Gin是如何解决跨域的

可以在gin.Context.Writer.Header()配置。

  1. Access-Control-Allow-Origin:必填,它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
  2. Access-Control-Allow-Methods:必填,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
  3. Access-Control-Allow-Headers:如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
  4. Access-Control-Expose-Headers:可选,CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
  5. Access-Control-Allow-Credentials:可选,它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
  6. Access-Control-Max-Age:可选,用来指定本次预检请求的有效期,单位为秒,在此期间,不用发出另一条预检请求。

func CORS() gin.HandlerFunc {
return func(context *gin.Context) {
// 允许 Origin 字段中的域发送请求
context.Writer.Header().Add(“Access-Control-Allow-Origin”, *)
// 设置预验请求有效期为 86400 秒
context.Writer.Header().Set(“Access-Control-Max-Age”, “86400”)
// 设置允许请求的方法
context.Writer.Header().Set(“Access-Control-Allow-Methods”, “POST, GET, OPTIONS, PUT, DELETE, UPDATE, PATCH”)
// 设置允许请求的 Header
context.Writer.Header().Set(“Access-Control-Allow-Headers”, “Content-Type, Content-Length,Apitoken”)
// 设置拿到除基本字段外的其他字段,如上面的Apitoken, 这里通过引用Access-Control-Expose-Headers,进行配置,效果是一样的。
context.Writer.Header().Set(“Access-Control-Expose-Headers”, “Content-Length, Access-Control-Allow-Headers”)
// 配置是否可以带认证信息
context.Writer.Header().Set(“Access-Control-Allow-Credentials”, “true”)
// OPTIONS请求返回200
if context.Request.Method == “OPTIONS” {
fmt.Println(context.Request.Header)
context.AbortWithStatus(200)
} else {
context.Next()
}
}
}

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:

Document 请选择上传文件:

后端代码:

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

文件的上传地址:直接复制WINDOWSLIUNX下的文件路径即可。
示例:

  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/gormgorm.io/gorm。这两个有什么区别呢?
省流解释:

  1. gorm.io/gorm:是 GORM 2.0版本库的地址;
  2. github.com/jinzhu/gormGORM 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官网
上图中,可以看到除了红圈,我还标注了V2 RELEASE NOTE(黄圈),它是 Gorm 2.0 版本的文档,点进去查看GORM 2.0 发布说明(语言切换成中文)。
GORM 2.0 发布说明
在如何升级这一部分终于看到两者的区别了:

  1. gorm.io/gorm:是 GORM 2.0版本库的地址;
  2. github.com/jinzhu/gormGORM 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的约定问题

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

-1712868916004)]
[外链图片转存中…(img-4oLSdVbU-1712868916004)]
[外链图片转存中…(img-NoobEoN4-1712868916005)]
[外链图片转存中…(img-PdxHKZY5-1712868916005)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-3AzWVy2l-1712868916006)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值