Gin的使用

2023-11-09

Gin框架

  • gin框架路由使用前缀树,路由注册的过程是构造前缀树的过程,路由匹配的过程就是查找前缀树的过程。
  • gin框架的中间件函数和处理函数是以切片形式的调用链条存在的,我们可以顺序调用也可以借助c.Next()方法实现嵌套调用。
  • 借助c.Set()和c.Get()方法我们能够在不同的中间件函数中传递数据。
  • 使用前需要调用gin.Default()生成gin引擎
  • 调用r.Run()结尾,可以指定端口

安装

go get -u github.com/gin-gonic/gin

静态文件解析

  • 一般放在statics文件夹下分类存放
//静态文件的处理:静态文件指html页面用到的css\js\图片
r.Static("/relativepath", "./statics") //必须在模板解析之前;前面指定相对路径(html模板中使用,后面指定静态文件位置)

//使用
<link rel="stylesheet" href="/relativepath/demo.css">
<script src="/relativepath/vendor/jquery/jquery.min.js"></script>

HTML渲染

  • HTML一般放在templates文件夹中;可以通过define 来给模板命名来定位;
  • 模板文件后缀可以是.html也可以是.tmpl
//例如
{{define "post/index.tmpl"}}
<!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>posts/index</title>
</head>
<body>
    {{.title}}
</body>
</html>
{{end}}

//模板加载的两种方式
r.LoadHTMLFiles("templates/post/index.tmpl", "templates/user/index.tmpl")//便于解析单个文件
r.LoadHTMLGlob("templates/**/*") //便于解析多个文件 **表示目录 *表示文件
//GET提交
r.GET("/post/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "post/index.tmpl", gin.H{ //第二个参数与模板中define 的文件名保持一致
			"title": "post/index渲染",
		})
	})


  • 自定义模板
// 自定义模板函数  必须写在模板解析之前
r.SetFuncMap(template.FuncMap{
	"safe": func(s string) template.HTML {
		return template.HTML(s)
	},
})
//使用:
<body>
    <h1> {{.title}}</h1>
    <div> {{.setFuncMap|safe}}</div>
</body>
  • 模板继承(调用"github.com/gin-contrib/multitemplate"库实现)
/*
示例;
假设home.tmpl和index.tmpl继承base.tmpl
templates
├── includes
│   ├── home.tmpl
│   └── index.tmpl
├── layouts
│   └── base.tmpl
└── scripts.tmpl
*/
func loadTemplates(templatesDir string) multitemplate.Renderer {
	r := multitemplate.NewRenderer()
	layouts, err := filepath.Glob(templatesDir + "/layouts/*.tmpl")
	if err != nil {
		panic(err.Error())
	}
	includes, err := filepath.Glob(templatesDir + "/includes/*.tmpl")
	if err != nil {
		panic(err.Error())
	}
	// 为layouts/和includes/目录生成 templates map
	for _, include := range includes {
		layoutCopy := make([]string, len(layouts))
		copy(layoutCopy, layouts)
		files := append(layoutCopy, include)
		r.AddFromFiles(filepath.Base(include), files...)
	}
	return r
}


func main(){
	r := gin.Default()
	r.HTMLRender = loadTemplates("./templates")
	r.GET("/index", func (c *gin.Context){
	c.HTML(http.StatusOK, "index.tmpl", nil)
})
	r.GET("/home", func (c *gin.Context){
	c.HTML(http.StatusOK, "home.tmpl", nil)
})
	r.Run()
}

JSON渲染

//方式1
r.GET("/hello", func(c *gin.Context) {
	// c.JSON:返回JSON格式的数据
	c.JSON(200, gin.H{
		"message": "Hello world!",
	})
})
//方式2
r.GET("/helloJSON2", func(c *gin.Context) {
	type msg struct {
		Name  string `json:"name"`
		Age   int
		Hobby string
	}
	var dataObj = msg{
		"wuzb",
		12,
		"soccer",
	}
	c.JSON(http.StatusOK, dataObj)
})

获取请求参数

//获取URL中querystring参数参数
//www.xxx.com/user/search?id=2&page=1
func main() {
	r := gin.Default()
	r.GET("/user/search", func(c *gin.Context) {
		userid := c.DefaultQuery("id ", "1")
		//userid := c.Query("id")
		page:= c.Query("page")
		//输出json结果给调用方
		c.JSON(http.StatusOK, gin.H{
			"message":  "ok",
			"userid ": userid ,
			"page":  page,
		})
	})
	r.Run()
}

