当前位置: 首页 > news >正文

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 框架&#xff0c;运行速度非常快&#xff0c;擅长 Api 接口的高并发&#xff0c;如果项目的规模不大&#xff0c;业务相对简单&#xff0c;这个时候我们也推荐您使用 Gin&#xff0c;特别适合微服务框架。 简单路由配置 package mai…...

vue3+threejs新手从零开发卡牌游戏(二十一):添加战斗与生命值关联逻辑

首先将双方玩家的HP存入store中&#xff0c;stores/common.ts代码如下&#xff1a; import { ref, computed } from vue import { defineStore } from piniaexport const useCommonStore defineStore(common, () > {const _font ref() // 字体const p1HP ref(4000) // 己…...

Linux内核err.h文件分析

在阅读和编写内核相关的代码时&#xff0c;经常会看到IS_ERR、ERR_PTR等函数。这些函数在内核头文件的err.h中。以我服务器的代码为例&#xff0c;内核版本为5.15。 这个文件的代码如下&#xff1a; /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_ERR_H #define _L…...

Qt 富文本处理 (字体颜色大小加粗等)

Qt中支持HTML的控件有textEdit 、label 、textBrowser 。 接口&#xff1a;setHtml("Qt"); toHtml(). 文本样式设置 : 可分字设置 &#xff0c;主要使用QTextCharFormat类进行文本样式设置。 示例&#xff1a; QTextCharFormat fmt; //粗体 fmt.setFontWeight…...

消息队列的七种经典应用场景

在笔者心中&#xff0c;消息队列&#xff0c;缓存&#xff0c;分库分表是高并发解决方案三剑客。 在职业生涯中&#xff0c;笔者曾经使用过 ActiveMQ 、RabbitMQ 、Kafka 、RocketMQ 这些知名的消息队列 。 这篇文章&#xff0c;笔者结合自己的真实经历&#xff0c;和大家分享…...

uniapp 微信小程序 canvas 手写板文字重复倾斜水印

核心逻辑 先将坐标系中心点通过ctx.translate(canvasw / 2, canvash / 2) 平移到canvas 中心&#xff0c;再旋转设置水印 假如不 translate 直接旋转&#xff0c;则此时的旋转中心为左上角原点&#xff0c;此时旋转示意如图所示 当translate到中心点之后再旋转&#xff0c;此…...

JavaScript如何制作轮播图

在JavaScript中实现轮播图可以通过多种方式&#xff0c;但最常见的方式是使用数组来存储图片&#xff0c;然后使用setInterval函数定期更改显示的图片。下面是一个简单的例子&#xff1a; 首先&#xff0c;你需要在HTML中设置一些用于显示图片的<img>标签&#xff0c;以…...

【面试经典150 | 动态规划】零钱兑换

文章目录 Tag题目来源解题思路方法一&#xff1a;动态规划 写在最后 Tag 【动态规划】【数组】 题目来源 322. 零钱兑换 解题思路 方法一&#xff1a;动态规划 定义状态 dp[i] 表示凑成总金额的最少硬币个数。 状态转移 从小到大枚举要凑成的金额 i&#xff0c;如果当前…...

什么是防火墙,部署防火墙有什么好处?

与我们的房屋没有围墙或界限墙一样&#xff0c;没有防护措施的计算机和网络将容易受到黑客的入侵&#xff0c;这将使我们的网络处于巨大的风险之中。因此&#xff0c;就像围墙保护我们的房屋一样&#xff0c;虚拟墙也可以保护和安全我们的设备&#xff0c;使入侵者无法轻易进入…...

学习鸿蒙基础(10)

目录 一、轮播组件 Swiper 二、列表-List 1、简单的List 2、嵌套的List 三、Tabs容器组件 1、系统自带tabs案例 2、自定义导航栏&#xff1a; 一、轮播组件 Swiper Entry Component struct PageSwiper {State message: string Hello Worldprivate SwCon: SwiperControl…...

