GO语言学习(16)Gin后端框架

目录

☀️前言

1.什么是前端?什么是后端?🌀

2.Gin框架介绍 🌷

3.Gin框架的基本使用 -Hello,World例子🌷

 🌿入门示例 - Hello,World

💻补充(一些常用的网络术语): 

3.1 Get请求与Post请求📞

3.2 状态码 🔧

4.Gin的各类返回方式 🌷

✏️返回字符串:

 ✏️返回xml:

✏️返回文件(如Excel,txt,png等文件):

 ✏️页面重定向:

 5.如何处理前端的请求数据🌷

6.Gin框架实战案例 -表单信息提交处理🌷

4.1 前端JS请求 🔅

4.2 后端Gin编写 🔅 


☀️前言

        通过前面的基本学习,终于开始进入项目学习阶段。本文将主要介绍Go语言官方的后端框架Gin如何与前端数据交互,以及实现最基本的表单数据交互案例,而关于后端操作数据库的部分,将留在下一章进行详细讲解。

1.什么是前端?什么是后端?🌀

        前端和后端是软件开发中的两个重要部分,它们共同协作完成一个完整的产品或系统。通俗来说,前端就像餐厅的前台,负责接待顾客、展示菜单、处理顾客的点餐需求,后端就像餐厅的后厨,负责准备食材、烹饪菜肴、确保菜品按时送到前台,前端是用户看到的“表面”,负责展示和交互。后端是用户看不到的“幕后”,负责处理数据和逻辑。

对比维度前端后端
定义前端是用户直接看到和交互的部分,主要负责展示界面和处理用户操作。后端是运行在服务器上的部分,主要负责数据处理、逻辑运算和存储。
主要功能展示页面、交互设计、响应用户操作(如点击按钮、输入内容)。处理业务逻辑、管理数据库、提供 API 接口给前端调用。
技术栈HTML、CSS、JavaScript、框架(如 React、Vue、Angular)。

服务器语言(如 Python、Java、Node.js、PHP)、

数据库(如 MySQL、MongoDB)。

工作内容设计和实现用户界面、优化用户体验、与后端 API 交互。开发服务器端逻辑、管理数据库、处理数据、提供安全性和性能优化。
用户体验直接影响用户对产品的第一印象,注重界面美观和交互流畅性。间接影响用户体验,主要通过提供稳定、快速的服务来支持前端。
安全性前端代码是公开的,容易被用户查看和篡改,安全性较弱。后端代码运行在服务器上,用户无法直接访问,安全性较高。
开发工具浏览器、代码编辑器(如 VS Code)、前端框架工具。服务器环境、数据库管理工具、API 测试工具(如 Postman)。

2.Gin框架介绍 🌷

        Gin 是一个用 Go 语言编写的高性能 HTTP Web 框架,以轻量级、快速路由和中间件支持著称。Gin的设计目标是帮助开发者快速构建Web应用和RESTful API,同时保持高性能和低资源占用。其主要特点如下:

  1. 高性能:基于Radix树的路由实现,内存占用小,无反射,API性能可预测。
  2. 零分配路由器:路由处理过程中不产生内存分配,确保高效。
  3. 中间件支持:支持链式中间件,可以用于日志记录、认证、GZIP压缩等。
  4. 崩溃恢复:能够捕获HTTP请求中的panic并恢复,确保服务器始终可用。
  5. JSON验证:支持对请求中的JSON数据进行验证,确保数据完整性。
  6. 路由分组:支持路由分组,便于组织不同功能的API版本或权限。
  7. 错误管理:提供方便的方式收集和处理HTTP请求中的错误。
  8. 内置渲染:支持JSON、XML和HTML的渲染。
  9. 可扩展性:易于创建自定义中间件,满足特定需求

同样Go语言的后端框架不止Gin一种,还有其它后端框架,如Beggo,比较结果如下:

框架性能路由中间件适用场景学习曲线
Gin极高基于httprouter丰富且灵活API服务、微服务、高性能后端
Echo自定义实现简洁RESTful API、轻量级应用
Fiber极高类似ExpressExpress风格替代Gin,追求极简语法
Beego中等自带MVC路由全功能全栈开发(含ORM、模板引擎)中高

