golang-gin包

文章目录

  • 一、了解gin
  • 二、html渲染
  • 三、gin中get/post获取值
  • 四、路由分组
  • 五、中间件
  • 六、文件上传
  • 七、gin中的cookie

一、了解gin

Gin 是一个用 Golang编写的 高性能的web 框架, 由于http路由的优化,速度提高了近 40 倍。 Gin的特

点就是封装优雅、API友好。

特性类别具体说明
性能表现基于 Radix 树实现路由,匹配速度极快,性能接近原生 Go HTTP 服务器
API 设计接口简洁直观,学习成本低,如 gin.Default() 快速创建实例,GET() / POST() 注册路由
中间件支持内置日志、恢复 panic、静态文件服务等中间件,支持自定义中间件实现扩展功能
路由管理支持路由分组(Group),便于按模块 / 版本 / 权限组织路由(如 /v1/*/admin/*
参数处理提供便捷的请求参数绑定(ShouldBind),支持 JSON / 表单 / Query 等格式,可配合标签验证
数据响应内置高效 JSON 处理,c.JSON() 快速返回 JSON 响应,性能优于标准库
错误处理简化异常处理流程,c.AbortWithError() 等方法可快速返回结构化错误响应
模板渲染集成 HTML 模板引擎,支持模板继承、自定义函数,适合传统 Web 应用开发
扩展性设计灵活,易于与 ORM、缓存、认证等工具集成,生态丰富
轻量特性核心代码简洁,依赖少,编译后二进制体积小,适合微服务或轻量应用

下载gin包

go get -u github.com/gin-gonic/gin

测试一下

package main
import "github.com/gin-gonic/gin"
func main() {router := gin.Default()router.GET("/", func(c *gin.Context) {c.JSON(200, map[string]interface{}{"name": "彪子","age": 15,})})router.Run(":8080") // 不写默认,8080,监听并在 0.0.0.0:8080 上启动服务
}

①返回字符串

package main
import "github.com/gin-gonic/gin"
func main() {router := gin.Default()// 类似printf的写法router.GET("/", func(c *gin.Context) {c.String(200, "我的值为:%v", "啊啊啊")})router.Run(":8080") // 不写默认,8080,监听并在 0.0.0.0:8080 上启动服务
}

②返回json

package main
import "github.com/gin-gonic/gin"
func main() {router := gin.Default()router.GET("/", func(c *gin.Context) {c.JSON(200, map[string]interface{}{"name": "彪子","age": 15,})})router.Run(":8080") // 不写默认,8080,监听并在 0.0.0.0:8080 上启动服务
}

或者可以将map类型用gin自带的,和我们写的一样

router.GET("/", func(c *gin.Context) {c.JSON(200,gin.H{"name": "彪子","age": 15,})})

也可以使用结构体

package main
import ("github.com/gin-gonic/gin"
)
type Ariticle struct {Title stringContent string
}
func main() {router := gin.Default()router.LoadHTMLGlob("templates/*") //配置模板文件router.GET("/", func(c *gin.Context) {article := &Ariticle{Title: "这是标题",Content: "这是内容",}c.JSON(200, article)})router.Run(":8080") // 不写默认,8080,监听并在 0.0.0.0:8080 上启动服务
}

二、html渲染

除了上诉的返回字符串和json数据,我们也可以渲染html。

在这里插入图片描述

如果模板目录下存在多个目录,每个目录下含有不同的html文件,那么我们这样操作

在这里插入图片描述

在html定义值

{{ $title := .Title }}
<h1>{{ $title }}</h1>
{{ $sum := 10 + 20 }}
<p>总和:{{ $sum }}</p>

注释

{{/* 这是模板注释,浏览器中看不到 */}}

条件判断

{{ if .IsLogin }}
<p>欢迎回来,{{ .Username }}</p>
{{ else }}
<a href="/login">请登录</a>
{{ end }}
<!-- 否定判断 -->
{{ if not .IsEmpty }}
<p>内容不为空</p>
{{ end }}

循环遍历