//获取form参数
func main() {
	r := gin.Default()
	r.POST("/user/search", func(c *gin.Context) {
		// DefaultPostForm取不到值时会返回指定的默认值
		//username := c.DefaultPostForm("username", "zs")
		username := c.PostForm("username")
		address := c.PostForm("address")
		//输出json结果给调用方
		c.JSON(http.StatusOK, gin.H{
			"message":  "ok",
			"username": username,
			"address":  address,
		})
	})
	r.Run(":8080")
}

//获取path参数
func main() {
	r := gin.Default()
	r.GET("/user/search/:username/:address", func(c *gin.Context) {
		username := c.Param("username")
		address := c.Param("address")
		c.JSON(http.StatusOK, gin.H{
			"message":  "ok",
			"username": username,
			"address":  address,
		})
	})
	r.Run(":8080")
}

//通过bind(基于反射)来自动绑定参数到结构体
type Login struct {
	Username string `form:"name"json:"name" binding:"required,NameValid"` //NameValid是自定义验证方法
	Password string `form:"pwd"json:"pwd"`
}
//shouldBind() 能够基于请求自动提取JSON、form表单和QueryString类型的数据,并把值绑定到指定的结构体对象。
//绑定JSON的示例 ({"name": "wz", "pwd": "123456"})
r.GET("/shudBind", func(c *gin.Context) {
	var u Login
	if err := c.ShouldBind(&u); err == nil {
		c.JSON(http.StatusOK, gin.H{
			"name": u.Username,
			"pwd":  u.Password,
		})
	} else {
		c.JSON(http.StatusOK, gin.H{
			"error": err.Error(),
		})
	}
})

关于binging中的参数既可以自定义也可以使用框架自带的参数;

  1. 框架自带的参数比如required,gt=x,lt=y(大于x小于y)等;
  2. 自定义参数的话,验证使用到gopkg.in/go-playground/validator.v8;例如:
//首先写一个验证方法
func NameValid(
	v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
	field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
	if s, ok := field.Interface().(string); ok {
		if s == "admin" {
			return false
		}
	}
	return true
}

// 在路由中绑定绑定验证器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
	v.RegisterValidation("NameValid", NameValid)
}

重定向

//HTTP重定向 
r.GET("/test", func(c *gin.Context) {
	c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
})
//路由重定向
r.GET("/test", func(c *gin.Context) {
    // 指定重定向的URL
    c.Request.URL.Path = "/test2"
    r.HandleContext(c)
})
r.GET("/test2", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"hello": "world"})
})

路由

//get
r.GET("/get", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{})
	})
//post
r.POST("/post", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{})
	})
//any可以匹配所有请求方法
r.Any("/any", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{})
	})
//NoRoute:用于处理非注册的路由,报404页面
r.NoRoute(func(c *gin.Context) {
		c.HTML(http.StatusNotFound, "404.html", nil)
	})
//路由组
ginRoute := gin.Default()
prodGroup := ginRoute.Group("/prod")
{
	prodGroup.POST("/list", func(c *gin.Context) {c.HTML(http.StatusOK,"index.html", gin.H{})})
	prodGroup.GET("/detail/:pid",func(c *gin.Context){c.HTML(http.StatusOK,"index.html", gin.H{})})
}
return ginRoute

中间件

//中间件函数(统计请求处理函数的耗时)
func m1() gin.HandlerFunc {
	//连接数据库或者其他的一些操作
	return func(c *gin.Context) {
		//存放具体的逻辑
		start := time.Now()
		c.Next() //调用后续的函数
		// c.Abort() //阻止后续的函数
		//c.Set()//往上下文中存值;通过c.Get()取值;实现中间件的值传递
		cost := time.Since(start)
		fmt.Printf("cost %d times", cost)
	}

}

//中间件使用
//1.单个路由注册
r.GET("/middleware", m1(), func(c *gin.Context) { //某个路由单独注册中间体
		c.JSON(http.StatusOK, gin.H{
			"msg": "middleware",
		})
	})
//2.注册一个全局中间件
r.Use(m1())
//3.组注册中间件
r.Use(m1()){
把组路由给包裹进来
}
//或者
prodGroup := ginRoute.Group("/prod",m1())
{
	prodGroup.POST("/list", func(c *gin.Context) {c.HTML(http.StatusOK,"index.html", gin.H{})})
	prodGroup.GET("/detail/:pid",func(c *gin.Context){c.HTML(http.StatusOK,"index.html", gin.H{})})
}