3.Gin框架的基本使用 -Hello,World例子🌷

        首先我们得先导入Gin的包,熟悉python语言的同学都知道,对于 python 我们可以在终端使用 pip install 命令进行下载所需要的包,而go语言,可以在终端使用 go get 命令来获取第三方包,导入到项目中。我们在项目的终端中,输入如下命令,即可将Gin框架导入到项目中,接下来就可以使用Gin框架进行开发了。

$ go get -u github.com/gin-gonic/gin
 🌿入门示例 - Hello,World
package mainimport "github.com/gin-gonic/gin"   // 导入Gin的包func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{"message": "Hello, World!"})})r.Run(":8080") // 监听 0.0.0.0:8080
}

 🌳解释🌳:

  • r := gin.Default() 使用gin创建了一个默认的路由器实例,它会自动加载一些中间件,比如日志记录和恢复中间件,接下来由它负责处理网页的HTTP请求并调用相应的处理函数。
  • r.get用于定义一个GET请求的路由。这里定义了一个路径为"/"的GET请求处理函数。当客户端访问应用的根路径"/"时,会调用这个处理函数。cgin.Context类型的参数,它包含了请求和响应的所有信息。c.JSON用于向客户端发送JSON格式的响应。200是HTTP状态码,表示请求成功。gin.H是一个快捷方式,用于创建一个map[string]interface{},这里用于构建JSON响应内容。
  • r.Run()启动HTTP服务器并开始监听请求。":8080"指定了服务器监听的端口号为8080

         通过本次简单的例子,我们可以归纳出更为普遍的Gin后端框架处理流程,如下图所示:

💻补充(一些常用的网络术语): 

3.1 Get请求与Post请求📞

        通俗来说,GET请求就像去图书馆借书,你告诉图书馆员你想借的书名(参数),这个书名会显示在借书单上(URL),别人可以看到。POST请求就像去图书馆还书,你把书交给图书馆员(数据放在请求体中),这个过程是相对私密的,别人不会知道你具体还了什么书。

对比维度GET请求POST请求
用途用于从服务器获取数据,比如访问一个网页或查询信息。用于向服务器提交数据,比如提交表单或上传文件。
数据传递方式参数附加在URL后面,比如http://example.com/search?q=keyword数据放在请求体中,不会显示在URL中。
安全性相对不安全,因为参数会显示在浏览器地址栏中,可能会被保存在浏览器历史记录或服务器日志中。相对更安全,因为数据不会显示在浏览器地址栏中,也不容易被缓存或记录在历史中。
限制URL长度有限制,通常不能超过2048个字符,不适合传递大量数据。没有长度限制,可以传递大量数据。
缓存可以被浏览器缓存,多次访问相同的URL时可能不会每次都向服务器发送请求。通常不会被浏览器缓存,每次提交都会向服务器发送请求。
幂等性是幂等的,多次请求相同URL不会产生不同结果。不是幂等的,多次提交相同数据可能会产生不同结果(如多次提交表单)。
书签可以通过书签保存URL,方便后续访问。不能通过书签保存请求体中的数据。
适用场景适合简单的查询和数据获取,比如搜索、查看页面内容。适合复杂操作和敏感数据的提交,比如登录、文件上传、表单提交等。
3.2 状态码 🔧

        HTTP状态码是服务器对客户端请求的响应状态的三位数字代码,用于表示请求的处理结果。状态码分为以下几类:

  • 1xx(信息性状态码):表示请求已接收,正在处理。

  • 2xx(成功状态码):表示请求已成功处理。

  • 3xx(重定向状态码):表示需要进一步操作才能完成请求。

  • 4xx(客户端错误状态码):表示客户端请求有误,服务器无法处理。

  • 5xx(服务器错误状态码):表示服务器处理请求时发生错误。

