gin-基础笔记

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 1、get和post方法
  • 2、重定向
  • 3、获取第三方数据
  • 4、多形式渲染
  • 5、文件服务器
  • 6、单文件上传
  • 7、多文件上传
  • 8、自定义中间件
  • 9、登录中间件
  • 10、同步异步
  • 11、多服务器程序运行
  • 12、路由组
  • 13、Gin框架bind
  • 14、调用restful接口
  • 15、参数校验1-tag验证
  • 16、参数校验2-嵌套结构体验证
  • 17、swagger
  • 18、Gin框架cookie
  • 19、Gin框架Session
  • 总结


前言

gin框架的基本使用,把各个知识点拆分写成demo。


1、get和post方法

最简单的获取参数的方法。我还知道json映射,后续补充。

package mainimport ("fmt""github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/hi", getMsg)r.POST("/hi", postMsg)r.Run(":9090")
}func getMsg(c *gin.Context) {name := c.Query("name")// c.String(http.StatusOK, "欢迎:%s",name)c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + name,})
}func postMsg(c *gin.Context) {name := c.DefaultPostForm("name", "lisi")fmt.Println(name)form, b := c.GetPostForm("name")fmt.Println(form, b)
}

2、重定向

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()// 第一种应该是在某个版本被废弃了/*r.GET("/hi", func(c *gin.Context) {c.Redirect(http.StatpusMovedPermanently, "http://www.baidu.com")})*/r.GET("/hi", getMsg)r.GET("/hello", func(c *gin.Context) {c.Request.URL.Path = "/hi"r.HandleContext(c)})r.Run(":9090")
}func getMsg(c *gin.Context) {name := c.Query("name")// c.String(http.StatusOK, "欢迎:%s",name)c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + name,})
}

3、获取第三方数据

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/getThird", func(c *gin.Context) {url := "http://www.baidu.com"resp, err := http.Get(url)if err != nil || resp.StatusCode != http.StatusOK {c.Status(http.StatusServiceUnavailable)return}body := resp.BodycontentLength := resp.ContentLengthcontentType := resp.Header.Get("Content-Type")c.DataFromReader(http.StatusOK, contentLength, contentType, body, nil)})r.Run(":9090")
}