文件上传

//html
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="f1">
    <input type="submit" value="上传">
</form>
//go
//单文件上传处理
func main() {
	router := gin.Default()
	// 处理multipart forms提交文件时默认的内存限制是32 MiB
	// 可以通过下面的方式修改
	// router.MaxMultipartMemory = 8 << 20  // 8 MiB
	router.POST("/upload", func(c *gin.Context) {
		// 单个文件
		file, err := c.FormFile("f1")
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{
				"message": err.Error(),
			})
			return
		}

		log.Println(file.Filename)
		dst := fmt.Sprintf("C:/tmp/%s", file.Filename)
		// 上传文件到指定的目录
		c.SaveUploadedFile(file, dst)
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("'%s' uploaded!", file.Filename),
		})
	})
	router.Run()
}
//多文件上传处理
func main() {
	router := gin.Default()
	// 处理multipart forms提交文件时默认的内存限制是32 MiB
	// 可以通过下面的方式修改
	// router.MaxMultipartMemory = 8 << 20  // 8 MiB
	router.POST("/upload", func(c *gin.Context) {
		// Multipart form
		form, _ := c.MultipartForm()
		files := form.File["file"]

		for index, file := range files {
			log.Println(file.Filename)
			dst := fmt.Sprintf("C:/tmp/%s_%d", file.Filename, index)
			// 上传文件到指定的目录
			c.SaveUploadedFile(file, dst)
		}
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("%d files uploaded!", len(files)),
		})
	})
	router.Run()
}

注意:

//异步(无法使用他的原始上下文,必须使用他的只读副本)
r.GET("/request-async", func(c *gin.Context) {
	copyC := c.Copy()
	go func() {
		time.Sleep(3 * time.Second)
		fmt.Println("异步请求:", copyC)
	}()
})