状态码描述
100继续,表示服务器已收到请求的初始部分,客户端可以继续发送其余请求。
200请求成功,服务器返回了请求的数据。
201资源已成功创建。
301资源的URL已永久更改。
302资源的URL暂时更改。
400请求有误,服务器无法处理。
401请求未授权。
403请求被拒绝。
404请求的资源不存在。
500服务器内部错误,无法完成请求。
502服务器从上游服务器接收到的响应无效。
503服务不可用,通常是服务器过载或维护

        而在Go语言中,可以使用net/http包来处理HTTP请求和响应,如http.StatusOK代表状态码200http.StatusBadRequest代表状态码400http.StatusInternalServerError代表状态码500

4.Gin的各类返回方式 🌷

        上述基本案例中,Gin返回的数据类型为json格式,下面介绍一些别的格式的数据返回。

✏️返回字符串:

router.GET("/str", func(c *gin.Context) {c.String(http.StatusOK, "返回成功")
})

 ✏️返回xml:

router.GET("/xml", func(c *gin.Context) {c.XML(http.StatusOK, gin.H{"user": "FJNU", "message": "hey", "status": http.StatusOK})
})

✏️返回文件(如Excel,txt,png等文件):

 router.GET("/download/:filename", func(c *gin.Context) {filename := c.Param("filename")           // 获取前端传输的文件名filePath := "./files/" + filename        // 获取本地的文件路径c.File(filePath)              // 将对应的文件传回前端})

        上述方法用于返回单个文件,filename必须包含文件的扩展名(如.png),Gin会自动根据文件扩展名设置正确的MIME类型。

        如果希望文件被浏览器作为附件下载而不是直接显示,可以使用c.FileAttachment()方法。

package mainimport "github.com/gin-gonic/gin"func main() {router := gin.Default()router.GET("/download/:filename", func(c *gin.Context) {filename := c.Param("filename")filePath := "./files/" + filenamec.FileAttachment(filePath, filename)})router.Run(":8080")
}

 ✏️页面重定向:

        如果你希望点击某个按钮后,跳转到另一个页面,可以使用以下方法:

router.GET("/redirect", func(c *gin.Context) {//支持内部和外部的重定向c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
})

 5.如何处理前端的请求数据🌷

        c *gin.Context 是 Gin 框架处理 HTTP 请求的核心对象,封装了请求和响应的所有操作。以下是其核心功能及用法:

功能方法/属性说明
获取请求参数c.Param("key")获取路由参数(如 /user/:id → id
c.Query("key")获取 URL 查询参数(如 ?name=John
c.PostForm("key")获取表单数据(Content-Type: application/x-www-form-urlencoded
c.FormFile("file")获取上传的文件(Content-Type: multipart/form-data
请求头操作c.GetHeader("User-Agent")获取请求头字段
c.Request.Header直接访问原始请求头(http.Header类型)

1.获取路由当中的静态值(Query):

r.GET("/test/:age", func(c *gin.Context) {age := c.Query("age")c.String(200, "I am %s years old", age)})

2.获取动态路由中的值(Param):

r.GET("/hello/:name", func(c *gin.Context) {name := c.Param("name")c.String(200, "hello %s", name)})

 3.保存前端所上传的文件(如word,excel,png图片等):

r := gin.Default()// 设置静态文件目录,方便前端访问上传的文件r.Static("/uploads", "./uploads")// 处理文件上传r.POST("/upload", func(c *gin.Context) {// 获取名为 "file" 的上传文件file, err := c.FormFile("file")if err != nil {c.String(http.StatusBadRequest, fmt.Sprintf("get form file err: %s", err.Error()))return}// 获取上传文件的原始文件名filename := file.Filename// 指定文件保存路径destination := "./uploads/" + filename// 创建 uploads 目录(如果不存在)err = os.MkdirAll("./uploads", os.ModePerm)if err != nil {c.String(http.StatusInternalServerError, fmt.Sprintf("mkdir err: %s", err.Error()))return}// 保存上传的文件到指定位置if err := c.SaveUploadedFile(file, destination); err != nil {c.String(http.StatusInternalServerError, fmt.Sprintf("upload file err: %s", err.Error()))return}// 返回成功信息c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", filename))})

当然对于接受到的前端数据c,也可以进行后端变量的数据绑定:

方法说明
c.ShouldBindJSON(&obj)将请求体 JSON 绑定到结构体,自动触发 binding 标签验证
c.ShouldBindQuery(&obj)绑定 URL 查询参数到结构体
c.ShouldBindUri(&obj)绑定路由参数到结构体
c.Bind(&obj)自动根据 Content-Type 选择绑定方式,验证失败直接返回 400 错误

以下为一段示例代码:

type User struct {Name  string `json:"name" binding:"required"`// 必填且必须是邮箱格式Email string `json:"email" binding:"required,email"`// 数值范围限制(18 ≤ Age ≤ 60)Age   int    `json:"age" binding:"gte=18,lte=60"`// 字符串长度限制(6 ≤ 密码长度 ≤ 16)Password string `json:"password" binding:"required,min=6,max=16"`// 枚举值(只能是 "male" 或 "female")Gender string `json:"gender" binding:"oneof=male female"`
}
func CreateUser(c *gin.Context) {var user Userif err := c.ShouldBindJSON(&user); err != nil {// 返回验证错误信息c.JSON(400, gin.H{"error": err.Error()})return}// 验证通过后的业务逻辑c.JSON(200, gin.H{"message": "User created"})
}

         上述代码,会将前端传回的json数据c的值绑定在结构体变量user中,并验证数据是否符合结构体当中的binding要求,若不满足则会产生对应的错误err,否则err为空。

        对于中间件与流程控制,有如下方法: 

方法说明
c.Next()继续执行后续中间件或处理函数(通常在中间件中调用)
c.Abort()终止当前请求的后续处理(如权限校验失败时)
c.AbortWithStatus(code)终止并返回指定 HTTP 状态码
c.Set("key", value)存储数据供后续中间件或处理函数使用
c.Get("key")获取通过 Set 存储的值

中间件示例代码:

func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {token := c.GetHeader("Authorization")if token != "valid-token" {c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})return}c.Set("user", "admin") // 传递用户信息c.Next()}
}// 路由中使用中间件
router.GET("/admin", AuthMiddleware(), func(c *gin.Context) {user := c.MustGet("user").(string)c.String(200, "Welcome %s", user)
})

        关于响应的请求头,以及Cookie,Session会话机制的内容,将在后续章节进一步详细解释。 

6.Gin框架实战案例 -表单信息提交处理🌷

        本次案例地前端是使用VUE3与Vite共同创建,采用的UI组件为ElementPlus-Form,如果你熟悉VUE2或其他UI组件库,当然也可以使用。这里就不过多叙述前端的搭建了,前端页面最终效果如下:

4.1 前端JS请求 🔅

        对Create按键添加绑定函数,使得用户点击该按钮的时候,能够自动提交表单填写的信息。

                         

        接着使用Axios,将前端的表单数据发送到后端,当然熟悉fetch的uu,也可以使用fetch的方法进行数据传递。             

4.2 后端Gin编写 🔅 

        首先先介绍一个概念-跨域请求(CORS):CORS(Cross-Origin Resource Sharing)是一种机制,允许服务器通过设置HTTP头部来指定哪些源(域、协议或端口)可以访问其资源。它用于解决浏览器的同源策略限制,使得不同源之间的资源可以安全地进行交互。 

        为了使得数据可以从前端传递到后端,首先我们得先配置一下Gin的CORS,具体代码如下:

r := gin.Default()// 自定义 CORS 中间件r.Use(func(c *gin.Context) {// 设置允许的请求头c.Writer.Header().Set("Access-Control-Allow-Origin", "*")c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")if c.Request.Method == "OPTIONS" {c.AbortWithStatus(http.StatusNoContent)return}c.Next()})

        配置完CORS之后,开始编写处理函数部分:

r.POST("/submit-form", func(c *gin.Context) {var formData map[string]interface{}if err := c.BindJSON(&formData); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}c.JSON(http.StatusOK, gin.H{"message": "Form submitted successfully", "data": formData})})

        这里与前端的请求相照应,由于前端发起的是POST方式,所以此处也使用r.POST,而不能使用r.GET,路径对应前端的请求路径,为 /submit-form

        接着声明一个 map[string]interface{} 类型的变量formData,用于存储从请求体中解析出来的JSON数据。map[string]interface{}是一个通用的键值对结构,可以存储任意类型的值。(关于Go语言当中map数据类型的内容,我确实没写过...后续有时间在补上。)

        c.BindJSON(&formData)尝试从请求体中解析JSON数据,并将其绑定到formData变量中。如果解析失败,err会包含错误信息。如果解析失败,使用c.JSON发送一个400状态码(http.StatusBadRequest)和一个包含错误信息的JSON响应。如果JSON解析成功,使用c.JSON发送一个200状态码(http.StatusOK)和一个包含成功消息和解析数据的JSON响应。

        最后依据前端的访问端口,进行对应的配置:

r.Run(":8000")

 至此,后端部分完成,下面开始测试:

1.使用npm run开启前端界面,以及运行对应的后端Go文件。

2.在前端界面的表单中输入信息,并点击Create按钮进行表单数据的提交

3.在后端Gin文件中,可以查看到刚刚的前端请求信息

 4.在前端界面中,使用F12,点击Console,可以在控制台看到,Gin所传回来的后端数据,接着前端接受,使用变量接收数据,便可以将数据渲染显示在网页界面上了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/74364.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析 Git Submodule:从基础到高级操作指南

深入解析 Git Submodule:从基础到高级操作指南 一、Git Submodule 是什么? git submodule 是 Git 提供的一个强大功能,允许在一个 Git 仓库(主仓库)中嵌入另一个独立的 Git 仓库(子模块)。主仓…

电子电气架构 --- EEA演进与芯片架构转移

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…

如何用deepseek生成流程图

软件准备: 在线流程图【Flowchart Maker & Online Diagram Software】或【process on】 步骤: 1、用 【DeepSeek】生成 结构化内容(Mermaid文件) 1.1、向deepseek输入指令:【帮我用mermaind写出“某某”的具体…

【华为OD技术面试真题 - 技术面】- Java面试题(17)

华为OD面试真题精选 专栏:华为OD面试真题精选 目录: 2024华为OD面试手撕代码真题目录以及八股文真题目录 文章目录 华为OD面试真题精选虚拟机分区1. **虚拟磁盘分区**2. **虚拟机的内存分区**3. **CPU分配**4. **虚拟网络分区**5. **存储虚拟化和分区**6. **虚拟机分区管理**…

Linux | I.MX6ULL内核及文件系统源码结构(7)

01 类型 描述 备注 ARM 交叉编译器 版本:4.9.4 提供软件工具 Uboot 版本:2016.03 提供源码 支持LCD显示;支持网口; 支持 EMMC,NAND FLASH; 支持环境变量修改保存 Linux 内核 版本:4.1.15 提供…

0基础入门scrapy 框架,获取豆瓣top250存入mysql

一、基础教程 创建项目命令 scrapy startproject mySpider --项目名称 创建爬虫文件 scrapy genspider itcast "itcast.cn" --自动生成 itcast.py 文件 爬虫名称 爬虫网址 运行爬虫 scrapy crawl baidu(爬虫名) 使用终端运行太麻烦了,而且…

鸿蒙NEXT小游戏开发:猜小球

1. 引言 “猜小球”是一个经典的益智游戏,通常由一名表演者和多名参与者共同完成。表演者会将一个小球放在一个杯子下面,然后将三个杯子快速地交换位置,参与者则需要猜出最终哪个杯子下面有小球。本文将介绍如何使用HarmonyOS NEXT技术&…

网络购物谨慎使用手机免密支付功能

在数字经济蓬勃发展的当下,“免密支付”成为许多人消费时的首选支付方式。 “免密支付”的存在有其合理性。在快节奏的现代生活中,时间愈发珍贵,每节省一秒都可能带来更高的效率。以日常通勤为例,上班族乘坐交通工具时&#xff0c…

记录 | Android getWindow().getDecorView().setSystemUiVisibility(...)设置状态栏属性

纯纯的一边开发一边学习,是小白是菜鸟,单纯的记录和学习,大神勿喷,理解有错望指正~ getWindow().getDecorView().setSystemUiVisibility(…) 该方法用于控制系统 UI(如状态栏、导航栏)的可见性…

java虚拟机---JVM

JVM JVM,也就是 Java 虚拟机,它最主要的作用就是对编译后的 Java 字节码文件逐行解释,翻译成机器码指令,并交给对应的操作系统去执行。 JVM 的其他特性有: JVM 可以自动管理内存,通过垃圾回收器回收不再…

VectorBT:使用PyTorch+LSTM训练和回测股票模型 进阶四

VectorBT:使用PyTorchLSTM训练和回测股票模型 进阶四 本方案融合 LSTM 时序预测与动态风险控制。系统采用混合架构,离线训练构建多尺度特征工程和双均线策略,结合在线增量更新持续优化模型。技术要点包括三层特征筛选、波动率动态仓位管理、混…

前端中rem,vh,vw

1. rem&#xff08;Root EM&#xff09; 参照对象 基准&#xff1a;相对于 根元素&#xff08;<html>&#xff09;的 font-size 计算。 默认情况下&#xff0c;浏览器的根 font-size 为 16px&#xff08;即 1rem 16px&#xff09;&#xff0c;但可通过 CSS 修改&#…

详解 MySQL 常见的存储引擎及它们之间的区别

MySQL 支持多种存储引擎&#xff0c;每种引擎针对不同的应用场景提供了特定的特性和优化。下面是几种常见的存储引擎以及它们之间的主要区别&#xff1a; 常见存储引擎 1. InnoDB&#xff08;重点&#xff09; 事务支持&#xff1a; 完全支持 ACID 事务&#xff0c;确保数据一…

html+css+js 实现一个贪吃蛇小游戏

目录 游戏简介 游戏功能与特点 如何玩转贪吃蛇 游戏设计与实现 HTML结构 JavaScript核心实现 代码结构&#xff1a; 效果 关于“其他游戏” 游戏简介 贪吃蛇是一款经典的单人小游戏&#xff0c;玩家通过控制蛇的移动&#xff0c;吃掉食物来增加长度&#xff0c;避免撞…

GLSL(OpenGL 着色器语言)基础语法

GLSL&#xff08;OpenGL 着色器语言&#xff09;基础语法 GLSL&#xff08;OpenGL Shading Language&#xff09;是 OpenGL 计算着色器的语言&#xff0c;语法类似于 C 语言&#xff0c;但提供了针对 GPU 的特殊功能&#xff0c;如向量运算和矩阵运算。 着色器的开头总是要声明…

ngx_http_core_merge_srv_conf

定义在 src\http\ngx_http_core_module.c static char * ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) {ngx_http_core_srv_conf_t *prev parent;ngx_http_core_srv_conf_t *conf child;ngx_str_t name;ngx_http_server_name_t…

uni-app:firstUI框架的选择器Select改造,添加一个搜索的插槽

<fui-select :show"showSiteType" :options"siteTypeList" textKey"dict_label" title"请选择站点类型" confirm"chooseSiteType" close"onCloseSiteType"><template v-slot:search><view><…

Debian/Ubuntu的networking的`/etc/network/interfaces`配置文件,如何配置route路由

Debian/Ubuntu的networking的/etc/network/interfaces配置文件,如何配置route路由 在 Debian/Ubuntu 系统中&#xff0c;通过 /etc/network/interfaces 配置文件配置路由&#xff08;静态路由或默认路由&#xff09;可以通过以下方式实现。以下是详细配置方法及示例&#xff1…

天梯赛 L2-024 部落

一个并查集题目&#xff0c;难点就在于统计总人数&#xff0c;使用map即可&#xff0c;还有需要注意的是编号不一定是小于N的&#xff0c;小于10000的&#xff0c;需要注意。 #include<bits/stdc.h> using namespace std; const int N 10010; int fa[N]; int find(int …

uniapp 微信小程序 使用ucharts

文章目录 前言一、组件功能概述二、代码结构分析2.1 模板结构 总结 前言 本文介绍一个基于 Vue 框架的小程序图表组件开发方案。该组件通过 uCharts 库实现折线图的绘制&#xff0c;并支持滚动、缩放、触摸提示等交互功能。文章将从代码结构、核心方法、交互实现和样式设计等方…