golang——Gin框架及路由介绍

一. 框架介绍

        Gin是一个轻量级的Go语言Web框架,它具有高性能和简洁的设计。由于其快速的路由匹配和处理性能,Gin成为Go语言中最受欢迎的Web框架之一。

        特点:

  • 快速和轻量:Gin框架的设计注重性能和效率,采用了一些优化措施,使其成为一个快速而轻量级的框架。
  • 路由和中间件:Gin提供了强大的路由功能,支持参数传递,路由分组等特性。同时,它支持中间件的使用,可以方便的在请求处理过程中执行一系列的操作,比如身份验证,日志记录等。
  • json解析:Gin内置了对json的解析和序列化支持,使得处理json数据变得简单而高效。
  • 支持插件:Gin允许开发者通过插件来扩展框架的功能,这样可以根据项目的需求进行灵活定制。

文档:

  • Github地址:https://github.com/gin-gonic/gin
  • 中文文档:https://gin-gonic.com/zh-cn/docs/

 二. 安装

        要安装Gin软件包,您需要安装Go并首先设置Go工作区。

  • 命令安装Gin
go get github.com/gin-gonic/gin@latest
  • 导入代码
import "github.com/gin-gonic/gin"

 三. 第一个Gin应用

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	//将应用切换到“发布模式”以提升性能
	gin.SetMode(gin.ReleaseMode)
	//创建路由
	r := gin.Default()
	//绑定路由规则,执行函数
	//gin.Context,封装了request和response
	r.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "hello world")
	})

	//监听端口,默认绑定端口8080
	r.Run(":8080")
}

代码解释:

  • gin.Default:创建一个Gin引擎。gin.Default()返回一个带有默认中间件的Gin引擎,包括Logger和Recovery中间件,用于日志记录和恢复。
  •  r.Get("/", func(c *gin.Context){...}):定义了一个GET方法的路由,当访问路径是"/"时,执行后面的回调函数。
  • c.String(http.StatusOK, "hello world"):在回调函数中,通过c.String方法返回一个字符串"hello world"并设置HTTP状态码为200 OK。
  • s.Run(":8080"):启动Web服务,监听在0.0.0.0:8080。如果不指定端口号,默认使用8080端口。此时,你可以通过浏览器或HTTP客户端访问http://localhost:8080,将会得到"hello world"的响应。

四. 应用举例

        以下项目都是使用Gin框架开发的:

  • gorush:Go 编写的通知推送服务器。
  • fnproject:容器原生,云 serverless 平台。
  • photoprism:基于 Go 和 Google TensorFlow 实现的个人照片管理工具。
  • krakend:拥有中间件的超高性能 API 网关。
  • picfit:Go 编写的图像尺寸调整服务器。
  • gotify:基于 WebSocket 进行实时消息收发的简单服务器。
  • cds:企业级持续交付和 DevOps 自动化开源平台。

五. Gin入门

  • gin.Engine

        在Gin里面,一个Web服务器被抽象成了Engnie。你可以在一个应用里面创建多个Engine实例,监听不同的端口。Engine承担了路由注册,接入中间件的核心职责。

        它组合了RouterGroup,RouterGroup才是实现路由功能的核心组件。

  • gin.Context

        gin.Context是Gin里面的核心类型。字面意思是"上下文",在Gin里面的核心职责是:

  • 处理请求
  • 返回响应 

六. 路由

        6.1 介绍

  • gin框架中采用的路由库是基于httprouter做的
  • 地址为:https://github.com/julienschmidt/httprouter
  •  支持Restful风格的API,意思是"表面层状态转化",是一个互联网应用程序的API设计理念:URL定位资源。
  • 可以创建路由组,为了管理相同的URL。
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	//将应用切换到“发布模式”以提升性能
	gin.SetMode(gin.ReleaseMode)
	//创建路由
	//默认使用了两个中间件Logger(),Recovery()
	r := gin.Default()

	r.GET("/hello1", func(c *gin.Context) {
		c.String(http.StatusOK, "hello1")
	})
	r.GET("/hello2", func(c *gin.Context) {
		c.String(http.StatusOK, "hello2")
	})

	//路由组1
	v1 := r.Group("/v1")
	{
		v1.GET("/hellov1", func(c *gin.Context) {
			c.String(http.StatusOK, "hello v1")
		})
		v1.GET("hellov11", func(c *gin.Context) {
			c.String(http.StatusOK, "hello v11")
		})
	}

	//路由组2
	v2 := r.Group("/v2")
	{
		v2.GET("/hellov2", func(c *gin.Context) {
			c.String(http.StatusOK, "hello v2")
		})

		v2.POST("/hellov22", func(c *gin.Context) {
			c.String(http.StatusOK, "hello v22")
		})
	}

	//监听端口,默认绑定端口8080
	r.Run(":8080")
}

        6.2  API参数 

  • 可以通过Context的Param方法来获取API参数
