gin框架学习笔记

gin学习网站

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

初识gin

什么是gin

  • gin是go语言编写的web框架,以更好的性能实现类似Martini框架的API。
  • gin是一个golang的net/http库封装的web微框架,封装比较优雅,API友好,源码注释比较明确,具有快速灵活,容错方便等特点。

同类框架对比

  • beego:开源的高性能go语言web框架。

​ beego是一个快速开发go应用的http框架。beego可以用来快速开发API、web、后端服务等各种应用,是一个restful风格的框架,主要设计灵感来源于tornado、sinatra、flask这三个框架,但是结合了go本身的一些特性(interface、struct以及继承等)而设计的一个框架。

  • Iris:全宇宙最快的go语言web框架。完备的MVC支持,未来尽在掌握。

​ Iris是一个快速,简单但功能齐全的非常有效率的web框架,提供了一个优美的表现力和容易使用的网站或API的基础。

小结

  • gin是一个web框架。
  • gin是封装了net/http库,底层的核心逻辑还是net/http

我们为什么要学习web框架

作为初学者很多时候,在学习一个框架的时候,一定要搞清楚为什么要学习它,这个非常的重要。

gin框架:使用的人多,大家都在用,所以就得学

随着互联网技术的发展,在早期我们大部分情况下,编写的都是静态网页html,如果有100篇文章就要编写100篇与之对应的静态网页,这样是非常痛苦的。于是乎就开始有了动态网页,动态网页必须要结合服务器端的技术,比如:go、java等。有了这些服务端语言的加持这样就可以完成一个静态网页到动态网页的转化。如下图:

gin框架学习笔记_第1张图片

  • 如果我们这里选择的是:gin和gorm。
  • 用户在访问浏览器地址时,这个地址是服务器提供,用于寻址一样,先找到服务器在哪里,我要访问服务器的什么。
  • 如果根据ip找到地址以后,通过port找到服务器的服务,原本你是一个go的web服务,就开始进入到程序中把对应的逻辑去执行(这个部分未来是我们使用gin去定义路由的对应的要执行的事情)。
  • 在执行的逻辑中,我们肯定会调用gorm把数据库存储起来的数据,查询出来。
  • 把查询出来的数据,和你定义好的模板开始用对应的模板语法进行渲染和碰撞。
  • 最后就呈现出一个完整的静态页面。
  • 这也就是经典的:B/S架构,B代表的是Broswer浏览器,S代表的是:Server是服务端也就是我们学习的go

环境的准备和搭建

go环境

  • go版本环境最低要求:1.18x

在这里插入图片描述

环境搭建

  • 新建一个gin-study工程,名字任取

gin框架学习笔记_第2张图片

  • 新建go.mod文件,有两种方案

    • 可以在项目中右键新建go模块文件

gin框架学习笔记_第3张图片

  • 在终端中输入命令:go mod init即可

gin框架学习笔记_第4张图片

  • 项目中一定要配置GOPROXY,否则github代码不能正常下载

gin框架学习笔记_第5张图片

gin项目快速开始

  • 下载gin:在终端中输入命令:go get -u github.com/gin-gonic/gin

  • 创建demo.go,输入代码:

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	// 创建一个gin服务
	ginServer := gin.Default()
	// 发起请求
	ginServer.GET("/hello", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"msg": "hello gin",
		})
	})
	// 设置端口,启动服务
	ginServer.Run(":8088")
}
  • 点击运行
  • 在浏览器中输入http://127.0.0.1:8088/hello,如果看到{“msg”:“hello gin”},恭喜你,第一个gin程序运行成功

restful API

restfu:用url定位资源,用HTTP动词(get、post、put、delete)描述操作。

restful api就是rest风格的api,即rest是一种架构风格,跟编程语言无关,跟平台无关,采用http做传输协议。

简单来说,rest的含义就是客户端与web服务器之间进行交互时,使用http协议中的4个请求方法代表不同的动作。

  • get :用来获取资源
  • post:用来新建资源
  • put:用来更新资源
  • delete:用来删除资源

只要api程序遵循了rest风格,那就可以称其为restful api。目前在前后端分离的架构中,前后端基本都是采用restful api来进行交互。

以前的写法

get	    	/user
post    	/create_user
post    	/update_user
post    	/delete_user

restful写法

get     	/user
post    	/user
put     	/user
delete  	/user

gin框架支持restful api

