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 出现后,使这一情况情况大有…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
Android屏幕刷新率与FPS(Frames Per Second) 120hz
Android屏幕刷新率与FPS(Frames Per Second) 120hz 屏幕刷新率是屏幕每秒钟刷新显示内容的次数,单位是赫兹(Hz)。 60Hz 屏幕:每秒刷新 60 次,每次刷新间隔约 16.67ms 90Hz 屏幕:每秒刷新 90 次,…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...

WinUI3开发_使用mica效果
简介 Mica(云母)是Windows10/11上的一种现代化效果,是Windows10/11上所使用的Fluent Design(设计语言)里的一个效果,Windows10/11上所使用的Fluent Design皆旨在于打造一个人类、通用和真正感觉与 Windows 一样的设计。 WinUI3就是Windows10/11上的一个…...