4、多形式渲染

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.GET("/getJson", func(c *gin.Context) {// JSON 使用 unicode 替换特殊 HTML 字符,例如 < 变为 \ u003cc.JSON(http.StatusOK, gin.H{"html": "<H1>hi</H1>",})})r.GET("/getHTML", func(c *gin.Context) {// 如果要正常返回HTML字符,用PureJSONc.PureJSON(http.StatusOK, gin.H{"html": "<H1>hi</H1>",})})r.GET("/getXML", func(c *gin.Context) {type Message struct {Name stringMsg  stringAge  int}info := Message{Name: "zhangsan",Msg:  "hello",Age:  20,}c.XML(http.StatusOK, info)})r.GET("/getYAML", func(c *gin.Context) {// 会下在一个yaml文件c.YAML(http.StatusOK, gin.H{"msg": "hello",})})r.Run(":9090")
}

5、文件服务器

package mainimport ("github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/file", func(c *gin.Context) {path := "/home/ld/workspace/study/gin-learn/2.4_file/" // 最后一个/一定要加上,否则拼接路径就不对了fileName := path + c.Query("name")// JSON 使用 unicode 替换特殊 HTML 字符,例如 < 变为 \ u003cc.File(fileName)})r.Run(":9090")
}

6、单文件上传

package mainimport ("fmt""github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.POST("/uploadOne", func(c *gin.Context) {file, err := c.FormFile("fileName")if err != nil {fmt.Println(err.Error())c.String(http.StatusBadRequest, "文件上传错误")}dst := "/home/ld/workspace/study/gin-learn/2.5_file_upload_one/"c.SaveUploadedFile(file, dst+file.Filename)c.String(http.StatusOK, "保存成功:%s", file.Filename)})r.Run(":9090")
}

设置请求头
设置请求体

7、多文件上传

package mainimport ("fmt""github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.POST("/uploadMoreThanOne", func(c *gin.Context) {form, err := c.MultipartForm()if err != nil {fmt.Println(err.Error())c.String(http.StatusBadRequest, "文件上传错误")}files := form.File["file_key"]dst := "/home/ld/workspace/study/gin-learn/2.6_file_upload_more_than_one/"for _, file := range files {c.SaveUploadedFile(file, dst+file.Filename)}c.String(http.StatusOK, "%d个文件保存成功", len(files))})r.Run(":9090")
}

设置请求体

8、自定义中间件

package mainimport ("github.com/gin-gonic/gin""net/http""strconv"
)func main() {r := gin.Default()r.Use(Middleware())r.GET("/middle", func(c *gin.Context) {c.String(http.StatusOK, "年龄验证成功,年龄为:%s", c.Query("age"))})r.Run(":9090")
}func Middleware() gin.HandlerFunc {return func(c *gin.Context) {ageStr := c.Query("age")age, err := strconv.Atoi(ageStr)if err != nil || age < 18 {c.AbortWithStatusJSON(http.StatusBadRequest, "年龄异常")return}c.Next()}
}

9、登录中间件

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()r.Use(AuthMiddleware())r.GET("/middle", func(c *gin.Context) {c.String(http.StatusOK, "身份验证成功,用户为:%s", c.MustGet(gin.AuthUserKey))})r.Run(":9090")
}func AuthMiddleware() gin.HandlerFunc {// 静态添加accounts := gin.Accounts{"admin": "admin","user":  "user",}// 动态添加accounts["boss"] = "boss"auth := gin.BasicAuth(accounts)return auth
}

10、同步异步

package mainimport ("github.com/gin-gonic/gin""net/http""time"
)func main() {r := gin.Default()r.GET("/sync", func(c *gin.Context) {sync(c)c.String(http.StatusOK, "同步任务结束")})r.GET("/async", func(c *gin.Context) {for i := 0; i < 6; i++ {go async(c)}c.String(http.StatusOK, "异步任务结束")})r.Run(":9090")
}func async(c *gin.Context) {println("开始同步任务")time.Sleep(3 * time.Second)println("同步任务结束")
}func sync(c *gin.Context) {println("开始同步任务")time.Sleep(3 * time.Second)println("同步任务结束")
}

11、多服务器程序运行

package mainimport ("fmt""github.com/gin-gonic/gin""golang.org/x/sync/errgroup""net/http""time"
)var g errgroup.Groupfunc main() {server01 := &http.Server{Addr:         ":9091",Handler:      router01(),ReadTimeout:  5 * time.Second,WriteTimeout: 10 * time.Second,}server02 := &http.Server{Addr:         ":9092",Handler:      router02(),ReadTimeout:  5 * time.Second,WriteTimeout: 10 * time.Second,}g.Go(func() error {return server01.ListenAndServe()})g.Go(func() error {return server02.ListenAndServe()})if err := g.Wait(); err != nil {fmt.Println("Error: ", err)}
}
func router01() http.Handler {r := gin.Default()r.GET("/router01", func(c *gin.Context) {c.String(http.StatusOK, "router01")})return r
}
func router02() http.Handler {r := gin.Default()r.GET("/router02", func(c *gin.Context) {c.String(http.StatusOK, "router02")})return r
}

12、路由组

package mainimport ("github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()group1 := r.Group("/group1"){group1.GET("/hi", getMsg)group1.GET("/hello", getMsg)}group2 := r.Group("/group2")group2.GET("/hi", getMsg)r.Run(":9090")
}func getMsg(c *gin.Context) {name := c.Query("name")// c.String(http.StatusOK, "欢迎:%s",name)c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + name,})
}

13、Gin框架bind

package mainimport ("github.com/gin-gonic/gin""net/http"
)// User 大写
type User struct {Name     string `json:"name" binding:"required"`Password string `json:"password"`
}func main() {r := gin.Default()r.POST("/hi", getMsg)r.Run(":9090")
}func getMsg(c *gin.Context) {var user User// 此处传指针err := c.Bind(&user)if err != nil {c.JSON(http.StatusBadRequest, err.Error())return}c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + user.Name,})
}

14、调用restful接口

package mainimport ("bytes""encoding/json""fmt""io/ioutil""net/http""time"
)// User 大写
type User struct {Name     string `json:"name" binding:"required"`Password string `json:"password"`
}type TempData struct {// Code string `json:"code"` // 不会给这个值反序列化Msg string `json:"msg"`
}func main() {testApi()// 应用中就是一样的道理了,解析请求体,然后调用,最后把响应体封装返回给请求端就好了
}func testApi() {url := "http://127.0.0.1:9090/hi"user := User{Name:     "zs",Password: "123",}data, err := getRestfulApi(url, user, "application/json")var tmp TempDatajson.Unmarshal(data, &tmp)fmt.Println(tmp, err)
}// getRestfulApi send post request
// url: 请求地址
// data: post请求提交的数据
// contentType: 请求体格式,如application/json
// res: 请求返回的内容
func getRestfulApi(url string, data interface{}, contentType string) ([]byte, error) {// 创建调用api接口的clientclient := &http.Client{Timeout: time.Second * 5}jsonStr, _ := json.Marshal(data)resp, err := client.Post(url, contentType, bytes.NewBuffer(jsonStr))if err != nil {fmt.Println("Error marshalling")return nil, err}res, err := ioutil.ReadAll(resp.Body)return res, err
}

15、参数校验1-tag验证

package mainimport ("github.com/gin-gonic/gin""github.com/go-playground/validator/v10""net/http""sync"
)var (Validate *validator.Validateonce     sync.Once
)// User 大写
type User struct {Name     string `json:"name" validate:"required"`Age      int    `json:"age" validate:"checkAge"` // 这里是为了演示,对于数字的校验,可以直接使用最大值最小值规则Password string `json:"password"`
}// 项目里可以这样实现
func init() {once.Do(func() {Validate = validator.New()Validate.RegisterValidation("checkAge", checkAgeFunc)})
}func checkAgeFunc(fl validator.FieldLevel) bool {if fl.Field().Int() > 18 {return true}return false
}func main() {r := gin.Default()r.POST("/hi", getMsg)r.Run(":9090")
}func getMsg(c *gin.Context) {var user User// 此处传指针err := c.Bind(&user)if err != nil {c.JSON(http.StatusBadRequest, err.Error())return}err = Validate.Struct(user)if err != nil {c.JSON(http.StatusBadRequest, err.Error())return}c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + user.Name,})
}

16、参数校验2-嵌套结构体验证

package mainimport ("fmt""github.com/gin-gonic/gin""github.com/go-playground/validator/v10""net/http""sync"
)var (Validate *validator.Validateonce     sync.Once
)// User 大写
type User struct {Name string    `json:"name" validate:"required"`Addr []Address `json:"addresses" validate:"required,dive"`
}type Address struct {Country string `json:"country" validate:"required"`City    string `json:"city" validate:"required"`
}// 项目里可以这样实现
func init() {once.Do(func() {Validate = validator.New()})
}func main() {r := gin.Default()r.POST("/hi", getMsg)r.Run(":9090")
}func getMsg(c *gin.Context) {var user User// 此处传指针err := c.Bind(&user)if err != nil {c.JSON(http.StatusBadRequest, err.Error())return}err = Validate.Struct(user)if err != nil {c.JSON(http.StatusBadRequest, err.Error())return}fmt.Print("你的地址包括:")for _, v := range user.Addr {fmt.Print(v.Country + "-" + v.City + " ")}fmt.Println()c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + user.Name,})
}

17、swagger

完成代码

package mainimport (_ "gin-learn/2.16_swagger/docs""github.com/gin-gonic/gin"swaggerfiles "github.com/swaggo/files"ginSwagger "github.com/swaggo/gin-swagger""net/http"
)// User 大写
type User struct {Name     string `json:"name" binding:"required"`Password string `json:"password"`
}func main() {r := gin.Default()r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))r.POST("/hi", getMsg)r.Run(":9090")
}// getMsg godoc
// @Tags 获取信息
// @Summary ping example
// @Description do ping
// @Accept json
// @Produce json
// @Param user body string true "用户"
// @Success 200 {string} json "{"code":"200", "msg":  "欢迎:username"}"
// @Router /hi [post]
func getMsg(c *gin.Context) {var user User// 此处传指针err := c.Bind(&user)if err != nil {c.JSON(http.StatusBadRequest, err.Error())return}c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + user.Name,})
}

