Go 之 Gin 框架
Gin 是一个 Go (Golang) 编写的轻量级 web 框架,运行速度非常快,擅长 Api 接口的高并发,如果项目的规模不大,业务相对简单,这个时候我们也推荐您使用 Gin,特别适合微服务框架。
简单路由配置
package mainimport ("github.com/gin-gonic/gin"
)func main() {// 创建一个默认的路由引擎r := gin.Default()// 配置路由r.GET("/", func(c *gin.Context) {aid := c.Query("aid")c.JSON(200, gin.H{"username": "name1","aid": aid,"data": []string{"hello", "world"},})})// 启动 HTTP 服务,默认在 0.0.0.0:8080 启动服务r.Run()
}
运行起来以后,在浏览器输入http://127.0.0.1:8080/?aid=xyz,即可获取到 url 请求的结果
{"aid":"xyz","data":["hello","world"],"username":"name1"}
动态路由
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/user/:id", func(c *gin.Context) {id := c.Param("id")c.JSON(200, gin.H{"username": "name1","id": id,"data": []string{"hello", "world"},})})r.Run()
}
请求 url:http://127.0.0.1:8080/user/looking
请求 result:
{"data":["hello","world"],"id":"looking","username":"name1"}
结果响应
c.String()
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/news", func(c *gin.Context) {c.String(200, "Hello world")})r.Run()
}
c.JSON()
大部分时候,我们直接返回 json 的数据格式要更多一些。数据返回我们可以使用 gin.H 的 map 形式,也可以直接用 struct 的形式,不过使用结构体的话,记得要给字段标注好 json 对应的 tag。
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/structJson", func(c *gin.Context) {// 结构体方式var msg struct {Username string `json:"username"`Msg string `json:"msg"`Age string `json:"age"`}msg.Username = "name1"msg.Msg = "msg1"msg.Age = "18"c.JSON(200, msg)})r.Run()
}
c.JSONP()
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/JSONP", func(c *gin.Context) {data := map[string]interface{}{"foo": "bar",}c.JSONP(http.StatusOK, data)})r.Run()
}
请求 url:http://127.0.0.1:8080/JSONP?callback=x
请求 result:
x({"foo":"bar"});
c.HTML()
index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>
<h1>这是一个 html 模板</h1><h3>{{.title}}</h3>
</body>
</html>
渲染之前,先对文件进行 load 加载,框架会自动将变量替换到 html 文件里进行渲染
package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.LoadHTMLFiles("./templates/index.html")r.GET("/index", func(c *gin.Context) {c.HTML(http.StatusOK, "index.html",map[string]interface{}{"title": "前台首页"})})r.Run()
}
http://127.0.0.1:8080/index

