前言
前面几篇文章介绍了不少go相关编程知识点,今天我们进入项目阶段,首先我们开始学习用gin框架来手把手搭建一个web应用。
gin简介
Gin 是一个用 Go 编写的轻量级的 web 框架,它提供了快速的路由(router)和中间件(middleware)机制,使得编写 Web 应用程序变得更加简单和高效。以下是 Gin 框架的一些基本特性和使用方法。
特性
-
快速和轻量: Gin 是一个轻量级的框架,性能优越。它的设计目标是快速、简单、易于学习和使用。
-
路由引擎: Gin 提供了强大的路由引擎,可以方便地定义路由和处理请求。
-
中间件: Gin 支持中间件机制,允许你在请求被处理之前或之后执行一些操作。这使得添加日志、身份验证、错误处理等功能变得非常容易。
-
组路由和嵌套路由: Gin 允许你创建组路由,以便将相似的路由分组在一起。嵌套路由允许你在一个路由组内定义更具体的子路由。
-
渲染引擎支持: Gin 支持多种渲染引擎,包括 JSON、HTML、XML、YAML 等。
-
参数绑定: Gin 支持对请求中的参数进行绑定,包括查询参数、表单参数和 JSON 数据。
-
静态文件服务: Gin 可以用于提供静态文件服务,例如图片、CSS 文件等
核心模块
-
Router(路由器): Gin 的路由器模块负责处理传入请求并将其分派到相应的处理函数。它支持定义不同 HTTP 方法的路由,并提供了灵活的路由匹配机制。
-
Middleware(中间件): Gin 的中间件机制允许在请求被处理之前或之后执行一些通用的操作。中间件可以用于添加日志、身份验证、错误处理等功能,使代码更模块化和可维护。
-
Context(上下文): 上下文是一个关键组件,代表了每个请求的上下文信息。在处理函数中,你可以通过上下文对象访问请求的参数、头部信息、响应等内容,以及调用一些方便的方法来处理请求。
-
Rendering(渲染引擎): Gin 提供了对多种渲染引擎的支持,包括 JSON、HTML、XML、YAML 等。这使得你可以根据需要选择合适的渲染引擎。
-
Group(路由组): Gin 允许你创建路由组,将相似的路由分组在一起。这使得代码结构更清晰,可以更方便地组织和管理路由。
项目实战
介绍完gin的相关知识,我们来手把手搭建一个web项目。
创建项目
创建一个go-web项目,并且用go mod init初始化,将依赖给mod管理
这里介绍下web项目的基本代码结构:
app:关于项目的相关内容,里面有controller、service、dao、middleware等。app里面的结构划分并不是固定的,也有以领域划分的形式,这个可以自己定义。
go.mod:这个是执行go mod init命令生成的,用来管理项目的依赖
main.go:项目启动的入口
安装gin
在项目的go.mod同级目录执行:go get -u github.com/gin-gonic/gin安装gin组件,安装完成go.mod文件中就有了这些依赖:
开发接口
在main方法中启动gin并且开发一个简单的接口,启动项目在8080端口监听:
package main
import "github.com/gin-gonic/gin"
func main() {
// 创建 Gin 实例
r := gin.Default()
// 定义路由
r.GET("/hello/:name", func(c *gin.Context) {
//返回值直接通过context而不是return
c.JSON(200, gin.H{"message": "Hello, Gin!"})
})
// 启动服务器
r.Run(":8080")
}
注意: r.Run(":8080")这行代码已经要放在最后,以为这个是开启监听,程序会阻塞在这个地方,如果放在路由定义之前,那么路由的绑定都没有执行,相当于没有定义接口
控制台看到启动一个项目,监听在8080端口上:
访问一下接口,可以得到返回值:
这样一个最简单的接口我们就实现完成了,但是在实际过程中我们的接口处理逻辑是非常复杂的,所以需要单独在一层controller里面书写,这样就需要和路径注册分开,下面我们来实现一下:
我们把所有接口的定义都放在router.go文件,接口的实现放在controller文件夹下
定义一个UserController,添加GetUser和CreateUser两个方法:
package controller
import (
"github.com/gin-gonic/gin"
"go-web/app/models"
"net/http"
)
func GetUser(ctx *gin.Context) {
var name = ctx.Param("name")
ctx.JSON(http.StatusOK, models.User{
Name: name,
})
}
func CreateUser(ctx *gin.Context) {
var user *models.User
if err := ctx.ShouldBind(&user); err != nil {
ctx.JSON(http.StatusInternalServerError, "参数异常")
return
}
ctx.JSON(http.StatusOK, user)
}
在router.go里面绑定路由:
package routers
import (
"github.com/gin-gonic/gin"
"go-web/app/controller"
"go-web/app/middleware"
)
func init() {
//创建一个gin示例
router := gin.Default()
//注册路径
user := router.Group("/user")
{
user.GET("/:name", middleware.UserMiddleware(), controller.GetUser)
user.POST("/create", controller.CreateUser)
}
//监听端口
router.Run(":8080")
}
可以看到这里我把初始化gin的一些操作又main程序放在router.go的init方法里面了,熟悉go的朋友都知道只要这个go文件被引入,那么init方法就会执行,所以我们只需要在mian里面引入这个router.go就可以
访问下添加用户的接口是通的:
到这里已经搭建了一个基本的go版本的web项目,剩下的只需要添加一些逻辑,下面再介绍一些比较常用的一些gin项目的操作:
gin.context
gin.Context
是 Gin 框架中的一个关键结构,代表每个请求的上下文信息。它包含了许多有用的方法和属性,用于处理请求和构建响应。以下是一些常用的 gin.Context
方法和属性:
1. 获取请求信息:
-
c.Request
: 获取原始的http.Request
对象,可以用于访问更底层的请求信息。 -
c.Param(key)
: 获取 URL 中的参数值。 -
c.Query(key)
: 获取查询参数的值。 -
c.PostForm(key)
: 获取表单参数的值。 -
c.GetHeader(key)
: 获取请求头部的值。
2. 发送响应:
-
c.JSON(code int, obj interface{})
: 发送 JSON 响应。 -
c.XML(code int, obj interface{})
: 发送 XML 响应。 -
c.HTML(code int, name string, data interface{})
: 发送 HTML 响应。 -
c.String(code int, format string, values ...interface{})
: 发送纯文本响应。
3. 处理重定向和错误:
-
c.Redirect(code int, location string)
: 执行重定向。 -
c.AbortWithStatus(code int)
: 中止请求并发送指定状态码的响应。
4. 其他常用方法:
-
c.Next()
: 执行后续处理函数,常用于中间件。 -
c.ShouldBind(&obj)
: 将请求的数据绑定到结构体或对象。 -
c.ShouldBindJSON(&obj)
: 将请求的 JSON 数据绑定到结构体或对象。 -
c.ShouldBindQuery(&obj)
: 将查询参数绑定到结构体或对象。 -
c.Get(key string)
: 获取由中间件设置的键值对。
关于context的使用上面的示例中我用到了GET和POST请求的两种具体传参以及返回的使用,方法比较多大家可以感兴趣的试一试。
Middleware
在 Gin 中,中间件(Middleware)是一种在请求到达处理函数之前或之后执行的功能模块。中间件可以用于执行一些通用的操作,例如日志记录、权限验证、请求处理等。在你的场景中,你可以编写一个中间件来拦截 HTTP 请求,并对请求的 Header 数据进行处理。
下面我定义了一个UserMiddleware的前置处理组件,在处理之前我们获取name参数,如果是hello就往上下文中设置一个参数值:
package middleware
import (
"github.com/gin-gonic/gin"
)
func UserMiddleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
name := ctx.Query("name")
if name == "hello" {
ctx.Set("name", "hello, world")
}
ctx.Next()
}
}
将Middleware绑定到具体的路由上,也可以绑定到路由组group上,对整组API生效,不过这了的配置我没有找到类似于Spring里面切面的表达式配置方式,没有那么灵活