安装:

go install github.com/swaggo/swag/cmd/swag@latest

生成文档文件

swag init

运行,然后打开
http://localhost:9090/swagger/index.html

在我操作过程中碰到一个问题,我生成的docs.go中有这样一段代码

// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{Version:          "",Host:             "",BasePath:         "",Schemes:          []string{},Title:            "",Description:      "",InfoInstanceName: "swagger",SwaggerTemplate:  docTemplate,LeftDelim:        "{{",RightDelim:       "}}",
}

而我的swag是v1.8.12,Spec的定义中没有LeftDelim、RightDelim,如下,导致了报错,我只能手动删除这部分,不知道哪一步出错了。

// Spec holds exported Swagger Info so clients can modify it.
type Spec struct {Version          stringHost             stringBasePath         stringSchemes          []stringTitle            stringDescription      stringInfoInstanceName stringSwaggerTemplate  string
}

18、Gin框架cookie

package mainimport ("encoding/hex""fmt""github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()// r.POST("/hi", getMsg)r.Use(CookieMiddleware())r.GET("/cookie", handleCookie)r.Run(":9090")
}func handleCookie(c *gin.Context) {name := c.Query("name")cookieName := "cookie_" + nameval, _ := c.Cookie(cookieName)if val == "" {c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "cookie : " + cookieName,})return}// c.String(http.StatusOK, "欢迎:%s",name)c.JSON(http.StatusOK, gin.H{"code": http.StatusOK,"msg":  "欢迎:" + cookieName + "-" + val,})
}func CookieMiddleware() gin.HandlerFunc {return func(c *gin.Context) {name := c.Query("name")if len(name) <= 0 {c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest,"msg":  "数据错误",})return}cookieName := "cookie_" + namecookieValue := hex.EncodeToString([]byte(cookieName + "value"))val, _ := c.Cookie(cookieName)if val == "" {c.SetCookie(cookieName, cookieValue, 3600, "/", "localhost", true, true)fmt.Println("cookie already set")}c.Next()}
}