<!-- 遍历切片/数组 -->
<ul>
{{ range .Items }}<li>{{ . }}</li> <!-- 内部的 . 代表当前元素 -->
{{ end }}
</ul><!-- 带索引的遍历 -->
<!-- 使用 {{ . }} 时注意上下文变化(如在 range 内部,. 代表当前元素) -->
{{ range $index, $item := .Items }}<p>{{ $index }}: {{ $item.Name }}</p>
{{ end }}<!-- 遍历映射 -->
{{ range $key, $value := .UserInfo }}<p>{{ $key }}: {{ $value }}</p>
{{ end }}<!-- 空集合处理 -->
{{ range .Items }}<li>{{ . }}</li>
{{ else }}<p>没有数据</p> <!-- 当集合为空时执行 -->
{{ end }}

原始html输出

<!-- 假设 .Content 包含 <strong>文本</strong> -->
{{ .Content }} <!-- 输出:&lt;strong&gt;文本&lt;/strong&gt; -->
{{ .Content | safeHTML }} <!-- 输出:<strong>文本</strong> -->

三、gin中get/post获取值

get请求

name:=c.Query("name")
age:=c.DefaultQuery("age","18")

post请求

name := c.PostForm("name")
age := c.DefaultPostForm("age", "18") // 默认值为string类型

将get/post请求的值绑定都按结构体

package mainimport ("net/http""github.com/gin-gonic/gin"
)
// 定义接收参数的结构体
type UserQuery struct {// form标签指定对应的查询参数名Name string `form:"name"`Page int `form:"page" binding:"default=1"` // 默认值1
}
func main() {r := gin.Default()// 注册路由r.GET("/user", func(c *gin.Context) {var query UserQuery// 绑定GET请求参数到结构体if err := c.ShouldBindQuery(&query); err == nil {// 绑定成功,使用参数c.JSON(http.StatusOK, query)return}})// 启动服务r.Run(":8080")
}

动态路由传值

package mainimport ("net/http""github.com/gin-gonic/gin"
)
func main() {r := gin.Default()// 注册路由r.GET("/:uid", func(c *gin.Context) {uid:=c.Param("uid")// 绑定GET请求参数到结构体c.String(http.StatusOK, "uid: %s", uid)})// 启动服务r.Run(":8080")
}

四、路由分组

package mainimport ("net/http""github.com/gin-gonic/gin"
)
func main() {r := gin.Default()// 1. 基础路由分组 - 添加路径前缀userGroup := r.Group("/user"){// 实际路径: /useruserGroup.GET("", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "用户列表"})})// 实际路径: /user/:iduserGroup.GET("/:id", func(c *gin.Context) {id := c.Param("id")c.JSON(http.StatusOK, gin.H{"message": "查看用户", "id": id})})// 实际路径: /user/createuserGroup.POST("/create", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "创建用户"})})}// 2. 带中间件的路由分组// 创建需要身份验证的路由分组authGroup := r.Group("/admin")// 为该分组添加中间件(如身份验证)authGroup.Use(AuthMiddleware()){// 实际路径: /admin/dashboard,访问前会经过AuthMiddleware验证authGroup.GET("/dashboard", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "管理员面板"})})// 实际路径: /admin/settingsauthGroup.GET("/settings", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "系统设置"})})}// 3. 嵌套路由分组v1 := r.Group("/api/v1"){// 嵌套用户分组,实际路径: /api/v1/usersusers := v1.Group("/users"){users.GET("", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "API v1 用户列表"})})}// 嵌套文章分组,实际路径: /api/v1/articlesarticles := v1.Group("/articles"){articles.GET("", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "API v1 文章列表"})})}}r.Run(":8080")
}
// 定义一个身份验证中间件示例
func AuthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {// 实际应用中这里会验证token或sessiontoken := c.GetHeader("Authorization")if token == "" {c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权访问"})c.Abort() // 终止请求处理链return}// 验证通过,继续处理请求c.Next()}
}

如果把不同路由放到不同文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

五、中间件

在这里插入图片描述

c.Next() 的核心作用

流程控制:在中间件中调用 c.Next() 会暂停当前中间件的执行,先执行后续的中间件或路由处理器。

前后置操作: c.Next() 调用前的代码可以视为 “前置操作”(如权限验证、日志记录开始),调用后的代码可以视为 “后置操作”(如日志记录结束、响应处理)。

