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 出现后,使这一情况情况大有…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...