ginServer.GET("/user", func(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, gin.H{
        "msg": "GET",
    })
})
ginServer.POST("/user", func(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, gin.H{
        "msg": "POST",
    })
})
ginServer.PUT("/user", func(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, gin.H{
        "msg": "PUT",
    })
})
ginServer.DELETE("/user", func(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, gin.H{
        "msg": "DELETE",
    })
})

测试其它请求使用postman进行测试

响应页面

gin服务如何跳转到html页面

  • 定义一个页面/templates/index.html
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Go Gin框架title>
head>
<body>

<h1>我是首页h1>
{{.msg}}
body>
html>
  • gin加载静态网页
// 加载静态网页
ginServer.LoadHTMLGlob("templates/*")
  • gin定义请求跳转页面
ginServer.GET("/index", func(ctx *gin.Context) {
    ctx.HTML(http.StatusOK,"index.html",gin.H{
        "msg":"hello 我是一条msg",
    })
})
  • 打开浏览器,地址:http://localhost:8088/index

index页面如要要渲染请求中数据,使用{{.}}进行渲染

例如请求中,gin.H{"msg":"hello 我是一条msg",}map数据,页面使用{{.msg}}进行渲染

如果要加载css、js等静态资源,将文件保存在static目录下

// 加载静态资源
ginServer.Static("/static", "./static")

响应json数据

普通json数据

  • 使用gin.H{},它本质就是一个map
type H map[string]any
// gin.H{}本质就是一个map
ginServer.GET("/json1", func(ctx *gin.Context) {
   ctx.JSON(http.StatusOK, gin.H{
      "name": "zhangsan",
      "age":  18,
   })
})

结构体数据

  • 定义一个结构体

/models/User.go

package models

type User struct {
	Name string `json:"name"`
	Age int `json:"age"`
	Sex string `json:"sex"`
}
  • 使用:
// 结构体User
ginServer.GET("/json2", func(ctx *gin.Context) {
    user := models.User{
        Name: "zhangsan",
        Age:  18,
        Sex:  "男",
    }
    ctx.JSON(http.StatusOK, user)
})

结构体切片

// 结构体切片
ginServer.GET("/json2", func(ctx *gin.Context) {
    users:=make([]models.User,2)
    users[0] = models.User{"zhangsan1",18,"男"}
    users[1] = models.User{"lisi",18,"女"}
    ctx.JSON(http.StatusOK, users)
})

获取请求参数

query参数

query参数为url路径中?后以key=value形式存储的数据

例如请求路径:https://localhost:8088/user/info?userId=1&name=zhangsan

// query参数
// http://localhost:8088/user/info?userId=1&name=zhangsan
ginServer.POST("/user/info", func(ctx *gin.Context) {
    userId := ctx.Query("userId")
    name := ctx.Query("name")
    ctx.JSON(http.StatusOK, gin.H{
        "userId": userId,
        "name":   name,
    })
})

param参数

param参数为restful风格的url的参数

例如url:https://localhost:8088/user/info/1/zhangsan

// param参数
// https://localhost:8088/user/info/1/zhangsan
ginServer.POST("/user/info/:userId/:name", func(ctx *gin.Context) {
   userId := ctx.Param("userId")
   name := ctx.Param("name")
   ctx.JSON(http.StatusOK, gin.H{
      "userId": userId,
      "name":   name,
   })
})

form表单参数

// 表单参数
ginServer.POST("/user/form", func(ctx *gin.Context) {
    username := ctx.PostForm("username")
    password := ctx.PostForm("password")
    ctx.JSON(http.StatusOK, gin.H{
        "username": username,
        "password": password,
    })
})

json数据

// json数据 GetRawData()获取
ginServer.POST("/user/json", func(ctx *gin.Context) {
    // 获取json字符串,类型为byte
    userData, _ := ctx.GetRawData()
    user := map[string]any{}
    // byte转map
    json.Unmarshal(userData, &user)
    ctx.JSON(http.StatusOK, user)
})

重定向

http重定向

// http重定向
ginServer.GET("/redirect", func(ctx *gin.Context) {
    ctx.Redirect(http.StatusFound, "https://www.baidu.com")
})

注意:如果要重定向到站外地址,必须要写完整地址,例如https://www.baidu.com不能省略https

否则就会与自己主机地址进行拼接,例如如果写成:www.baidu.com,最后访问路径就是http://localhost:8088/www.baidu.com