在这里插入图片描述

全局中间件:可以使后续的所有请求都走此中间件

func main() {r := gin.Default()r.Use(mid1, mid2)// 实际路径: /userr.GET("/", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "成功"})})r.Run(":8080")
}

在分组路由后配置中间件的两种方式

// 方式1
a:=r.Group("admin",mid1, mid2)
// 方式2
a:=r.Group("admin")
a.Use(mid1, mid2)

在不同中间件传递值

在这里插入图片描述

gin中间件中使用grountine

在这里插入图片描述

六、文件上传

单个文件上传

package mainimport ("net/http""os""path/filepath""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 单个文件上传r.POST("/upload", func(c *gin.Context) {// 获取上传的文件file, err := c.FormFile("file")if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "获取文件失败: " + err.Error(),})return}// 定义保存路径(当前目录下的uploads文件夹)savePath := "./uploads"// 确保保存目录存在if err := ensureDir(savePath); err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "创建保存目录失败: " + err.Error(),})return}// 构建完整的保存路径(目录+文件名)dst := filepath.Join(savePath, file.Filename)// 使用SaveUploadedFile保存文件if err := c.SaveUploadedFile(file, dst); err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件失败: " + err.Error(),})return}c.JSON(http.StatusOK, gin.H{"message":  "文件上传成功","filename": file.Filename,"savePath": dst,})})r.Run(":8080")
}// 确保目录存在,不存在则创建
func ensureDir(dir string) error {if _, err := os.Stat(dir); os.IsNotExist(err) {return os.MkdirAll(dir, 0755)}return nil
}

多文件上传

package mainimport ("net/http""os""path/filepath""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 多个文件上传r.POST("/upload-multiple", func(c *gin.Context) {// 解析多部分表单form, err := c.MultipartForm()if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "解析表单失败: " + err.Error(),})return}// 获取所有名为"file"的文件files := form.File["file"]if len(files) == 0 {c.JSON(http.StatusBadRequest, gin.H{"error": "未找到上传的文件",})return}// 定义保存路径savePath := "./uploads"if err := ensureDir(savePath); err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "创建保存目录失败: " + err.Error(),})return}// 保存所有文件uploadedFiles := make([]string, 0, len(files))for _, file := range files {dst := filepath.Join(savePath, file.Filename)if err := c.SaveUploadedFile(file, dst); err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件 " + file.Filename + " 失败: " + err.Error(),})return}uploadedFiles = append(uploadedFiles, file.Filename)}c.JSON(http.StatusOK, gin.H{"message":   "所有文件上传成功","fileCount": len(uploadedFiles),"filenames": uploadedFiles,})})r.Run(":8080")
}// 确保目录存在,不存在则创建
func ensureDir(dir string) error {if _, err := os.Stat(dir); os.IsNotExist(err) {return os.MkdirAll(dir, 0755)}return nil
}

七、gin中的cookie

package mainimport ("net/http""strings""github.com/gin-gonic/gin"
)func main() {r := gin.Default()// 设置Cookier.GET("/set_cookie", func(c *gin.Context) {// 设置一个名为"username",值为"JohnDoe",1小时后过期的Cookiec.SetCookie("username", "JohnDoe", 3600, "/", "example.com", false, true)c.JSON(http.StatusOK, gin.H{"message": "Cookie set successfully"})})// 获取 Cookier.GET("/get_cookie", func(c *gin.Context) {cookie, err := c.Cookie("username")if err != nil {c.JSON(http.StatusOK, gin.H{"message": "Cookie not found", "error": err.Error()})return}c.JSON(http.StatusOK, gin.H{"message": "Cookie retrieved successfully", "username": cookie})})//删除 Cookier.GET("/delete_cookie", func(c *gin.Context) {// 将过期时间设置为1小时前,以达到删除Cookie的效果c.SetCookie("username", "", -3600, "/", "example.com", false, true)c.JSON(http.StatusOK, gin.H{"message": "Cookie deleted successfully"})})// 遍历Cookier.GET("/list_cookies", func(c *gin.Context) {cookies := c.Request.Cookies()var cookieList []stringfor _, cookie := range cookies {cookieList = append(cookieList, cookie.Name+"="+cookie.Value)}c.JSON(http.StatusOK, gin.H{"message": "List of cookies", "cookies": strings.Join(cookieList, ", ")})})r.Run(":8080")
}

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

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