验证的时候需要手动输入cookie,如图:

选择cookie

填充cookie

19、Gin框架Session

package mainimport ("github.com/gin-contrib/sessions""github.com/gin-contrib/sessions/cookie""github.com/gin-gonic/gin""net/http"
)func main() {r := gin.Default()store := cookie.NewStore([]byte("session_secret"))r.Use(sessions.Sessions("mySession", store))r.GET("/session", handleSession)r.Run(":9090")
}var sessionName string
var sessionValue stringtype MyOption struct {sessions.Options
}func handleSession(c *gin.Context) {name := c.Query("name")if len(name) <= 0 {c.JSON(http.StatusBadRequest, "数据错误")return}sessionName = "session_" + namesessionValue = "session_value_" + namesession := sessions.Default(c)sessionData := session.Get(sessionName)if sessionData != sessionValue {session.Set(sessionName, sessionValue)o := MyOption{}o.Path = "/"o.MaxAge = 10 // 有效期,ssession.Options(o.Options)session.Save() // 保存sessionc.JSON(http.StatusOK, "首次访问,保存session")return}c.JSON(http.StatusOK, "session: "+sessionData.(string))
}

总结

gin框架的基本使用

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UML六大关系总结

UML六大关系有&#xff1a;继承、关系、聚合、组合、实现、依赖。分为通过图和代码总结这些关系。 1、继承 继承&#xff08;Inheritance&#xff09;&#xff1a;表示类之间的继承关系&#xff0c;子类继承父类的属性和方法&#xff0c;并可以添加自己的扩展。 继承&#x…

滑动窗口9.23

1876.长度为3且各字符不同的子字符串 1876. 长度为三且各字符不同的子字符串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/substrings-of-size-three-with-distinct-characters/?envTypelist&envId24zW97w8自写思路&#xff1a; 数组充当哈希表…

C语言指针变量的引用距离

本段代码&#xff0c;测试&#xff0c;C的函数传参中&#xff0c;形参是基础类型参数和地址参数&#xff0c;对于实参的值影响。 #include <stdio.h> add(int a,int b){a;b;printf("add副本a%d\n",a);printf("add副本b%d\n",b);printf("副本ca…

html怎么设置按钮返回顶部

在 HTML 中&#xff0c;我们可以通过一些代码和 CSS 样式来创建一个这样的按钮。 <button onclick"topFunction()" id"myBtn">返回顶部</button> <style> #myBtn { display: none; position: fixed; bottom: 20px; right: 30px; z-inde…

Qt QCustomPlot介绍

介绍 主要介绍qcustomplot及其用法 最新版本:QCustomPlot Patch Release 2.1.1//November 6, 2022 下载:https://www.qcustomplot.com/index.php/download 官网:https://www.qcustomplot.com/index.php 简单使用 mainwindow.h /**************************************…

Godot配置C#语言编写脚本(使用VSCode作为外部编辑器)

文章目录 Godot部分查看VSCode的所在位置配置外部编辑器 配置VSCode编写脚本中文注释 其他文章字符编码 Godot部分 打开编辑器-编辑器设置&#xff1b; 查看VSCode的所在位置 右键单击你的VScode快捷方式&#xff0c;选择属性。 这里的目标就是你的VSCode所在的位置。 配…

【算法专题突破】二分查找 - 704. 二分查找(16)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; 题目非常简单&#xff0c;就是查找一个 target。 2. 算法原理 根据最基本的二分查找算法&#xff1a; 在一个…

swift 天气

定义不同模式主题 自定义颜色 输入框 委托和协议 扩展 协议 http 请求 调用api 闭包

#循循渐进学51单片机#UART串口通信#not.10

1、能够理解UART串口通信的基本原理和通信过程。 1&#xff09;串行通信的初步认识 并行通信&#xff1a;通信时数据的各个位同时传送&#xff0c;可以实现字节为单位通信&#xff0c;但是通信线占用资源太多&#xff0c;成本高。 串行通信&#xff1a;一次只能发送一位&…

亚马逊云科技 Amazon Lightsail :一种在云服务器上运行容器的简单方法

当向开发人员介绍亚马逊云科技云服务时&#xff0c;通常会花一点时间来介绍并演示 Amazon Lightsail 。它是迄今为止开始使用亚马逊云科技的最简单方法。使用它&#xff0c;您在几分钟内即可在自己的虚拟服务器上运行您的应用程序。而后增加了在 Amazon Lightsail 上部署基于容…

你知道 delete 删除属性时的一些细节吗?

探究 delete 的一些细节&#xff0c;起源于刚刚做过的一道笔试&#xff0c;原题如下&#xff1a; a 1; const b 2; console.log(delete a); console.log(delete b); // 输出结果是&#xff1f; // 答&#xff1a;true false我可从来没用过 delete 的返回值&#xff0c;但凡…

Java反序列化和php反序列化的区别

文章目录 PHP反序列化漏洞反序列化漏洞什么是反序列化漏洞&#xff1f;修改序列化后的数据&#xff0c;目的是什么&#xff1f; Java反序列化漏洞反序列化漏洞 PHP反序列化漏洞 序列化存在的意义是为了传输数据/对象&#xff0c;类是无法直接进行传输的。通过序列化后转换为字…