阿里云对象存储OSS入门

阅读目录 一、阿里云OSS的使用 1、OSS是什么&#xff1f;2、OSS的使用 二、阿里云OSS的使用三、图床的搭建四&#xff1a;图床绑定阿里云OSS 编写不易&#xff0c;如果我的文章对你有帮助的话&#xff0c;麻烦小伙伴还帮忙点个赞再走&#xff01; 如果有小伙伴觉得写的啰嗦&a…...

[幻灯片]软件需求设计方法学全程实例剖析-03-业务用例图和业务序列图

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 pdf已上传至本号的CSDN资源&#xff0c;或到以下地址下载&#xff1a; http://umlchina.com/training/umlchina_03_bm.pdf...

ctfshow-web入门-xxe

什么是xxe&#xff1f; XXE&#xff0c;全称XML External Entity Injection&#xff0c;即XML外部实体注入。这是一种针对应用程序解析XML输入类型的攻击。当包含对外部实体的引用的XML输入被弱配置的XML解析器处理时&#xff0c;就会发生这种攻击。这种攻击通过构造恶意内容&…...

Docker数据卷挂载

一、容器与数据耦合的问题: 数据卷是虚拟的&#xff0c;不真实存在的&#xff0c;它指向文件中的文件夹 &#xff0c;属主机文件系统通过数据卷和容器数据进行联系&#xff0c;你改变我也改变。 解决办法&#xff1a; 对宿主机文件系统内的文件进行修改&#xff0c;会立刻反应…...

QT_day4:对话框

1、完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码不匹配&…...

矢量数据库:连接人工智能应用程序的数据复杂性与可用性的桥梁

关注我的公众号&#xff1a;Halo咯咯 简介 矢量数据库是一种专门设计的数据库&#xff0c;专注于高效地存储、管理和操作矢量数据。与传统数据库处理标量值&#xff08;如数字、字符串、日期&#xff09;不同&#xff0c;矢量数据库针对的是那些表现为多维数据点的向量&#xf…...

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 原因&#xff1a;docker.sock不能创建 解决方式&#xff1a; rm -rf /var/run/docker.sock 然后重新启动docker Docker是一种相对使用较简单的容器&#xff0c;我们可以通过以下几种方式获取信息&…...

Qt 图形视图 /图形视图框架坐标系统的设计理念和使用方法

文章目录 概述Qt 坐标系统图形视图的渲染过程Item图形项坐标系Scene场景坐标系View视图坐标系map坐标映射场景坐标转项坐标视图坐标转图形项坐标图形项之间的坐标转换 其他 概述 The Graphics View Coordinate System 图形视图坐标系统是Qt图形视图框架的重要组成部分&#xf…...

视频号小店类目资质如何申请?新手看一遍就懂了!

我是电商珠珠 大家在视频号小店后台新增商品的时候&#xff0c;需要先完成类目资质的申请&#xff0c;通过后才可以上架相关商品。 而类目资质分为普通类目和特殊类目&#xff0c;如果你所上架的商品属于开放类目&#xff0c;那么就去按照普通类目资质去申请。 如果是定向准…...

整合SpringSecurity+JWT实现登录认证

一、关于 SpringSecurity 在 Spring Boot 出现之前&#xff0c;SpringSecurity 的使用场景是被另外一个安全管理框架 Shiro 牢牢霸占的&#xff0c;因为相对于 SpringSecurity 来说&#xff0c;SSM 中整合 Shiro 更加轻量级。Spring Boot 出现后&#xff0c;使这一情况情况大有…...

【操作系统】第三章 内存管理(一)

第三章 内存管理 3.1 内存管理概念 3.1.1 内存管理的基本原理和要求 内存管理的主要功能&#xff1a; 内存空间的分配与回收。[连续分配管理方式](#3.1.2 连续分配管理方式)和非连续分配管理方式&#xff08;分页、分段&#xff09;地址转换&#xff1a;实现逻辑地址到物理…...