相关文章

基于脚手架微服务的视频点播系统-界面布局部分(二):用户界面及系统管理界面布局

基于脚手架微服务的视频点播系统-界面布局部分:二.首页及播放界面布局一.用户界面布局1.1用户界面布局分析与实现1.2更新用户图像按钮及逻辑1.3修改按钮及逻辑1.4上传视频对话框实现逻辑1.4.1页面跳转逻辑处理1.4.2页面控件响应处理二.系统界面布局2.1系统管理页框架2.2审核管理…

STL库——二叉搜索树

ʕ • ᴥ • ʔ づ♡ど &#x1f389; 欢迎点赞支持&#x1f389; 个人主页&#xff1a;励志不掉头发的内向程序员&#xff1b; 专栏主页&#xff1a;C语言&#xff1b; 文章目录 前言 一、二叉搜索树的概念 二、二叉搜索树的性能分析 三、二叉搜索树的插入 四、二叉搜索树的查…

【Linux】线程概念与控制

一. 线程的概念1.什么是线程线程是进程内部的一个执行流&#xff0c;是进程调度的基本单位。它具有轻量的特点&#xff0c;它的创建和销毁所消耗的资源更少&#xff0c;线程间切换比进程间切换消耗的资源更少&#xff1b;它与进程共享一张虚拟地址空间表&#xff0c;通过进程来…

双轴倾角传感器厂家与物联网角度传感器应用全解析

本文主要探讨双轴倾角传感器厂家的核心技术优势&#xff0c;以及物联网角度传感器在智能监测中的创新应用。同时&#xff0c;也详细介绍了水平监测传感器厂家的解决方案特点&#xff0c;并分析了专业进口倾角传感器代理所提供的原厂品质保障与本地化服务支持。以深圳瑞惯科技有…

容器-资源隔离机制

一. 引言&#xff1a; 大家都知道&#xff0c;在一台机器上&#xff0c;可以运行任意(根据系统资源)个容器实例。且各容器间是相互独立&#xff0c;不做任何关联的。那么&#xff0c;docker是通过什么方式来实现容器隔离的呢&#xff1f; 接下来我们了解下。 二. 关于容器隔离…

Agentic RL Survey: 从被动生成到自主决策

Agentic RL Survey: 从被动生成到自主决策 本文将系统解读《The Landscape of Agentic Reinforcement Learning for LLMs: A Survey》这篇综述。该综述首次将智能体强化学习&#xff08;Agentic RL&#xff09;与传统LLM-RL范式正式区分&#xff0c;通过MDP/POMDP理论框架梳理…

彻底禁用 CentOS 7.9 中 vi/vim 的滴滴声

在 VMware 虚拟机中安装的 CentOS 7.9 系统&#xff0c;即使通过修改 /etc/inputrc 禁用了终端铃声&#xff08;set bell-style none&#xff09;&#xff0c;vi 或 vim 编辑时仍可能发出滴滴声。这是因为 vi/vim 有自己独立的铃声控制机制。以下是解决方法&#xff1a;方法 1&…

基于A2A和ADK的内容规划代理

项目概述 Content Planner Agent 是一个基于 Google Agent Development Kit (ADK) 和 Python A2A SDK 构建的智能内容规划代理。该代理能够根据高层次的内容描述&#xff0c;创建详细的内容大纲。 什么是A2A Protocol A2A Protocol&#xff08;Agent2Agent 协议&#xff09;…

Linux-条件变量

文章目录条件变量概述条件变量的优缺点条件变量相关函数pthread_cond_init函数pthread_cond_destroy函数pthread_cond_wait函数pthread_cond_signal函数测试生产者和消费者模型条件变量 概述 与互斥锁不同&#xff0c;条件变量是用来等待而不是用来上锁的&#xff0c;条件变量…

[硬件电路-166]:Multisim - SPICE与Verilog语言的区别