/*
gin.Default()默认使用了Logger和Recovery中间件:
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。
*/
//需要建立个空白中间件的gin引擎的话可以使用
gin.New()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Gin的使用 的相关文章

  • 【Golang入门】Golang第一天心得

    生活所迫 入门一下Go 很奇葩的第一点 接口 package main import fmt 定义一个接口 type Shape interface Area float64 定义一个矩形类型 type Rectangle struct W
  • golang: Logrus实现日志打印

    Github https github com sirupsen logrus golang标准库的日志框架非常简单 仅仅提供了print panic和fatal三个函数 对于更精细的日志级别 日志文件分割以及日志分发等方面并没有提供支持
  • Go语言学习路线

    gogogo git 地址 Go 学习 学习路线 2 基础知识 3 开发工具安装地址 下载 Go基础知识 链接为gitee地址 放心查看 基础结构 learn1 go 基础语法 learn2 go 数据类型 learn3 go 变量 lea
  • Golang-使用 goroutine 运行闭包的“坑”

    介绍 在 Go 语言中 函数支持匿名函数 闭包就是一种特殊的匿名函数 它可以用于访问函数体外部的变量 需要注意的是 在 for range 中 使用 goroutine 执行闭包时 经常会掉 坑 因为匿名函数可以访问函数体外部的变量 而 f
  • 【网络通信】TCP网络编程

    TCP网络编程 一 面向连接的TCP流模式 二 server程序 三 client程序 四 相关文章 1 TCP网络编程 2 sockaddr和sockaddr in详解 3 socket编程为什么需要htons ntohl ntohs h
  • 权重实现随机抽奖

    一般抽奖是怎么实现的 在实习期间学会了一种通用的写法 在这里记录一下 最近在学Golang语法基础 这里就用Golang来写 package main import fmt time math rand func main r rand N
  • Golang连接Jenkins获取Job Build状态及相关信息

    文章目录 1 连接Jenkins 2 controller 3 module 4 router 5 效果展示 第三方包 gojenkins 方法文档 gojenkins docs 实现起来很简单 利用第三方库 连接jenkins 调用相关方
  • beego+goAdmin+mysql+docker+natapp作为微信小程序地服务器“伪部署”

    写在前面的话 1 为什么我要叫伪部署 答 因为我把它们放在服务器运行 都是开发模式 生产模式实在不会弄 所以就这样了 2 系统环境 答 腾讯云服务器 系统为 ubuntu 版本不记得 应该是比较高的 3 前提假设 答 假设你的服务器已经安装
  • 【golang】error parsing regexp: invalid or unsupported Perl syntax (正则表达式校验密码)

    要在 Go 中编写密码校验规则 确保密码不少于8位且包含数字和字母 你可以使用正则表达式和 Go 的 regexp 包来实现 以下是一个示例代码 错误示范 package main import fmt regexp func valida
  • Go语言里面的各种疑难杂症

    什么是闭包 闭包有什么缺陷 func AddUpper func int int var n int 10 return func x int int n n x return n func main f AddUpper fmt Prin
  • Go 语言输出文本函数详解

    Go语言拥有三个用于输出文本的函数 Print Println Printf Print 函数以其默认格式打印其参数 示例 打印 i 和 j 的值 package main import fmt func main var i j stri
  • 基于Go语言实现简易Web应用

    目录 前言 Go语言特点 写在使用Go语言实现Web应用前面 创建Web服务器 声明一个结构体操作 加入中间件的使用 使用静态文件服务器 最后 前言 在编程语言中 近几年问世的几个新语言都是非常不错的 比如Go Python Rust等等
  • go-zero开发入门-API网关开发示例

    开发一个 API 网关 代理 https blog csdn net Aquester article details 134856271 中的 RPC 服务 网关完整源代码 file main go package main import
  • go-zero目录结构和说明

    code of conduct md 行为准则 CONTRIBUTING md 贡献指南 core 框架的核心组件 bloom 布隆过滤器 用于检测一个元素是否在一个集合中 breaker 熔断器 用于防止过多的请求导致系统崩溃 cmdli
  • go-zero开发入门之gateway深入研究1

    创建一个 gateway 示例 main go package main import flag fmt gateway middleware github com zeromicro go zero core conf github co
  • GoLong的学习之路,进阶,Viper(yaml等配置文件的管理)

    本来有今天是继续接着上一章写微服务的 但是这几天有朋友说 再写Web框架的时候 遇到一个问题 就是很多的中间件 redis 微信 mysql mq 的配置信息写的太杂了 很不好管理 希望我能写一篇有管理配置文件的 所以这篇就放到今天写吧 微
  • go开发--操作mysql数据库

    在 Go 中访问 MySQL 数据库并进行读写操作通常需要使用第三方的 MySQL 驱动 Go 中常用的 MySQL 驱动有 github com go sql driver mysql 和 github com go xorm xorm
  • [每周一更]-(第55期):Go的interface

    参考地址 https juejin cn post 6978322067775029261 https gobyexample com interfaces https go dev tour methods 9 介绍下Go的interfa
  • 这套Go语言开发框架组合真的非常高效

    我尝试过很多框架 从Django Flask和Laravel到NextJS和SvelteKit 到目前为止 这是我唯一可以使用的不会让我感到疯狂或者放弃项目的堆栈 框架 我喜欢所有这些框架 但我只是不太适应它们的设计方式 实际上 我是一个弱
  • 【go语言】结构体数据填充生成md错误码文件

    这里使用pongo2这个模版引擎库进行md文件渲染 GitHub flosch pongo2 Django syntax like template engine for Go package main import fmt github

