感谢大家的关注和支持,大家一起进步呀
前言
Gin是一个用Go(Golang)编写的轻量级HTTP web框架,以其运行速度快、API友好和封装优雅著称。Gin框架支持RESTful风格的API设计,允许开发者使用URL定位资源,并通过HTTP请求类型(如GET、POST、PUT、DELETE等)描述操作。
-
Gin框架的主要特点包括:
-
高性能:
基于Radix树的路由,内存占用小,速度快。
使用了httprouter,速度提高了近40倍。 -
易用性:
-
API设计简洁明了,易于学习和使用。
支持多种数据格式的响应,包括JSON、XML、HTML等。
灵活性: -
支持中间件,可以对请求进行预处理和后处理。
支持路由组,可以更好地组织路由。 -
错误处理:
-
提供了一种方便的方法来收集HTTP请求期间发生的所有错误。
可扩展性: -
内置渲染为JSON、XML和HTML提供了易于使用的API。
允许开发者自定义模板函数,增强模板的灵活性和功能。
1.Gin框架的路由
Gin框架提供了丰富的路由功能,包括基本路由、路由组、命名路由等。开发者可以轻松地定义各种HTTP请求的处理逻辑,并通过路由参数、查询参数等方式获取请求数据。
2.Gin框架的重定向
重定向实现的两种方式
给匿名函数命名,拆出实现
3.Gin框架的中间件
中间件是Gin框架中的一个重要概念,它允许开发者在请求处理流程中的不同阶段插入自定义的逻辑。中间件可以用于日志记录、身份验证、请求验证等多种场景。Gin框架支持全局中间件和局部中间件,可以根据需要灵活配置。
c.Next()
c.About()
4.注意事项
在使用Gin框架时,应确保Go语言版本符合要求(通常需要Go 1.13及以上版本)。
在处理错误和异常情况时,应合理使用panic和recover机制,以避免程序崩溃和数据丢失。
在开发Web应用时,应关注安全性问题,如防止SQL注入、跨站脚本攻击(XSS)等。
总的来说,Gin框架是一个功能强大、易于使用的Go语言Web框架,适合用于开发各种规模的Web应用。
5.gin开发知识点
5.1请求方法
GET
POST
DELETE
PUT
5.2状态码
1xx
2xx 成功相关
3xx 重定向
4xx 客户端请求相关
5xx 服务器相关
5.3前后端分离
前端 vue 好像的页面,接收后端数据,渲染到页面
后端 gin 处理前端的请求,编写接口,供前端调用
5.4交互方式:
ajax jquery
axios vue
表单
5.5参数获取 content-type
- url query查询子字符串参数 根据不同类型参数进行参数绑定
- form 参数,post表单参数
- json 参数
- url param 动态参数
5.6万能的参数获取方式
tag 首字母大写对应上
要传指针
5.7restful API 开发规范
5.8数据库
mysql
redis
mongdb
5.9第三方包
调用别人的日志
5.10测试工具
postman
自己搭建页面,发ajax 这就是前端开发
5.11nginx 部署相关
前端静态文件部署
后端部署
6.Gin框架的安装和使用
安装
go get -u github.com/gin-gonic/gin
导入
import "github.com/gin-gonic/gin"
main.go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// 主函数入口
func main() {
// 创建一个默认的路由引擎
r := gin.Default()
// GET :请求方式;/ping 路径 访问时地址栏输入
// func(c *gin.Context) 请求进来时执行匿名函数
r.GET("/ping", func(c *gin.Context) {
// c 实例化参数,,里面封装了gin的方法
// c.JSON:返回JSON格式数据
// http.StatusOK 状态码
//gin.H 是一个便捷的地图(map)类型,
//gin.H 实际上是 map[string]interface{} 的别名,这意味着它可以存储任何类型的值,并且键是字符串类型。
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
// 启动HTTP服务,默认在0.0.0.0:8080启动服务
r.Run()
}
7.需求与实现
// 文件上传 单文件 多文件
// 重定向 未定义的路由返回统一界面
// 给匿名函数命名拆出
// 路由组 路由组嵌套 也可以分文件
// 中间件
局部注册
在匿名函数前加 中间件()
全局注册
中间件的使用
r.use(中间件())
c.Set("name", "root") 设置值
name := c.MustGet("name").(string) 取值
// 启动多个服务
7.1上传文件
前端
注意属性:multiple
name="avatar"
name="files"
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>上传文件示例</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="avatar">
<input type="submit" value="上传">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Upload Multiple Files</title>
</head>
<body>
<h1>Upload Multiple Files</h1>
<form action="/uploads" method="post" enctype="multipart/form-data">
<input type="file" name="files" multiple>
<button type="submit">Upload</button>
</form>
</body>
</html>
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"path/filepath"
)
// 上传按钮
//点击上传
// 后端存在哪里
func main() {
r := gin.Default()
// 加载模板
r.LoadHTMLFiles("templates/upload.html")
r.LoadHTMLFiles("templates/uploads.html")
// 返回界面
r.GET("/upload", func(c *gin.Context) {
c.HTML(http.StatusOK, "upload.html", nil)
})
r.GET("/uploads", func(c *gin.Context) {
c.HTML(http.StatusOK, "uploads.html", nil)
})
// upfile
r.POST("/upload", func(c *gin.Context) {
// 接收文件 保存到本地
// 单文件
f, err := c.FormFile("avatar")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
})
return
}
// 保存到指定目录
dst := "upload/" + f.Filename
err = c.SaveUploadedFile(f, dst)
if err != nil {
fmt.Println("出错啦")
fmt.Println(err.Error())
return
}
// 返回相应
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("%s uploaded success!", f.Filename),
})
})
// upfile
r.POST("/uploads", func(c *gin.Context) {
// 接收文件 保存到本地
// 多文件
form, err := c.MultipartForm()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
})
return
}
files := form.File["files"]
for _, file := range files {
fmt.Println(file.Filename)
err = c.SaveUploadedFile(file, filepath.Join("upload", file.Filename))
if err != nil {
fmt.Println("出错啦")
fmt.Println(err.Error())
return
}
}
// 返回相应
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("%d files uploaded success!", len(files)),
})
})
// 重定向
r.GET("/abc", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
})
r.GET("/abed", func(c *gin.Context) {
c.Request.URL.Path = "/uploads"
r.HandleContext(c)
})
r.GET("/aaa", aaaHandeler)
r.NoRoute(func(c *gin.Context) {
c.String(http.StatusNotFound, "没有这个网页")
})
r.Run()
}
func aaaHandeler(c *gin.Context) {
fmt.Println("xxxxxxx")
c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
}
7.2路由组
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
// 创建一个默认的 Gin 引擎
r := gin.Default()
// 创建一个路由组
api := r.Group("/api")
{
// 在组内添加 GET 请求路由
api.GET("/user", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Get user",
})
})
// 在组内添加 POST 请求路由
api.POST("/user", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Post user",
})
})
// 你可以为组添加更多的路由
api.PUT("/user", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Put user",
})
})
api.DELETE("/user", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Delete user",
})
})
}
// 另一个路由组
v1 := r.Group("/v1")
{
v1.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
// 你可以在组内嵌套组
stats := v1.Group("/stats")
{
stats.GET("/cpu", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "cpu stats",
})
})
stats.GET("/memory", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "memory stats",
})
})
}
}
// 启动 Gin 引擎
r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务
}
7.3中间件
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"log"
"time"
)
func CostTime(format string) gin.HandlerFunc {
return func(c *gin.Context) {
begin := time.Now()
fmt.Println(begin.Format(format))
//c中设置值,后续处理函数可以拿到
c.Set("name", "root")
// 调用该请求处理剩余的程序
c.Next()
// 不调用该请求处理剩余的程序
// c.Abort() 遇到这个程序不在往下走
//计算耗时
cost := time.Since(begin)
log.Panicln(cost)
}
}
func main() {
r := gin.Default()
r.GET("/a", CostTime("2024-12-12"), func(c *gin.Context) {
name := c.MustGet("name").(string)
log.Println(name)
fmt.Println(name)
c.JSON(200, gin.H{
"name": name,
})
})
r.Run()
}
7.4请求参数 返回参数 重定向 非法页面处理
package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
type Login struct {
User string `json:"user" form:"user" binding:"require"`
Password string `json:"password" form:"password" binding:"require"`
}
// 主函数入口
func main() {
// 创建一个默认的路由引擎
r := gin.Default()
// GET :请求方式;/ping 路径 访问时地址栏输入
// func(c *gin.Context) 请求进来时执行匿名函数
r.GET("/hello", func(c *gin.Context) {
// c 实例化参数,,里面封装了gin的方法
// c.JSON:返回JSON格式数据
// http.StatusOK 状态码
//gin.H 是一个便捷的地图(map)类型,
//gin.H 实际上是 map[string]interface{} 的别名,这意味着它可以存储任何类型的值,并且键是字符串类型。
c.JSON(http.StatusOK, gin.H{
"user": gin.H{
"id": 123,
"name": "John Doe",
},
"message": "Hello, world!",
})
})
r.Any("/home", func(context *gin.Context) {
// 根据请求的方法做处理
if context.Request.Method == http.MethodGet {
context.String(http.StatusOK, "欢迎来到首页")
}
})
r.GET("/login", func(c *gin.Context) {
// 结构体
var msg struct {
Name string `json:"user"`
Pwd string `json:"password"`
IsLogin int `json:"is_login"`
}
msg.Name = "root"
msg.Pwd = "123456"
msg.IsLogin = 1 // 1表示成功登录
c.JSON(http.StatusOK, msg)
})
r.GET("/sms_login/search", func(c *gin.Context) {
// 结构体
var msg struct {
Name string `json:"username"`
Pwd string `json:"password"`
IsLogin string `json:"is_login"`
}
// 查询参数获取 sms_login/search?username=xx&password=1234
// 查询参数获取 sms_login/search?password=1234
username := c.DefaultQuery("username", "游客")
password := c.Query("password")
msg.Name = username
msg.Pwd = password
msg.IsLogin = "ok" // 1表示成功登录
c.JSON(http.StatusOK, msg)
})
// form表单
r.POST("/sms_login/search", func(c *gin.Context) {
// 结构体
var msg struct {
Name string `json:"username"`
Pwd string `json:"password"`
IsLogin string `json:"is_login"`
}
username := c.DefaultPostForm("username", "游客")
password := c.PostForm("password")
fmt.Println(password)
msg.Name = username
msg.Pwd = "*******"
msg.IsLogin = "ok" // 1表示成功登录
c.JSON(http.StatusOK, msg)
})
// 获取json参数
r.POST("/json", func(c *gin.Context) {
// 结构体
var msg struct {
Name map[string]interface{} `json:"username"`
Pwd string `json:"password"`
IsLogin string `json:"is_login"`
}
user, _ := c.GetRawData() //请求体中拿数据
var username map[string]interface{}
// 反序列化
_ = json.Unmarshal(user, &username)
msg.Name = username
msg.IsLogin = "ok" // 1表示成功登录
c.JSON(http.StatusOK, msg)
})
// 获取path参数
r.GET("/path/:username/:password", func(c *gin.Context) {
// 结构体
var msg struct {
Name string `json:"username"`
Pwd string `json:"password"`
IsLogin string `json:"is_login"`
}
username := c.Param("username")
password := c.Param("password")
fmt.Println(password)
msg.Name = username
msg.Pwd = "*******"
msg.IsLogin = "ok" // 1表示成功登录
c.JSON(http.StatusOK, msg)
})
// 参数绑定
r.POST("/loginJson", func(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err != nil {
fmt.Printf("login info:%#v\n\n", login)
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// 重定向
r.GET("/abc", func(c *gin.Context) {
// c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
c.Request.URL.Path = "/upload"
r.HandleContext(c)
})
r.NoRoute(func(c *gin.Context) {
c.String(http.StatusNotFound, "没有这个网页")
})
// 启动HTTP服务,默认在0.0.0.0:8080启动服务
r.Run(":8080")
}
小结
基于gin框架的简单使用就到此结束了,本文主要是概念性内容,和一些重要开发经验,框架就是个半成品,需要去熟悉它的源码执行流程,希望大家能够有所收获 。