【Go语言】Gin 框架教程
Gin 框架教程
1.第一个 Gin 程序
1.1 Gin 安装
# 执行执行如下操作即可,安装Gin前需要安装Go环境
go get -u -v github.com/gin-gonic/gin
# -v:打印出被构建的代码包的名字
# -u:已存在相关的代码包,强行更新代码包及其依赖包
1.2 Gin 项目创建
在一个空文件夹里新建文件 main.go
,参考如下代码编写一个 Gin
程序。
// blog.euansu.cn
// main.go
package mainimport "github.com/gin-gonic/gin"func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {c.String(200, "Hello, EuanSu")})r.Run() // listen and serve on 0.0.0.0:8080
}
运行 main.go
程序,如下图所示。
go run main.go
代码说明:
- 首先,
r := gin.Default()
这里生成了一个Gin
引擎实例,用于处理HTTP
请求,也即WSGI
应用程序,这个实例会预先加载一些默认的中间件。 r.GET("/", ...)
则是声明了一个路由,以及路由对应的函数方法。r.Run()
函数则是运行应用程序,默认的监听端口是8080
,也可以传入参数设置应用程序运行端口,例如r.Run(":8888")
,即应用运行在8888
端口。
1.3 网站图标设置
这里使用一个 Gin
的中间件 github.com/thinkerou/favicon
,使用同 gin
框架,首先是安装 github.com/thinkerou/favicon
库。
go get github.com/thinkerou/favicon
接下来,则是使用该中间件,代码如下所示:
// blog.euansu.cn
// main.go
package mainimport ("github.com/gin-gonic/gin""github.com/thinkerou/favicon"
)func main() {// 创建一个服务r := gin.Default()// 使用中间件r.Use(favicon.New("./static/favicon.ico"))// 路由函数r.GET("/", func(c *gin.Context) {c.String(200, "Hello, EuanSu")})r.Run() // listen and serve on 0.0.0.0:8080
}
项目运行后,就能够在浏览器中看到 favicon.ico
网站图标。
2.Gin 中的路由
2.1 路由语法
$router.$method("$router", $handlerFunction)
# router,Gin 引擎实例
# method,http路由方法,可选参数为:GET、POST、PUT、PATCH、DELETE、OPTIONS、HEAD以及能够处理任意类型的HTTP请求的Any和处理指定类型的HTTP请求的Match
# handlerFunction,路由函数,处理路由响应
示例如下:
router.GET("/path", handlerFunction) // 获取资源
router.POST("/path", handlerFunction) // 创建资源
router.PUT("/path", handlerFunction) // 更新资源
router.DELETE("/path", handlerFunction) // 删除资源
router.PATCH("/path", handlerFunction) // 更新部分资源
router.OPTIONS("/path", handlerFunction) // 获取服务器支持的 HTTP 方法
router.HEAD("/path", handlerFunction) // 获取资源的头部信息
router.Any("/path", handlerFunction) // 处理任意类型的 HTTP 请求
router.Match([]string{"GET", "POST"}, "/path", handlerFunction) // 处理指定类型的 HTTP 请求
2.2 请求参数的处理
2.2.1 路由参数解析
参数包含在路由中,如 /user/:name
,通过调用不同的 路由参数
传入不同的 name
,如下所示:
r.GET("/user/:name", func(c *gin.Context) {name := c.Param("name")c.String(http.StatusOK, "%s, Welcome to your clicl.", name)
})
这里需要注意下,如果新增了路由,需要重启 Gin
程序,重启之后,再次访问路由地址,就能够正常解析路由参数了。
2.2.2 Query 参数解析
Query 参数
与上文的路由参数一样,参数都是路由的一部分,不同的是 Query 参数
是键值对的形式,查询参数通常位于URL的问号(?
)之后,以键值对的形式出现,并且多个参数之间用与号(&
)分隔。
r.GET("/users", func(c *gin.Context) {name := c.Query("name")c.String(http.StatusOK, "%s, Thank you for your click.", name)
})
也可以直接使用 URL
通过浏览器请求该接口。
2.2.3 POST 参数解析(form表单)
这里使用一个表单参数进行举例,如下所示,输入分数转化为及格、不及格的判断,代码如下所示。
package mainimport ("github.com/gin-gonic/gin""net/http""strconv"
)func evaluateScore(score int) string {if score >= 90 {return "优秀"} else if score >= 60 {return "及格"} else {return "不及格"}
}func main() {r := gin.Default()// POST参数解析// POSTr.POST("/form", func(c *gin.Context) {username := c.PostForm("username")// DefaultPostForm,只支持string类型,因此需要进行类型的转换scoreStr := c.DefaultPostForm("score", "0")score, err := strconv.Atoi(scoreStr)if err != nil {// 处理错误情况,例如当输入的值不是整数时c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid score"})return}result := evaluateScore(score)c.JSON(http.StatusOK, gin.H{"username": username, "score": score, "evaluation": result})})r.Run() // listen and serve on 0.0.0.0:8080
}
r.POST("/form", func(c *gin.Context) {username := c.PostForm("username")password := c.DefaultPostForm("password", "000000") // 可设置默认值fmt.Println(password)c.String(http.StatusOK, "%s, Thank you for your login.", username)
})
请求后端的接口,返回如下。
2.2.4 POST 参数解析(json)
package mainimport ("github.com/gin-gonic/gin""net/http""strconv"
)func evaluateScore(score int) string {if score >= 90 {return "优秀"} else if score >= 60 {return "及格"} else {return "不及格"}
}// 定义结构体,与JSON数据匹配
type Person struct {Username string `json:"username"`Score int `json:"score"`
}func main() {r := gin.Default()// 处理POST请求,接收JSON参数r.POST("/json", func(c *gin.Context) {var person Person// 绑定JSON到结构体if err := c.ShouldBindJSON(&person); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}result := evaluateScore(person.Score)c.JSON(http.StatusOK, gin.H{"username": person.Username, "score": person.Score, "evaluation": result})})r.Run() // listen and serve on 0.0.0.0:8080
}
请求后端的接口,返回如下。
2.3 路由处理
2.3.1 重定向
r.GET("/redirect", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "/")
})
如下所示,当后端收到 /redirect
路由的请求,会重定向至 /
。
2.3.2 分组路由
分组路由主要是为了处理路由前缀一致的情况,例如有一组路由前缀都是 /api/v1
开头,通过分组路由就能够简化路由的定义,也可以更好的实现路由的权限控制,例如将需要登录的路由放到同一分组中。代码示例如下:
// 默认的路由方法
defaultHandler := func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"path": c.FullPath(),})
}// group: v1
v1 := r.Group("/v1")
{v1.GET("/posts", defaultHandler)v1.GET("/series", defaultHandler)
}
// group: v2
v2 := r.Group("/v2")
{v2.GET("/posts", defaultHandler)v2.GET("/series", defaultHandler)
}
请求不同的路由地址,均能够得到正常的响应。
3.RESTful API
RESTful API
具体概念可以查看 https://blog.euansu.cn/post/djangorestframework/
这篇文章中关于 RESTful API
的相关介绍 。
使用 Go
语言能够快速的实现 RESTful API
,实现如下:
r.GET("/user", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "get user"})
})
r.POST("/user", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "post user"})
})
r.PUT("/user", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "put user"})
})
r.DELETE("/user", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"msg": "delete user"})
})
使用 Apifox
等接口测试工具测试,应用程序能够根据使用的 HTTP
请求方式的不同而使用不同的函数进行处理。
-
GET
请求 -
POST
请求 -
PUT
请求 -
DELETE
请求
如上测试所示,Gin
框架能够快速、简洁的实现 RESTful API
。
4.响应页面
可以通过以下方式,先加载静态页面到 Gin
应用程序中。
// 加载静态页面
r.LoadHTMLGlob("templates/*")
// 加载指定的静态页面(不推荐)
r.LoadHTMLFiles("templates/index.html")
路由函数
r.GET("/", func(c *gin.Context) {c.HTML(http.StatusOK, "index.html", gin.H{"msg": "index.html", "path": "/"})
})
打开浏览器,访问 Gin
的 /
路由,显示如下。
5.中间件
首先是在项目中,声明一个中间件方法 myHandler()
,如下是 myHandler()
的代码方法。
func myHandler() gin.HandlerFunc {return func(c *gin.Context) {// 设置中间件的值c.Set("usersession", "xxx")if c.Request.URL.Path == "/" {// 阻止fmt.Println("阻止")c.Abort()}// 放行fmt.Println("放行")c.Next()}
}
在 Gin
应用程序中使用这个中间件。
func main() {// 创建一个服务r := gin.Default()// 使用中间件r.Use(myHandler())...r.Run() // listen and serve on 0.0.0.0:8080
}
实际测试效果如下:
-
请求
/
路由,后端返回为空。 -
请求其他的路由,则不受影响,就如我们在中间件方法所写的判断一样,仅仅只是拦截了
/
的路由请求。
6.数据库
Gin
项目中使用数据库,涉及以下操作:
- 安装数据库驱动和
ORM
库,安详需要使用的数据库驱动和ORM
库,常见的ORM
库是GORM
,支持MySQL
、PostgreSQL
和SQLite
等数据库。 - 配置数据库的连接信息,需要在
Gin
项目配置中配置数据库连接,通常是main.go
或者单独的配置文件。 - 初始化数据库,在项目启动的时候,进行数据库连接的初始化。
- 项目中使用数据库, 在路由关联的函数中使用数据进行增删改查的操作。
6.1 安装数据库驱动和 ORM 库
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
6.2 配置数据库的连接信息
在 main.go
文件中配置数据库的连接信息。
// 数据库连接信息
dsn := "username:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
var err error// 连接数据库
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {log.Fatalf("无法连接数据库: %v", err)
}
6.3 数据库初始化
使用 gorm
库,定义数据库模型,在 main.go
文件中添加 AutoMigrate
方法,进行数据库的迁移操作。
// 定义一个全局的数据库连接变量
var db *gorm.DB// User 定义数据库模型
type User struct {ID uint `json:"id" gorm:"primaryKey"`Username string `json:"username"`Email string `json:"email"`
}func main() {// 创建一个服务r := gin.Default()// 使用中间件r.Use(favicon.New("./static/favicon.ico"))r.Use(myHandler())// 加载静态页面r.LoadHTMLGlob("templates/*")// 数据库连接信息dsn := "username:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"var err error// 连接数据库db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {log.Fatalf("无法连接数据库: %v", err)}// 自动迁移数据库db.AutoMigrate(&User{})r.Run() // listen and serve on 0.0.0.0:8080
}
项目启动如下,项目启动后,执行 AutoMigrate
方法。
连接配置的数据库,发现 AutoMigrate
初始化生成的表,数据库迁移操作成功。
6.4 数据库使用
如下是获取用户列表和创建用户的两个函数方法。
// 获取用户列表的处理函数
func getUsers(c *gin.Context) {var users []Userresult := db.Find(&users)if result.Error != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})return}c.JSON(http.StatusOK, users)
}// 创建用户的处理函数
func createUser(c *gin.Context) {var user Userif err := c.ShouldBindJSON(&user); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}result := db.Create(&user)if result.Error != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})return}c.JSON(http.StatusOK, user)
}
在 main.go
中添加路由函数,如下所示:
// 定义路由和处理函数
r.GET("/users", getUsers)
r.POST("/users", createUser)
进行路由请求,如下所示:
-
POST
请求进行用户的创建。 -
GET
请求获取用户信息。
数据库操作的完整代码为:
// blog.euansu.cn
// main.go
package mainimport ("fmt""github.com/gin-gonic/gin""github.com/thinkerou/favicon""gorm.io/driver/mysql""gorm.io/gorm""log""net/http"
)func myHandler() gin.HandlerFunc {return func(c *gin.Context) {// 设置中间件的值c.Set("usersession", "xxx")if c.Request.URL.Path == "/" {// 阻止fmt.Println("阻止")c.Abort()}// 放行fmt.Println("放行")c.Next()}
}// 定义一个全局的数据库连接变量
var db *gorm.DB// User 定义数据库模型
type User struct {ID uint `json:"id" gorm:"primaryKey"`Username string `json:"username"`Email string `json:"email"`
}func main() {// 创建一个服务r := gin.Default()// 使用中间件r.Use(favicon.New("./static/favicon.ico"))r.Use(myHandler())// 加载静态页面r.LoadHTMLGlob("templates/*")// 数据库连接信息dsn := "username:password@tcp(127.0.0.1:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"var err error// 连接数据库db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {log.Fatalf("无法连接数据库: %v", err)}// 自动迁移数据库db.AutoMigrate(&User{})// 定义路由和处理函数r.GET("/users", getUsers)r.POST("/users", createUser)// 路由函数r.GET("/", func(c *gin.Context) {//c.String(200, "Hello, EuanSu")c.HTML(http.StatusOK, "index.html", gin.H{"msg": "index.html", "path": "/"})})r.GET("/home", func(c *gin.Context) {//c.String(200, "Hello, EuanSu")c.HTML(http.StatusOK, "index.html", gin.H{"msg": "index.html", "path": "/home"})})r.Run() // listen and serve on 0.0.0.0:8080
}func getUsers(c *gin.Context) {var users []Userresult := db.Find(&users)if result.Error != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})return}c.JSON(http.StatusOK, users)
}func createUser(c *gin.Context) {var user Userif err := c.ShouldBindJSON(&user); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}result := db.Create(&user)if result.Error != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})return}c.JSON(http.StatusOK, user)
}
7.相关链接
[1] Go Gin 简明教程 https://geektutu.com/post/quick-go-gin.html
[2] 【【狂神说】Gin框架一小时上手 | 快速转型GoWeb开发 | Go语言零基础教程】 https://www.bilibili.com/video/BV1Rd4y1C7A1/?share_source=copy_web&vd_source=5fdcc6213ac2d30f16a78fe5d6e8df4d
相关文章:

【Go语言】Gin 框架教程
Gin 框架教程 1.第一个 Gin 程序 1.1 Gin 安装 # 执行执行如下操作即可,安装Gin前需要安装Go环境 go get -u -v github.com/gin-gonic/gin # -v:打印出被构建的代码包的名字 # -u:已存在相关的代码包,强行更新代码包及其依赖包…...

MySQL性能问题诊断方法和常用工具
作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG数据库运维(如安装迁移,性能优化、故障应急处理等) 公众号:老苏畅谈运维 欢迎关注本人公众号,更多精彩与您分享。MySQL运…...
CGFloat转NSString保持原有的精度,末尾不添加0
问题阐述: 我们进行CGFloat转NSString可能会遇到一个问题 例如有一个CGFloat的值为2.1,转化成NSString后显示2.1000... 解决办法: 方法一: 如何解决呢,可以使用%g格式符,可以保证传入的不管是2还是2.1…...

UDS服务——TransferData (0x36)
诊断协议那些事儿 诊断协议那些事儿专栏系列文章,本文介绍TransferData (0x36)—— 数据传输,用于下载/上传数据时用的,数据的传输方向由不同的服务控制:0x34服务表示下载,0x35服务表示上传。通过阅读本文,希望能对你有所帮助。 文章目录 诊断协议那些事儿传输数据服务…...