随机推荐

  • 一维连续型随机变量的函数分布

    目录 a b N 2 a b N 0 1 2 N 2 e sin a b N 2 a b N 0 1 2 N 2 e sin
  • LoadRunner脚本测试——登录实践

    实习公司最近在做一款会计项目的财政管理系统 跟着测试组在做登录响应测试时 学到了不少实践经验 本文作以简单阐述和分享 通过代理服务器录制脚本 测试系统的门户必须用Chrome打开 然而测试环境lr11似乎只对IE浏览器兼容 事实上 lr与浏
  • Java入门(2) —— 变量详解、运算符、定义类和定义方法以及方法的调用

    1 变量 1 定义变量 1 声明的同时直接赋值 数据类型 变量名 值 2 先声明 后赋值 声明 数据类型 变量名 赋值 变量名 值 2 数据类型 基本数据类型 4类8种 整数 gt 直接写整数 默认就是 int byte 1个字节 shor
  • 喷水装置(一)贪心算法

    听说这是 贪心算法 的一个简单应用 虽说是简单 但是对我来说 确实不简单 说下面说有用的 题目描述 现有一块草坪 长为20米 宽为2米 要在横中心线上放置半径为Ri的喷水装置 每个喷水装置的效果都会让以它为中心的半径为实数Ri 0
  • Fire-YOLO:一种用于火灾检测的小目标检测方法

    点击上方 小白学视觉 选择加 星标 或 置顶 重磅干货 第一时间送达 作者丨CY 来源丨当交通遇上机器学习 编辑丨极市平台 极市导读 本次介绍的文章是太原理工大学团队在2022年发表在 Sustainability 的关于火灾检测的小目标实
  • qiankun 常见问题集合(一)

    qiankun 常见问题集合 一 1 loader js 220 Uncaught in promise Error qiankun You need to export lifecycle functions in app4 entry
  • 在使用localstorage的时候发生了报错的解决办法

    在使用localstorage的时候 发生了报错 提示是传入的格式不正确 但是传入的是json格式 为什么不正确呢 1 在localStorage setItem 过程中 传进的参数需使用JSON tringfy 方法转成json格式的字符
  • 用链式线性表实现两个一元多项式相加

    include
  • springboot+vue跨域(草稿箱中翻出来的)

    第一种 新建 GlobalCorsConfig 类 import org springframework context annotation Bean import org springframework context annotati
  • Copilot是GPT的理想应用模式吗?

    自OpenAI发布ChatGPT以来 LLM持续火热 各大公司纷纷入场 但近一段时间以来 我观测到的LLM应用场景 基本都是Copilot的形式 即以对话为基础的辅助应用 尽管体验起来十分的高大上 但我能明确感受到 这种Copilot的形式
  • pyspark中文api

    内容基于官网pyspark SparkSQL官方文档翻译及拓展 官方文档 https spark apache org docs latest api python reference pyspark sql index html 具体使用
  • Eclipse上的HTML/JSP/XML编辑器插件Eclipse HTML Editor

    官网 http amateras sourceforge jp cgi bin fswiki en wiki cgi page EclipseHTMLEditor Eclipse HTML Editor is an Eclipse plug
  • js的三种弹窗

    1 alert 提示框 用途 一般用于提示信息或者警告信息的展示 2 confirm option 确认 或 取消 消息框 用途 用户点击 确定 或 取消 按钮时 弹窗会返回一个布尔值 确认返回true 取消返回false 由此可以判断用户
  • adb shell 执行sh脚本_程序开发——Shell脚本

    Shell 是一个用 C 语言编写的程序 它是用户使用 Linux 的桥梁 Shell 既是一种命令语言 又是一种程序设计语言 Shell 是指一种应用程序 这个应用程序提供了一个界面 用户通过这个界面访问操作系统内核的服务 Ken Tho
  • 深入浅出 Spark Thrift Sever

    一 Spark Thrift Sever是什么 Spark借助Hive的Metadata Service可以实现通过命令行客户端工具执行Sql语句 就像是Hive或者Mysql的命令行工具一样 称之为Spark CLI Spark CLI适
  • 基于GMap.Net的地图解决方案

    一 地图的加载与显示 关于GMap的介绍与使用可以看我以前的文章 GMap Net开发之在WinForm和WPF中使用GMap Net地图插件 GMap Net是 Net下一个地图控件 可以基于Http协议加载各个公司的地图 如Google
  • 如何设计一个秒杀系统

    什么是秒杀 秒杀场景一般会在电商网站举行一些活动或者节假日在12306网站上抢票时遇到 对于电商网站中一些稀缺或者特价商品 电商网站一般会在约定时间点对其进行限量销售 因为这些商品的特殊性 会吸引大量用户前来抢购 并且会在约定的时间点同时在
  • MinGW-W64下载、配置教程

    注意 本文采用的操作系统 Windows7 64位 注 文章原创 配图的知乎水印也是笔者账号 一 下载与配置 使用浏览器访问 MinGW W64 图1 找到图2所示区域 根据需求点击一项 下载压缩包 图2 解压下载的压缩包 内容如图3 图3
  • JAVA练习34-验证回文串

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 目录 前言 一 题目 验证回文串 1 题目描述 2 思路与代码 2 1 思路 2 2 代码 总结 前言 提示 这里可以添加本文要记录的大概内容 1月29日练习内容 提示 以下
  • Gin的使用

    Gin框架 gin框架路由使用前缀树 路由注册的过程是构造前缀树的过程 路由匹配的过程就是查找前缀树的过程 gin框架的中间件函数和处理函数是以切片形式的调用链条存在的 我们可以顺序调用也可以借助c Next 方法实现嵌套调用 借助c Se