请求传值
get查询和动态路由前面已经有示例了,我们看下其他类型的传值。
post获取表单数据
package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.POST("/doAddUser", func(c *gin.Context) {username := c.PostForm("username")password := c.PostForm("password")age := c.DefaultPostForm("age", "20")c.JSON(200, gin.H{"usernmae": username, "password": password, "age": age,})})r.Run()
}
post/get传值绑定到结构体
传值绑定结构体是我们正常开发时最常用的参数解析方式之一了
package mainimport ("fmt""github.com/gin-gonic/gin""net/http"
)type Userinfo struct {Username string `form:"username" json:"user"`Password string `form:"password" json:"password"`
}func main() {r := gin.Default()r.GET("/", func(c *gin.Context) {var userinfo Userinfoif err := c.ShouldBind(&userinfo); err == nil {fmt.Printf("userinfo: %+v\n", userinfo) // userinfo: {Username:zhangsan Password:123456}c.JSON(http.StatusOK, userinfo)} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})r.Run()
}
http://127.0.0.1:8080/?username=zhangsan&password=123456
{"user":"zhangsan","password":"123456"}
同理,POST请求等也可以将请求参数绑定到结构体中
package mainimport ("github.com/gin-gonic/gin""net/http"
)type Userinfo struct {Username string `form:"username" json:"user"`Password string `form:"password" json:"password"`
}func main() {r := gin.Default()r.POST("/doLogin", func(c *gin.Context) {var userinfo Userinfoif err := c.ShouldBind(&userinfo); err == nil {c.JSON(http.StatusOK, userinfo)} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}})r.Run()
}
post获取xml数据
一般请求传递 xml 格式数据的遇到的不多,不过也可以试试。
package mainimport ("fmt""github.com/gin-gonic/gin""net/http"
)type Article struct {Title string `json:"title" xml:"title"`Content string `json:"content" xml:"content"`
}func main() {r := gin.Default()r.POST("/xml", func(ctx *gin.Context) {var article Articleif err := ctx.ShouldBindXML(&article); err == nil {fmt.Printf("article: %+v\n", article)ctx.JSON(http.StatusOK, article)}else {ctx.JSON(http.StatusBadRequest, gin.H {"err": err.Error()})}})r.Run()
}
可以使用 Apifox 发送请求尝试,可以直观看到接口返回的结果

路由分组
路由分组即将相关的路由加上相同的前缀,用以和其他路由进行区分和辨别。
package mainimport ("github.com/gin-gonic/gin"
)func ApiRouter(r *gin.Engine) {apiRouter := r.Group("/api"){apiRouter.GET("/", func(ctx *gin.Context) {ctx.String(200, "api")})apiRouter.GET("articles", func(ctx *gin.Context) {ctx.String(200, "/api/articles")})}
}func main() {r := gin.Default()ApiRouter(r)r.Run()
}
路由分离
路由分离可以将不相关的路由解耦,分离到单独的文件进行维护。
在项目新建文件夹router,然后在router目录下创建apiRouter.go 和adminRouter.go
package router
// apiRouter.go
import "github.com/gin-gonic/gin"func ApiRouter(r *gin.Engine) {apiRouter := r.Group("/api"){apiRouter.GET("/", func(ctx *gin.Context) {ctx.String(200, "api")})apiRouter.GET("articles", func(ctx *gin.Context) {ctx.String(200, "/api/articles")})}
}
package router// adminRouter.go
import ("net/http""github.com/gin-gonic/gin"
)func AdminRouter(r *gin.Engine) {adminRouter := r.Group("/admin"){adminRouter.GET("/", func(ctx *gin.Context) {ctx.String(200, "admin")})adminRouter.GET("list", func(ctx *gin.Context) {ctx.String(http.StatusOK, "admin/list")})}
}
在main.go中引入路由模块并使用即可
package mainimport ("github.com/gin-gonic/gin""github.com/test/router"
)func main() {// 创建一个默认的路由引擎r := gin.Default()// 引入路由模块router.AdminRouter(r)router.ApiRouter(r)// 启动 HTTP 服务,默认在 0.0.0.0:8080 启动服务r.Run()
}
自定义控制器
当我们的项目比较大的时候有必要对我们的控制器进行分组 , 业务逻辑放在控制器中(有的把业务逻辑处理部分称为 handler)。
新建 controller/api/userController.go
package apiimport "github.com/gin-gonic/gin"func UserIndex(c *gin.Context) {c.String(200, "api UserIndex")
}func UserAdd(c *gin.Context) {c.String(200, "api UserAdd")
}func UserList(c *gin.Context) {c.String(200, "api UserList")
}
func UserUpdate(c *gin.Context) {c.String(200, "api UserUpdate")
}func UserDelete(c *gin.Context) {c.String(200, "api UserDelete")
}
apiRouter.go
package router
// apiRouter.go
import ("github.com/gin-gonic/gin""github.com/test/controller/api"
)func ApiRouter(r *gin.Engine) {apiRouter := r.Group("/api"){apiRouter.GET("/")apiRouter.GET("/users", api.UserIndex)apiRouter.GET("/users/:id", api.UserList)apiRouter.POST("/users", api.UserAdd)apiRouter.PUT("/users/:id", api.UserUpdate)apiRouter.DELETE("/users", api.UserDelete)}
}
控制器继承
要让控制器可以继承,最好将控制器做成方法的形式(一般默认是函数的形式),这样的话,就可以根据结构体的匿名字段,实现对继承结构体的方法进行很方便的调用。
baseController.go
package apiimport "github.com/gin-gonic/gin"type BaseController struct {
}func (con BaseController) Success(c *gin.Context) {c.String(200, "success")
}func (con BaseController) Error(c *gin.Context) {c.String(200, "failed")
}
userController.go
package apiimport "github.com/gin-gonic/gin"type UserController struct {BaseController
}func (con UserController) UserIndex(c *gin.Context) {// c.String(200, "api UserIndex")con.Success(c)
}func (con UserController) UserAdd(c *gin.Context) {c.String(200, "api UserAdd")
}func (con UserController) UserList(c *gin.Context) {c.String(200, "api UserList")
}
func (con UserController) UserUpdate(c *gin.Context) {c.String(200, "api UserUpdate")
}func (con UserController) UserDelete(c *gin.Context) {c.String(200, "api UserDelete")
}
apiRouter.go
package router
// apiRouter.go
import ("github.com/gin-gonic/gin""github.com/test/controller/api"
)func ApiRouter(r *gin.Engine) {apiRouter := r.Group("/api"){apiRouter.GET("/")apiRouter.GET("/index", api.UserController{}.UserIndex)apiRouter.GET("/users", api.UserController{}.UserList)apiRouter.GET("/users/:id", api.UserController{}.UserList)apiRouter.POST("/users", api.UserController{}.UserAdd)apiRouter.PUT("/users/:id", api.UserController{}.UserUpdate)apiRouter.DELETE("/users", api.UserController{}.UserDelete)}
}
To be continued
相关文章:
Go 之 Gin 框架
Gin 是一个 Go (Golang) 编写的轻量级 web 框架,运行速度非常快,擅长 Api 接口的高并发,如果项目的规模不大,业务相对简单,这个时候我们也推荐您使用 Gin,特别适合微服务框架。 简单路由配置 package mai…...
vue3+threejs新手从零开发卡牌游戏(二十一):添加战斗与生命值关联逻辑
首先将双方玩家的HP存入store中,stores/common.ts代码如下: import { ref, computed } from vue import { defineStore } from piniaexport const useCommonStore defineStore(common, () > {const _font ref() // 字体const p1HP ref(4000) // 己…...
Linux内核err.h文件分析
在阅读和编写内核相关的代码时,经常会看到IS_ERR、ERR_PTR等函数。这些函数在内核头文件的err.h中。以我服务器的代码为例,内核版本为5.15。 这个文件的代码如下: /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_ERR_H #define _L…...
Qt 富文本处理 (字体颜色大小加粗等)
Qt中支持HTML的控件有textEdit 、label 、textBrowser 。 接口:setHtml("Qt"); toHtml(). 文本样式设置 : 可分字设置 ,主要使用QTextCharFormat类进行文本样式设置。 示例: QTextCharFormat fmt; //粗体 fmt.setFontWeight…...
消息队列的七种经典应用场景
在笔者心中,消息队列,缓存,分库分表是高并发解决方案三剑客。 在职业生涯中,笔者曾经使用过 ActiveMQ 、RabbitMQ 、Kafka 、RocketMQ 这些知名的消息队列 。 这篇文章,笔者结合自己的真实经历,和大家分享…...
uniapp 微信小程序 canvas 手写板文字重复倾斜水印
核心逻辑 先将坐标系中心点通过ctx.translate(canvasw / 2, canvash / 2) 平移到canvas 中心,再旋转设置水印 假如不 translate 直接旋转,则此时的旋转中心为左上角原点,此时旋转示意如图所示 当translate到中心点之后再旋转,此…...
JavaScript如何制作轮播图
在JavaScript中实现轮播图可以通过多种方式,但最常见的方式是使用数组来存储图片,然后使用setInterval函数定期更改显示的图片。下面是一个简单的例子: 首先,你需要在HTML中设置一些用于显示图片的<img>标签,以…...
【面试经典150 | 动态规划】零钱兑换
文章目录 Tag题目来源解题思路方法一:动态规划 写在最后 Tag 【动态规划】【数组】 题目来源 322. 零钱兑换 解题思路 方法一:动态规划 定义状态 dp[i] 表示凑成总金额的最少硬币个数。 状态转移 从小到大枚举要凑成的金额 i,如果当前…...
什么是防火墙,部署防火墙有什么好处?
与我们的房屋没有围墙或界限墙一样,没有防护措施的计算机和网络将容易受到黑客的入侵,这将使我们的网络处于巨大的风险之中。因此,就像围墙保护我们的房屋一样,虚拟墙也可以保护和安全我们的设备,使入侵者无法轻易进入…...
学习鸿蒙基础(10)
目录 一、轮播组件 Swiper 二、列表-List 1、简单的List 2、嵌套的List 三、Tabs容器组件 1、系统自带tabs案例 2、自定义导航栏: 一、轮播组件 Swiper Entry Component struct PageSwiper {State message: string Hello Worldprivate SwCon: SwiperControl…...
阿里云对象存储OSS入门
阅读目录 一、阿里云OSS的使用 1、OSS是什么?2、OSS的使用 二、阿里云OSS的使用三、图床的搭建四:图床绑定阿里云OSS 编写不易,如果我的文章对你有帮助的话,麻烦小伙伴还帮忙点个赞再走! 如果有小伙伴觉得写的啰嗦&a…...
[幻灯片]软件需求设计方法学全程实例剖析-03-业务用例图和业务序列图
DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 pdf已上传至本号的CSDN资源,或到以下地址下载: http://umlchina.com/training/umlchina_03_bm.pdf...
ctfshow-web入门-xxe
什么是xxe? XXE,全称XML External Entity Injection,即XML外部实体注入。这是一种针对应用程序解析XML输入类型的攻击。当包含对外部实体的引用的XML输入被弱配置的XML解析器处理时,就会发生这种攻击。这种攻击通过构造恶意内容&…...
Docker数据卷挂载
一、容器与数据耦合的问题: 数据卷是虚拟的,不真实存在的,它指向文件中的文件夹 ,属主机文件系统通过数据卷和容器数据进行联系,你改变我也改变。 解决办法: 对宿主机文件系统内的文件进行修改,会立刻反应…...
QT_day4:对话框
1、完善对话框,点击登录对话框,如果账号和密码匹配,则弹出信息对话框,给出提示”登录成功“,提供一个Ok按钮,用户点击Ok后,关闭登录界面,跳转到其他界面 如果账号和密码不匹配&…...
矢量数据库:连接人工智能应用程序的数据复杂性与可用性的桥梁
关注我的公众号:Halo咯咯 简介 矢量数据库是一种专门设计的数据库,专注于高效地存储、管理和操作矢量数据。与传统数据库处理标量值(如数字、字符串、日期)不同,矢量数据库针对的是那些表现为多维数据点的向量…...
docker:can’t create unix socket /var/run/docker.sock: is a directory
docker:can’t create unix socket /var/run/docker.sock: is a directory 原因:docker.sock不能创建 解决方式: rm -rf /var/run/docker.sock 然后重新启动docker Docker是一种相对使用较简单的容器,我们可以通过以下几种方式获取信息&…...
Qt 图形视图 /图形视图框架坐标系统的设计理念和使用方法
文章目录 概述Qt 坐标系统图形视图的渲染过程Item图形项坐标系Scene场景坐标系View视图坐标系map坐标映射场景坐标转项坐标视图坐标转图形项坐标图形项之间的坐标转换 其他 概述 The Graphics View Coordinate System 图形视图坐标系统是Qt图形视图框架的重要组成部分…...
视频号小店类目资质如何申请?新手看一遍就懂了!
我是电商珠珠 大家在视频号小店后台新增商品的时候,需要先完成类目资质的申请,通过后才可以上架相关商品。 而类目资质分为普通类目和特殊类目,如果你所上架的商品属于开放类目,那么就去按照普通类目资质去申请。 如果是定向准…...
整合SpringSecurity+JWT实现登录认证
一、关于 SpringSecurity 在 Spring Boot 出现之前,SpringSecurity 的使用场景是被另外一个安全管理框架 Shiro 牢牢霸占的,因为相对于 SpringSecurity 来说,SSM 中整合 Shiro 更加轻量级。Spring Boot 出现后,使这一情况情况大有…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