SPICE与Verilog语言在电子设计领域中扮演不同角色&#xff0c;SPICE是电路仿真语言&#xff0c;用于精确模拟电路行为&#xff1b;Verilog是硬件描述语言&#xff0c;用于描述数字电路的结构和行为。以下是两者的详细区别&#xff1a;一、核心定位与用途SPICE&#xff1a;电路仿…

玩转Docker | 使用Docker部署Umbrel操作系统

玩转Docker | 使用Docker部署Umbrel操作系统 前言 一、 Umbrel 介绍 Umbrel简介 Umbrel主要特点 二、系统要求 环境要求 环境检查 Docker版本检查 检查操作系统版本 三、部署Umbrel服务 下载Umbrel镜像 编辑部署文件 创建容器 检查容器状态 检查服务端口 安全设置 四、访问Umbr…

Flink Task线程处理模型:Mailbox

Task的线程 和 MailboxProcessor 的绑定executingThread 是 Task 类&#xff08;StreamTask 的父类&#xff09;在构造时创建的物理线程。MailboxProcessor 是 StreamTask 用来处理异步事件和驱动其主要处理逻辑&#xff08;processInput&#xff09;的核心组件。它们之间的绑定…

OpenCV 银行卡号识别

目录 一、项目原理与核心技术 二、环境准备与工具包导入 1. 环境依赖 2. 工具包导入 三、自定义工具类 myutils.py 实现 四、主程序核心流程&#xff08;银行卡识别.py&#xff09; 1. 命令行参数设置 2. 银行卡类型映射 3. 辅助函数&#xff1a;图像展示 五、步骤 1…

计算机二级Python

一.静态语言和脚本语言高级语言根据计算机执行机制的不同分为两类&#xff1a;静态语言和脚本语言静态语言的核心特征&#xff1a;变量的类型在编译时&#xff08;写代码时&#xff09;就必须确定并固定下来&#xff0c;即在使用一个变量前必须显式地声明它地类型一旦声明&…

Mybatis Log Plugin打印日志,会导致CPU升高卡死

原因 大量日志输出:MyBatis Log Plugin 会打印大量的 SQL 日志,包括 SQL 语句及其参数。如果项目中 SQL 查询频繁且复杂,日志量会非常大,导致 CPU 使用率升高,甚至卡死。 日志级别设置不当:如果将日志级别设置为 DEBUG 或 TRACE,MyBatis 会输出非常详细的日志信息,这会…

鸿蒙:深色模式适配和浅色模式的切换

前言&#xff1a; 有些时候我们需要对应用进行深色模式的适配处理&#xff0c;并且在不需要的时候切换到浅色状态&#xff0c;下面和大家一起照着官方文档来学习。 下面是官方文档的链接&#xff1a; https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-dark-…

Coze源码分析-资源库-删除插件-后端源码-数据访问和基础设施层

5. 数据访问层 5.1 仓储接口定义 插件仓储接口 文件位置&#xff1a;backend/domain/plugin/repository/plugin.go type PluginRepository interface {// DeleteDraftPlugin 删除插件草稿DeleteDraftPlugin(ctx context.Context, pluginID int64) error// DeleteAPPAllPlugins …

案例一: 对基础选择器的使用【网页盒子】

【1】样例&#xff1a;首先&#xff0c;观察到&#xff0c;几个元素竖着排列的&#xff0c;所以使用块级元素&#xff0c;而不是行内元素。【2】代码演示<head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,…

爬虫项目优化:如何用 Redis 实现 “断点续爬”?避免重复采集电商数据

在电商数据采集场景中&#xff0c;爬虫常因网络波动、服务器重启、IP 封禁等问题中断。若缺乏断点续爬机制&#xff0c;重启后需从头开始&#xff0c;不仅浪费带宽与时间&#xff0c;还可能因重复采集导致数据冗余。Redis 凭借其高性能、原子操作、多样数据结构的特性&#xff…

决策树概念与原理

决策树简介决策树是一种树形结构树中每个内部节点表示一个特征上的判断&#xff0c;每个分支代表一个判断结果的输出&#xff0c;每个叶子节点代表一种分类结果(仅举例无其他意义或隐喻)就像一个女孩去相亲&#xff0c;那么首先询问是否大于30&#xff0c;大于则不见&#xff0…