package main

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/user/:name/*action", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Param("action")

		fmt.Println(name, ":", action) //对于url /user/wy/aa 打印 wy : /aa
		//去除/
		action = strings.Trim(action, "/")
		c.String(http.StatusOK, name+" is "+action)
	})
	r.Run()
}

        6.3 URL参数

  • URL参数可以通过DefaultQuery()或Query方法获取
  • DefaultQuery()若参数不存在,返回默认值。Query()若参数不存在,返回空串。
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/user", func(c *gin.Context) {
		name := c.Query("name")
		action := c.DefaultQuery("action", "")

		c.String(http.StatusOK, name+" is "+action)
	})
	r.Run()
}

        6.4 表单参数

  • 表单传输参数为POST请求,http常见的传输格式为四种:

    • application/json

    • application/x-www-form-urlencode

    • application/xml

    • mulipart/form-data

  • 表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencode或form-data格式的参数。

POST请求的html代码:

<!--test.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="/form" method="post"
action="application/x-www-form-urlencoded">
用户名:<input type="text" name="username" placeholder="请输入你的用户名">
<br>密&nbsp;&nbsp;&nbsp;码:<input type="password" name="userpassword"
placeholder="请输入你的密码"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>

服务端代码

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	//设置HTML文件所在目录
	r.LoadHTMLGlob("./*.html")
	//设置GET方法路由,成功返回test.html文件
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "test.html", nil)
	})

	//设置POST方法路由
	r.POST("/form", func(c *gin.Context) {
		//设置没有传的参数的默认值
		types := c.DefaultPostForm("type", "post")
		username := c.PostForm("username")
		password := c.PostForm("userpassword")

		c.String(http.StatusOK, "username:%s, userpassword:%s, types:%s", username, password, types)
	})

	r.Run()
}

演示:

         6.5 上传文件

上传单个文件:

  • multipart/form-data格式用于上传文件
  • gin文件上传与原生的net/http方法类似,不同在于gin吧原生的request封装到了c.Request中。
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	//设置HTML文件所在目录
	r.LoadHTMLGlob("./*.html")
	//设置GET方法路由,成功返回test.html文件
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "test.html", nil)
	})

	//设置POST方法路由
	r.MaxMultipartMemory = 8 << 20 //限制上传最大尺寸
	r.POST("/upload", func(c *gin.Context) {
		//用于获取表单信息中file格式的参数,并且返回一个文件流
		file, err := c.FormFile("file") //html中的name
		if err != nil {
			c.String(500, "上次图片错误")
		}
		//参数1为指定需要保存操作的文件,参数2为指定保存路径。
		c.SaveUploadedFile(file, file.Filename)
		//返回文件名
		c.String(http.StatusOK, file.Filename)

	})

	r.Run()
}

 演示:

上传特定文件:

        有的用户上传文件需要限制文件的类型以及上传文件的大小,可以基于原生的函数写法自己写一个可以限制大小以及文件类型的上传函数。

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.LoadHTMLGlob("./*.html")
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "test.html", nil)
	})

	r.POST("/upload", func(c *gin.Context) {
		_, header, err := c.Request.FormFile("file")
		if err != nil {
			c.String(405, "文件错误")
			return
		}

		if header.Size > 1024*1024*2 {
			c.String(406, "文件太大")
			return
		}

		if header.Header.Get("Content-Type") != "image/png" {
			c.String(407, "只允许上传图片")
			return
		}

		c.SaveUploadedFile(header, header.Filename)
		c.String(http.StatusOK, header.Filename)
	})

	r.Run()
}

上传多个文件:

package main

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.LoadHTMLGlob("./*.html")
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "test.html", nil)
	})
	//限制表单上传大小8MB 默认32MB
	r.MaxMultipartMemory = 8 << 20 * 2
	r.POST("/upload", func(c *gin.Context) {
		//用于获取multipart表单。当用户通过表单上传文件时,浏览器通常会将表单编码为multipart/form-data格式。
		form, err := c.MultipartForm()
		if err != nil {
			c.String(http.StatusBadRequest, fmt.Sprintf("get a %v", err))
			return
		}
		//获取所有文件
		files := form.File["files"]
		//遍历所有文件
		for _, file := range files {
			if err := c.SaveUploadedFile(file, file.Filename); err != nil {
				c.String(http.StatusBadRequest, fmt.Sprintf("upload get a %v", err))
				return
			}
		}
		c.String(http.StatusOK, fmt.Sprintf("upload %d files ok", len(files)))
	})

	r.Run()
}

         6.6 路由原理

        httprouter会将所有路由规则构造一棵前缀树。

        例如有root,and,as,at,cn,com

        6.7 路由拆分与注册

  • 基本的路由注册

         下面最基础的gin路由注册方式,使用于路由条目比较少的简单项目或者项目demo。

package main

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
)

func sayHello(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"message": "hello go",
	})
}

func main() {
	r := gin.Default()
	r.GET("/hello", sayHello)
	if err := r.Run(); err != nil {
		fmt.Printf("startup server err : %v", err)
	}
}
  • 路由拆分成单独文件或包 

        当项目的规模增大后,就不适合继续在项目的main.go文件中实现路由注册相关逻辑了,我们会倾向于把路由部分的代码都拆分出来,形成一个单独的文件或包。

  • 形成单独文件

  • 形成独立的包 

  • 拆分成多个文件

        当业务规模继续膨胀,单独的一个router文件或包已经满足不了我们的需求了。 因为我们把所有的路由注册都写在一个SetRouter函数中的话会很复杂。

        我们可以将其拆分为多个文件。

  • 路由拆分到不同APP 

        有时候项目规模太大,那么我们就更倾向于把业务拆分的更加详细,例如把不同的业务代码拆分成不同的APP。

        因此我们在项目目录下单独定义一个app目录,用来存放我们不同业务线的代码文件,这样就很容易进行横向扩展。

目录结构:

app/blog:

代码如下: 

gin/app/shop: 

 gin/router/router.go

 gin/main.go

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

02-二进制转换,原码 反码 补码

二进制是什么? 为什么用二进制? 计算机底层只能识别二进制。 计算机底层只识别二进制是因为计算机内部的电子元件只能识别两种状态&#xff0c;即开和关&#xff0c;或者高电平和低电平。 二进制正好可以用两种状态来表示数字和字符&#xff0c;因此成为了计算机最基本的表示…

收银系统源码-千呼新零售2.0【宠物、养生、大健康行业解决方案】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物、中医养生、大健康等连锁店…

28. 深度学习中的损失函数:起源、分类及统一理解

在深度学习和机器学习领域&#xff0c;损失函数&#xff08;Loss Function&#xff09;是优化问题的核心&#xff0c;决定了模型参数的调整方向和幅度。尽管损失函数种类繁多&#xff0c;但理解其起源和背后的理论有助于我们更好地选择和应用它们。 损失函数的起源 所有的优化…

【Linux】Wmware Esxi磁盘扩容

目录 一、概述 1.1 磁盘分区概念 1.2 LVM概念 二、扩容步骤 二、报错 一、概述 1.1 磁盘分区概念 在 Linux 中&#xff0c;每一个硬件设备都映射到一个系统的文件&#xff0c;对于硬盘、光驱等 IDE 或 SCSI 设备也不例外。Linux把各种 IDE 设备分配了一个由 hd 前缀组成的文…

深度解析:ChatGPT是如何理解和生成自然语言文章的?

引言 随着人工智能的发展&#xff0c;ChatGPT作为一种先进的自然语言处理工具&#xff0c;正逐渐改变人们与技术交互的方式。那么&#xff0c;ChatGPT是如何理解和生成自然语言文章的&#xff1f;本文将从其技术原理、训练过程、实际应用等多个角度&#xff0c;深入解析这一过…

mysql GROUP_CONCAT分组连接

文章目录 GROUP_CONCAT 分组连接GROUP_CANCAT 的使用分班级列出名单分班级列出名单并包含显示性别组合IFNULL组合IF组合case when GROUP_CONCAT 分组连接 准备的数据示例 CREATE TABLE students (id int(11) NOT NULL AUTO_INCREMENT,name varchar(20) DEFAULT NULL,classNa…

ArcGIS Pro三维空间分析、专题制图、遥感制图全流程系统教学

ESRI宣布&#xff1a;ArcGIS 10.8.2 是 ArcMap 的当前版本&#xff0c;在 2026 年 3 月 1 日之前将继续受支持。我们没有计划在 2021/22 年随 ArcGIS 版本一起发布 ArcMap 10.9.x。这意味着 10.8.x 系列将是 ArcMap 的最终版本系列&#xff0c;并将在 2026 年 3 月 1 日之前受支…

KING大咖直播 | 人大金仓深度解析KES执行计划缓存

对数据库查询迟缓深感困扰&#xff1f; 担心高并发场景下数据库性能拖后腿&#xff1f; &#x1f645;别再烦恼了~ 执行计划缓存功能正是你的救星✨ KES执行计划缓存 减少SQL查询的解析和优化时间 让你的数据库 在高并发场景下依然保持高性能&#xff01; 6月27日19:30-20:30 锁…

10个国内免费AI绘画网站汇总【2024最新】

迎战MidJourney和Stable Diffusion&#xff1a;10款国产AI绘画神器&#xff0c;让你轻松创作出超凡艺术品&#xff01;不论你是初学者还是资深艺术家&#xff0c;这些AI绘画平台都能帮你轻松入门。快来探索这些AI绘画网站&#xff0c;释放你的创意潜能&#xff01; 1、AI绘画创…

algorithm中常见算法

1、前言 C的<algorithm>库是C标准库中的一个重要组成部分&#xff0c;它提供了一系列的函数&#xff0c;用于执行各种常见的算法操作&#xff0c;比如排序、查找、替换、合并等。这些算法函数通常以模板函数的形式提供&#xff0c;可以用于任何符合特定条件的容器类型。 …

SaaS技术解析:如何构建高效、安全的软件即服务解决方案

摘要&#xff1a;随着云计算技术的飞速发展&#xff0c;软件即服务&#xff08;Software as a Service&#xff0c;简称SaaS&#xff09;作为一种新兴的软件应用模式&#xff0c;正逐渐改变着企业信息化的格局。本文将对SaaS技术进行深入解析&#xff0c;探讨如何构建高效、安全…

校园巡礼:一周只上四天课,入学即发钱?深圳理工大学,开局即王炸

校园巡礼 | 一周只上四天课&#xff0c;入学即发钱&#xff1f;深圳理工大学&#xff0c;开局即王炸&#xff01; 会议之眼 快讯 目前各省的高考成绩现已陆续揭晓&#xff0c;广东省教育考试院发布了2024年高考录取最低分数线&#xff0c;物理类本科线为442分&#xff0c;历史…

Rocky Linux设置静态IP

[connection] idens160 uuidcd246f67-c929-362a-809d-f1b44ddc5d25 typeethernet autoconnect-priority-999 interface-nameens160 timestamp1719094243[ethernet][ipv4] ## 在IPV4下面修改如下内容 methodmanual address192.…

科普文:贝叶斯过滤器判定垃圾邮件

简介 贝叶斯分类的运作是借着使用标记(一般是字词&#xff0c;有时候是其他)与垃圾邮件、非垃圾邮件的关连&#xff0c;然后搭配贝叶斯推断来计算一封邮件为垃圾邮件的可能性。 贝叶斯垃圾邮件过滤是非常有威力的技术&#xff0c;可以修改自己以符合个别使用者的需要&#xff0…

pdf压缩,pdf压缩在线,pdf压缩在线网页版

当我们遇到PDF文件过大&#xff0c;需要压缩其容量大小时&#xff0c;通常是为了更方便地传输、存储或分享这些文件。PDF文件的大小可能因其包含的图像、字体等元素的数量和质量而有所不同。下面&#xff0c;我们将详细介绍压缩PDF容量大小的方法&#xff0c;帮助您轻松实现文件…

TikTok短视频矩阵系统

随着数字化时代的到来&#xff0c;短视频已成为人们获取信息、娱乐消遣的重要渠道。TikTok&#xff0c;作为全球最受欢迎的短视频平台之一&#xff0c;其背后的短视频矩阵系统是支撑其成功的关键因素。本文将深入探讨TikTok短视频矩阵系统的构成、功能以及它在新媒体时代中的影…

基于 JuiceFS 构建高校 AI 存储方案:高并发、系统稳定、运维简单

中山大学的 iSEE 实验室&#xff08;Intelligence Science and System) Lab&#xff09;在进行深度学习任务时&#xff0c;需要处理大量小文件读取。在高并发读写场景下&#xff0c;原先使用的 NFS 性能较低&#xff0c;常在高峰期导致数据节点卡死。此外&#xff0c;NFS 系统的…

《Three.JS零基础入门教程》第九篇:环境详解

往期回顾&#xff1a; 《Three.JS零基础入门教程》第一篇&#xff1a;搭建开发环境 《Three.JS零基础入门教程》第二篇&#xff1a;起步案例 《Three.JS零基础入门教程》第三篇&#xff1a;开发辅助 《Three.JS零基础入门教程》第四篇&#xff1a;基础变换 《Three.JS零基…

element-ui侧边栏:default-openeds

element-ui侧边栏实现路由跳转后展开对应侧边栏&#xff1a;default-openeds 当菜单是在本地写死时&#xff0c;如果想展开第一块内容、里面就只写1 :default-openeds"[‘1’]" 当菜单是动态获取时&#xff0c;点击跳转之后如何展开对应的菜单&#xff0c;在watch中监…

三元前驱体废水回收镍钴工艺:环保与经济效益的双重胜利

在全球新能源产业迅猛发展的背景下&#xff0c;锂离子电池作为绿色能源的核心组件&#xff0c;其需求量激增&#xff0c;带动了上游材料市场&#xff0c;尤其是三元前驱体材料的蓬勃发展。然而&#xff0c;伴随着行业的快速扩张&#xff0c;三元前驱体生产过程中产生的含镍钴废…