错误页面处理

ginServer.NoRoute(func(ctx *gin.Context) {
   ctx.HTML(http.StatusNotFound, "404.html", gin.H{
      "err": "你的页面找不到了",
   })
})

路由组

在业务架构,我们通常会把一类相同类型的业务采用相同的前缀名字以便和其它类型的业务区分开,方便开发人员维护和设计。

例如,有关用户的一类业务,接口都是/user/* ,订单的一类业务,接口为/order/*

在gin框架中,我们可以把这一统一的前缀提取出来,定义为一个路由组,方便区分,代码也会更简介。

// 订单业务
orderGroup:=ginServer.Group("/order")
orderGroup.GET("/list", func(ctx *gin.Context) { })
orderGroup.GET("/update", func(ctx *gin.Context) { })
orderGroup.GET("/add", func(ctx *gin.Context) { })
orderGroup.GET("/delete", func(ctx *gin.Context) { })

访问的真实接口就是:

/order/list
/order/update
/order/add
/order/delete

中间件

gin框架允许开发者在处理请求时,加入用户自己设计的函数。

它用于处理一些公共的业务逻辑。例如登录认证、权限校验、数据分页、记录日志、耗时统计等。

也就是我们所说的中间件。

必须是一个gin.HanderFunc类型。

全局注册

  1. 定义一个自定义中间件
func MyHandler() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		fmt.Println("请求 ----- start")
		if true {
			// 请求继续向下执行
			ctx.Next()
		} else {
			// 中断
			ctx.Abort()
		}
		fmt.Println("请求 ----- end")
	}
}
  1. 使用:
ginServer.Use(MyHandler())

注意:注册中间件一定要定义在所有请求的前面

局部注册

如果只想在一类业务或某一个请求上加入中间件,gin框架同样可以做到。

在路由组中加入中间件:

orderGroup:=ginServer.Group("/order", MyHandler())
orderGroup.GET("/list", func(ctx *gin.Context) { })
orderGroup.GET("/update", func(ctx *gin.Context) { })
orderGroup.GET("/add", func(ctx *gin.Context) { })
orderGroup.GET("/delete", func(ctx *gin.Context) { })

在某一个请求上加入中间件,中间件作为参数定义在请求接口后,真正的请求之前

ginServer.GET("/user", MyHandler() ,func(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, gin.H{
        "msg": "GET",
    })
})

gin默认中间件

gin.Default()默认使用了LoggerRecovery中间件

  • Logger中间件将日志写入gin.DefaultWriter,即配置了GIN_MODE = release

  • Recovery中间件会recover任何panic。如果有panic,会写入500响应码。

如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个gin服务。

中间件的数据传递

在定义中间件时可以存储数据,这个数据可以在定义了中间件的任何请求中获取到:

中间件:

func MyHandler() gin.HandlerFunc {
   return func(ctx *gin.Context) {
      ctx.Set("name","zhangsan")
      ctx.Next()
   }
}

请求:

ginServer.GET("/user", MyHandler() ,func(ctx *gin.Context) {
   name,ok:=ctx.Get("name")
   if !ok {
      name = "unknown"
   }
   ctx.JSON(http.StatusOK, gin.H{
      "msg": "GET",
      "name" : name,
   })
})

session

session的使用:

导入session的源码

go get github.com/gin-contrib/sessions

package models

type User struct {
	Id   int64  `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
	Sex  string `json:"sex"`
}
// 创建一个gin服务
ginServer := gin.Default()
// 创建cookie存储
store:=cookie.NewStore([]byte("mycookie"))
// 添加session中间件
ginServer.Use(sessions.Sessions("mysession", store))
// 注册用户模型
gob.Register(models.User{})
// 登录添加session
ginServer.POST("/login", func(ctx *gin.Context) {
    // 创建一个session
    session:=sessions.Default(ctx)
    // 将用户放入session中
    session.Set("user",models.User{
        Id:   1,
        Name: "zhangsan",
        Age:  18,
        Sex:  "男",
    })
    // 保存
    session.Save()
})
ginServer.POST("/session", func(ctx *gin.Context) {
    session:=sessions.Default(ctx)
    // 获取session中信息
    user:=session.Get("user")
    ctx.JSON(http.StatusOK,user)
})
// 设置端口,启动服务
ginServer.Run(":8088")

你可能感兴趣的:(gin框架学习,gin)