jQuery 基本操作
01-简介 jQuery 是一个功能丰富且广泛使用的 JavaScript 库,它简化了 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作。jQuery 通过其易用的 API,使复杂的 JavaScript 编程任务变得更加简单,并且兼容各种浏览器。 1、jQuery特点 简化 DOM …...

有玩家在2011年的MacBook上成功运行了Windows XP 还安装了触摸屏
我们已经在许多不同的设备上看到过 Windows XP 正在运行。这个古老的操作系统于 2001 年正式推出,现在已经老到其最后一次软件更新是在近十年前。一位好奇的玩家试图在 2011 年的触摸屏 MacBook 上为 Windows XP 打造了一个新家,复古技术探索者 Michael …...

高纯PFA容量瓶PFA试剂瓶在半导体材料的应用
在半导体生产过程中,为避免金属污染对硅器件性能造成不利影响,碳化硅产业链不同阶段产品(如衬底、外延、芯片、器件)表面的痕量杂质元素浓度表征至关重要。 在实验人员使用质谱法高精度检测第三代半导体碳化硅材料的痕量杂质浓度…...

AudioSep:从音频中分离出特定声音(人声、笑声、噪音、乐器等)本地一键整合包下载
AudioSep是一种 AI 模型,可以使用自然语言查询进行声音分离。这一创新性的模型由Audio-AGI开发,使用户能够通过简单的语言描述来分离各种声音源。 比如在嘈杂的人流车流中说话的录音中,可以分别提取干净的人声说话声音和嘈杂的人流车流噪声。…...