java打卡学习3:ArrayList扩容机制

ArrayList扩容机制概述ArrayList是基于动态数组实现的集合类&#xff0c;当元素数量超过当前数组容量时&#xff0c;会自动触发扩容机制。其核心目的是平衡内存占用与性能开销。默认初始容量未指定初始容量时&#xff0c;默认创建一个空数组&#xff08;JDK 1.8&#xff09;&am…...

字节开源AI神器DeerFlow,4.1万星标刷屏,普通人免费就能用

文章目录这玩意儿不是ChatGPT那种"嘴炮型"选手35k星标怎么来的&#xff1f;字节这次把"龙虾"养明白了多智能体协作&#xff1a;不是一个人在战斗沙箱执行&#xff1a;让AI真的"动手"干活对比OpenAI&#xff1a;免费、本地、可控普通人怎么上手&a…...

3分钟搞定Vue时间轴组件:打造优雅时间线应用的终极指南

3分钟搞定Vue时间轴组件&#xff1a;打造优雅时间线应用的终极指南 【免费下载链接】timeline-vuejs Minimalist Timeline ⏳ with VueJS &#x1f49a; 项目地址: https://gitcode.com/gh_mirrors/ti/timeline-vuejs 还在为Vue项目中的时间线展示而烦恼吗&#xff1f;t…...

FireRedASR-AED-L在Windows系统的部署问题解决方案

FireRedASR-AED-L在Windows系统的部署问题解决方案 1. 引言 如果你正在Windows系统上尝试部署FireRedASR-AED-L这个强大的语音识别模型&#xff0c;可能会遇到各种让人头疼的问题。环境配置、依赖冲突、GPU兼容性——这些都是Windows环境下部署深度学习模型时常见的拦路虎。 …...

Verilog进阶实战:独热码状态机设计序列检测器的核心技巧

1. 独热码状态机的设计哲学 第一次接触独热码(One-Hot)编码时&#xff0c;我盯着那串只有一个1的状态编码看了半天——这不就是硬件版的"单选题"吗&#xff1f;每个状态都有自己的专属VIP通道&#xff0c;这种设计理念在中小规模状态机中简直是降维打击。记得去年做电…...

STM32上如何用串口BREAK中断优雅处理DMX与RDM协议(附完整代码)

STM32串口BREAK中断实现DMX/RDM协议双模通信实战指南 舞台灯光控制系统对实时性和可靠性有着近乎苛刻的要求。作为行业标准的DMX512协议及其扩展协议RDM&#xff0c;承载着数以万计舞台灯具的控制指令。传统基于STM32的软件轮询检测方案常面临响应延迟、误触发等问题&#xff0…...

哔哩下载姬DownKyi:新手快速上手指南与实战技巧

哔哩下载姬DownKyi&#xff1a;新手快速上手指南与实战技巧 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印等&#xff09;…...

Phi-4-Reasoning-Vision从零开始:双卡4090环境nvidia-smi调优

Phi-4-Reasoning-Vision从零开始&#xff1a;双卡4090环境nvidia-smi调优 1. 项目概述 Phi-4-Reasoning-Vision是基于微软Phi-4-reasoning-vision-15B多模态大模型开发的高性能推理工具&#xff0c;专为双卡4090环境优化。这个工具严格遵循官方SYSTEM PROMPT规范&#xff0c;…...

从零开始:SpaCy安装与模型下载的完整流程(含版本查询技巧)

从零开始&#xff1a;SpaCy安装与模型下载的完整流程&#xff08;含版本查询技巧&#xff09; 自然语言处理&#xff08;NLP&#xff09;正在改变我们与计算机交互的方式&#xff0c;而SpaCy作为这一领域的明星工具库&#xff0c;以其高效性和易用性赢得了众多开发者的青睐。无…...