Prompt 提示词工程:翻译提示
近期在对计算机学习时,许多内容需要看原始的英文论文,对于我这种学渣来说特别不友好,🤷🏻♀️无奈只能一边看翻译,一边学习。 之前有搜到过专门的翻译工具,无奈都是按照字数算费用的…...
【MySQL 的三大日志的作用】
在管理MySQL数据库时,了解和区分数据库使用的三大日志类型至关重要。这些日志对于确保数据的完整性、提供恢复机制以及维持数据库的稳定性发挥着关键作用。最主要还是小豆前段时间去参加面试被问到了这些内容,下面将详细讨论Redo Log、Binlog和Undo Log的…...
数据库中数据的id生成和算法
id生成策略 自增主键 一般使用整数类型的id可使用自增主键的策略去生成id 优点: 简单、易于使用和理解。保证唯一性,无需额外的查询操作。提高查询性能,因为ID是有序的,且支持索引。 缺点: 不适用于分布式系统&a…...

SystemVerilog Assertion精华知识
前言 断言主要用于验证设计的行为。断言也可用于提供功能覆盖率,并标记用于验证的输入激励不符合假定的需求。 在验证平台中,通常进行三个主要任务: 产生激励功能检查功能覆盖率度量 在当今的设计越来越复杂情况下,像波形调试…...

pdf怎么压缩到2m以内或5m以内的方法
PDF作为一种广泛使用的文档格式,已经成为我们工作和生活中不可或缺的一部分。然而,有时候PDF文件内存会比较大,给我们的存储和传输带来了很大的不便。因此,学会压缩 PDF 文件是非常必要的。 打开"轻云处理pdf官网"&…...

Butter Knife 8
// 部分代码省略… Override public View getView(int position, View view, ViewGroup parent) { ViewHolder holder; if (view ! null) { holder (ViewHolder) view.getTag(); } else { view inflater.inflate(R.layout.testlayout, parent, false); holder new ViewHolde…...

AMSR/ADEOS-II L1A Raw Observation Counts V003地球表面和大气微波辐射的详细观测数据
AMSR/ADEOS-II L1A Raw Observation Counts V003 简介 AMSR/ADEOS-II L1A Raw Observation Counts V003数据是由日本航空航天研究开发机构(JAXA)的AMSR (Advanced Microwave Scanning Radiometer)仪器收集的一组原始观测计数数据。这些数据是从ADEOS-I…...

MySQL之复制(十一)
复制 复制的问题和解决方案 数据损坏或丢失的错误 当一个二进制日志损坏时,能恢复多少数据取决于损坏的类型,有几种比较常见的类型: 1.数据改变,但事件仍是有效的SQL 不幸的是,MySQL甚至无法察觉这种损坏。因此最好还是经常检查…...

深入源码设计!Vue3.js核心API——Computed实现原理
如果您觉得这篇文章有帮助的话!给个点赞和评论支持下吧,感谢~ 作者:前端小王hs 阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主 此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来 书籍&a…...

驾考小技巧:老北京布鞋!距离高考出分还剩3天,我却看到有些孩子已经拿了“满分”——早读(逆天打工人爬取热门微信文章解读)
我20年驾校4000多块钱,你呢? 引言Python 代码第一篇 洞见 距离高考出分还剩3天,我却看到有些孩子已经拿了“满分”第二篇 视频新闻结尾 引言 昨天的文章顺利发出 看来“梅西” 这两个字在我们这边 不是敏感词 只是很多个罗粉搞得有点过头了 …...
java-正则表达式 2
7. 复杂的正则表达式示例(续) 7.1 验证日期格式 以下正则表达式用于验证日期格式,例如YYYY-MM-DD。 import java.util.regex.*;public class RegexExample {public static void main(String[] args) {String[] dates {"2023-01-01&q…...
hadoop常见简单基础面试题
文章目录 hadoop简单基础面试题1. 请说下 HDFS 读写流程2. HDFS 在读取文件的时候,如果其中一个块突然损坏了怎么办3. HDFS 在上传文件的时候,如果其中一个 DataNode 突然挂掉了怎么办4. NameNode 在启动的时候会做哪些操作5.Secondary NameNode 了解吗&…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...

elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...