gin-crud


前言

大概内容:

序言

主要内容概述如下:

  1. 项目初始化:首先着手创建一个新的Gin Web项目,确保具备进行后续开发工作的基础框架。

  2. CRUD接口实现:在构建的Gin项目中,着手实现一组用于模拟数据操作的RESTful API接口。此阶段涵盖了创建(Create)、检索(Read)、更新(Update)与删除(Delete)功能的完整实现,确保每个接口均能准确对应相应的数据操作。

  3. 接口测试:借助Apifox这类专业的API测试工具,对上述实现的增删查改接口进行全面的功能验证与性能测试。通过构造符合接口定义的请求,发送至指定端点,分析接收到的响应,以确保接口行为符合预期,数据传递准确无误,同时监测响应时间、错误处理等性能指标,保证接口的稳定性和可靠性。

  4. 文档编制:最后,为已实现的接口集编写详尽的Swagger文档。利用Swagger的标准化描述格式,清晰阐述各个接口的路由、请求方法、请求参数、预期响应结构、HTTP状态码含义等关键信息,形成一套完整的API参考手册。此举旨在提升项目的技术透明度,方便团队内外的开发者查阅、理解和调用接口,促进代码的可维护性与协作效率。
    实验环境:

操作系统:实验环境运行于Windows 11操作系统之上。
开发环境:已配备Goland作为Go语言的主要集成开发环境(IDE)。
编程语言与框架:已预先安装Go编程语言(全称为Golang),这是实验所依赖的核心编程环境。在本次实验中,我们选用Go语言生态系统中的Gin框架作为主要的Web开发框架进行操作。Gin以其轻量、高性能的特点,为构建高效、可扩展的Web应用程序提供了坚实基础。
特别说明:Goland是专为Go语言设计的集成开发工具,而Go语言的正式名称为Golang。二者在实验环境中分别扮演开发工具与编程语言的角色。


提示:以下是本篇文章正文内容,下面案例仅供参考

初始化项目

新建项目

打开goland,File->New->Projectimage.png
选择Go,然后我们需要改变的是Location(路径)和添加代理Environment(环境)
image.png
我们需要给自己的项目设置项目存储路径,我这里是D:\project\go\workspace\test\
gin-gorm-crud是我的项目名字,也是项目文件夹名字,你可以随意设置自己的项目名字。
image.png
在使用go的时候,会需要安装一些第三方包
如果不配置Environment代理,那么则会从go的官网上去拉取第三方包,由于go官网的服务器在国外,访问速度受到限制,这样通常会出现访问比较慢的现象或者直接访问可能导致的网络问题,而goproxy.cn是一个在中国广泛使用的Go语言代理服务,可以显著加速在中国境内访问可能受限的海外模块仓库的速度,同时避免直接访问可能导致的网络问题。
给Environment添加上如下环境变量设定

GOPROXY=https://goproxy.cn,direct

image.png
其余不改变,点击Create,你的项目就已经创建成功了。
image.png

安装Gin:

使用Go的包管理工具go get命令从GitHub仓库下载并安装Gin框架。在命令行终端中执行:

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

这里的-u参数表示同时更新(upgrade)依赖包至最新版本。如果您不希望自动升级,可以省略此参数。
示例:
image.png

验证安装:

安装完成后,可以在命令行中运行如下命令来检查Gin的版本,确认安装成功:

go list -m github.com/gin-gonic/gin

如果一切正常,命令将返回已安装的Gin框架版本信息。
image.png

应用示例

至此,Gin框架已安装完毕,您可以开始使用它来创建新的Go Web项目或在现有项目中引入Gin进行开发。例如,下面是一个简单的Gin应用示例:
根目录下新建文件main.go

package main

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

func main() {
	r := gin.Default()
	r.GET("/test", func(c *gin.Context) {
		c.String(200, "hello world!")
	})
	r.Run() // 默认监听并服务在 http://localhost:8080
}

这段代码启动了一个Gin服务器,定义了一个GET请求的路由/test,当访问该路由时,服务器将返回一个包含消息Hello, Gin!的JSON响应。运行此程序,即可通过浏览器访问http://localhost:8080/test来测试您的第一个Gin应用,你会看见浏览器上显示Hello World!

如何执行

在命令台项目根目录下执行go run .\main.go或者在main.go文件上右键执行Run ‘go build main.go’
image.png
image.png

gin模拟crud

具体实现

注意:以下代码均为在main.go里面操作的
定义一个结构体来映射JSON数据

// 定义一个结构体来映射JSON数据
type UserModel struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

定义一个结构体来映射返回的数据

// 定义一个结构体来映射返回的数据
type Response struct {
	Code int    `json:"code"`
	Data any    `json:"data"`
	Msg  string `json:"msg"`
}

给结构体UserModel添加实体测试用例user1,user2,user3,并添加至实体数组users

var user1 = UserModel{ID: 1, Name: "aaa", Age: 16}
var user2 = UserModel{ID: 2, Name: "bbb", Age: 17}
var user3 = UserModel{ID: 3, Name: "ccc", Age: 18}

var users = []UserModel{user1, user2, user3}

定义主函数

func main() {
	// 创建gin路由
	router := gin.Default()

	// 定义user的路由分组
	userGroup := router.Group("/user")
	{
		userGroup.GET("/", _list)
		userGroup.POST("/", _create)
		userGroup.GET("/:id", _get)
		userGroup.PUT("/:id", _update)
		userGroup.DELETE("/:id", _delete)
	}

	// 启动HTTP服务器并监听在8080端口
	router.Run(":8080")
}

添加增删改查函数

func _list(c *gin.Context) {
	c.JSON(http.StatusOK, Response{Code: 200, Data: users, Msg: "success"})
}

func _create(c *gin.Context) {
	var user UserModel
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error()})
		return
	}
	user.ID = len(users) + 1
	users = append(users, user)
	c.JSON(http.StatusCreated, Response{Code: http.StatusCreated, Data: user, Msg: "success"})
}

func _get(c *gin.Context) {
	id := c.Param("id")
	for _, user := range users {
		if strconv.Itoa(user.ID) == id {
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Data: user, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

func _update(c *gin.Context) {
	id := c.Param("id")
	for index, user := range users {
		if strconv.Itoa(user.ID) == id {
			users = append(users[:index], users[index+1:]...)
			var updatedUser UserModel
			if err := c.ShouldBindJSON(&updatedUser); err != nil {
				c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error()})
				return
			}
			updatedUser.ID = user.ID
			users = append(users, updatedUser)
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

func _delete(c *gin.Context) {
	id := c.Param("id")
	for index, user := range users {
		if strconv.Itoa(user.ID) == id {
			users = append(users[:index], users[index+1:]...)
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

main.go完整代码

package main

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

// 定义一个结构体来映射JSON数据
type UserModel struct {
	ID int `json:"id"`
	Name string `json:"name"`
	Age int `json:"age"`
}

// 定义一个结构体来映射返回的数据
type Response struct {
	Code int `json:"code"`
	Data interface{} `json:"data"`
	Msg string `json:"msg"`
}

var user1 = UserModel{ID: 1, Name: "aaa", Age: 16}
var user2 = UserModel{ID: 2, Name: "bbb", Age: 17}
var user3 = UserModel{ID: 3, Name: "ccc", Age: 18}

var users = []UserModel{user1, user2, user3}

func _list(c *gin.Context) {
	c.JSON(http.StatusOK, Response{Code: 200, Data: users, Msg: "success"})
}

func _create(c *gin.Context) {
	var user UserModel
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error()})
		return
	}
	user.ID = len(users) + 1
	users = append(users, user)
	c.JSON(http.StatusCreated, Response{Code: http.StatusCreated, Data: user, Msg: "success"})
}

func _get(c *gin.Context) {
	id := c.Param("id")
	for _, user := range users {
		if strconv.Itoa(user.ID) == id {
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Data: user, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

func _update(c *gin.Context) {
	id := c.Param("id")
	for index, user := range users {
		if strconv.Itoa(user.ID) == id {
			users = append(users[:index], users[index+1:]...)
			var updatedUser UserModel
			if err := c.ShouldBindJSON(&updatedUser); err != nil {
				c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error()})
				return
			}
			updatedUser.ID = user.ID
			users = append(users, updatedUser)
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

func _delete(c *gin.Context) {
	id := c.Param("id")
	for index, user := range users {
		if strconv.Itoa(user.ID) == id {
			users = append(users[:index], users[index+1:]...)
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

func main() {
	// 创建gin路由
	router := gin.Default()
	// 定义user的路由分组
	userGroup := router.Group("/user")
	{
		userGroup.GET("/", _list)
		userGroup.POST("/", _create)
		userGroup.GET("/:id", _get)
		userGroup.PUT("/:id", _update)
		userGroup.DELETE("/:id", _delete)
	}

	// 启动HTTP服务器并监听在8080端口
	router.Run(":8080")
}

apifox验证crud

运行项目,打开apifox验证下面请求是否编写成功

GET http://127.0.0.1:8080/user
POST http://127.0.0.1:8080/user
GET http://127.0.0.1:8080/user/{id}
PUT http://127.0.0.1:8080/user{id}
DELETE http://127.0.0.1:8080/user/{id}

GET http://127.0.0.1:8080/user
image.png
POST http://127.0.0.1:8080/user
image.png
GET http://127.0.0.1:8080/user/{id}
image.png
PUT http://127.0.0.1:8080/user{id}
image.png
image.png
DELETE http://127.0.0.1:8080/user/{id}
image.png

gin模拟crud添加swagger

安装swagger

使用Go的包管理工具go get命令从GitHub仓库下载并安装Gin框架。在命令行终端中执行:

go get -u github.com/swaggo/swag/cmd/swag
go get -u github.com/swaggo/files
go get -u github.com/swaggo/gin-swagger

添加swagger注释

在main函数路由内部使用swagger

// Swagger UI endpoint
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

在main函数上方添加swagger注释

// @title User Management API
// @version 1.0
// @description This is a sample User Management API using Gin framework.

// @host localhost:8080
// @BasePath

UserModelResponse结构体添加注释

// 定义一个结构体来映射JSON数据
type UserModel struct {
	// 用户ID
	ID int `json:"id"`
	// 用户名
	Name string `json:"name"`
	// 年龄
	Age int `json:"age"`
}

// 定义一个结构体来映射返回的数据
type Response struct {
	// 状态码
	Code int `json:"code"`
	// 数据
	Data interface{} `json:"data"`
	// 消息
	Msg string `json:"msg"`
}

在_list函数上添加swagger注释
如果出现跨域问题则将// @Router /user [get]改为// @Router /user/ [get]
下图为跨域问题:
image.png

// @Summary 获取用户列表
// @Description 获取所有用户的信息
// @Tags User
// @Produce json
// @Success 200 {object} Response{data=[]UserModel}
// @Router /user [get]

在_create函数上添加swagger注释
如果出现跨域问题则将// @Router /user [post]改为// @Router /user/ [post]

// @Summary 创建用户
// @Description 新增一个用户
// @Tags User
// @Accept json
// @Produce json
// @Param user body UserModel true "用户信息"
// @Success 201 {object} Response{data=UserModel}
// @Failure 400 {object} Response
// @Router /user [post]

在_get函数上添加swagger注释

// @Summary 获取用户
// @Description 根据ID获取单个用户信息
// @Tags User
// @Produce json
// @Param id path string true "用户ID"
// @Success 200 {object} Response{data=UserModel}
// @Failure 404 {object} Response
// @Router /user/{id} [get]

在_update函数上添加swagger注释

// @Summary 更新用户
// @Description 更新指定ID用户的全部信息
// @Tags User
// @Accept json
// @Produce json
// @Param id path string true "用户ID"
// @Param user body UserModel true "更新后的用户信息"
// @Success 200 {object} Response
// @Failure 400 {object} Response
// @Failure 404 {object} Response
// @Router /user/{id} [put]

在_delete函数上添加swagger注释

// @Summary 删除用户
// @Description 根据ID删除一个用户
// @Tags User
// @Produce json
// @Param id path string true "用户ID"
// @Success 200 {object} Response
// @Failure 404 {object} Response
// @Router /user/{id} [delete]

设置跨域

Gin v1.x 及更高版本已经内置了 CORS 中间件。只需在路由设置中添加 gin-contrib/cors 包提供的中间件即可。确保已通过 go get 安装该包:

go get -u github.com/gin-contrib/cors

然后在你的应用初始化代码中导入并配置 CORS 中间件(一般写在路由最上方):

// 启用跨域请求, 允许所有源。一般写在路由最上方
router.Use(cors.Default())

生成 Swagger 文档

在项目根目录下运行swag命令生成 Swagger JSON 和 YAML 文件:
当main.go文件在项目根目录下时,执行以下代码

swag init

image.png
当main.go文件在项目根目录下的src/cmd目录下时,执行以下代码,-g后面跟着的是main.go的相对于项目根目录的相对路径,你可以替换为你的main.go文件所在的路径

swag init -g ./src/cmd/main.go -o ./docs  #初始化文档

main.go引入docs文件夹

_ "your-project-name/docs" //这里的your-project-name是你的项目名

下图是我的引用
image.png

执行

在命令台项目根目录下执行go run .\main.go,其中.\main.go为main.go的相对于项目的目录
或者在main.go文件上右键执行Run ‘go build main.go’

go run main.go

打开浏览器输入http://127.0.0.1:8080/swagger/index.html
出现下图即为成功:
image.png
其中创建用户,不需要使用id,测试的时候把id删了即可,因为我没有设置传输方式,所以示例包括了id,更新用户同理
image.png

注意事项

swagger注释每改一次,都要重新生成swagger文档,即初始化swagger文档。
如果出现如下结果,请重新去添加swagger注释那里看看,修改完后请用命令重新初始化swagger文档
重新打开swagger文档:http://127.0.0.1:8080/swagger/index.html
image.png

源码

package main

import (
	_ "gin-gorm-crud/docs"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
	"net/http"
	"strconv"
)

// 定义一个结构体来映射JSON数据
type UserModel struct {
	// 用户ID
	ID int `json:"id"`
	// 用户名
	Name string `json:"name"`
	// 年龄
	Age int `json:"age"`
}

// 定义一个结构体来映射返回的数据
type Response struct {
	// 状态码
	Code int `json:"code"`
	// 数据
	Data interface{} `json:"data"`
	// 消息
	Msg string `json:"msg"`
}

var user1 = UserModel{ID: 1, Name: "aaa", Age: 16}
var user2 = UserModel{ID: 2, Name: "bbb", Age: 17}
var user3 = UserModel{ID: 3, Name: "ccc", Age: 18}

var users = []UserModel{user1, user2, user3}

// @Summary 获取用户列表
// @Description 获取所有用户的信息
// @Tags User
// @Produce json
// @Success 200 {object} Response{data=[]UserModel}
// @Router /user/ [get]
func _list(c *gin.Context) {
	c.JSON(http.StatusOK, Response{Code: 200, Data: users, Msg: "success"})
}

// @Summary 创建用户
// @Description 新增一个用户
// @Tags User
// @Accept json
// @Produce json
// @Param user body UserModel true "用户信息"
// @Success 201 {object} Response{data=UserModel}
// @Failure 400 {object} Response
// @Router /user/ [post]
func _create(c *gin.Context) {
	var user UserModel
	if err := c.ShouldBindJSON(&user); err != nil {
		c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error()})
		return
	}
	user.ID = len(users) + 1
	users = append(users, user)
	c.JSON(http.StatusCreated, Response{Code: http.StatusCreated, Data: user, Msg: "success"})
}

// @Summary 获取用户
// @Description 根据ID获取单个用户信息
// @Tags User
// @Produce json
// @Param id path string true "用户ID"
// @Success 200 {object} Response{data=UserModel}
// @Failure 404 {object} Response
// @Router /user/{id} [get]
func _get(c *gin.Context) {
	id := c.Param("id")
	for _, user := range users {
		if strconv.Itoa(user.ID) == id {
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Data: user, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

// @Summary 更新用户
// @Description 更新指定ID用户的全部信息
// @Tags User
// @Accept json
// @Produce json
// @Param id path string true "用户ID"
// @Param user body UserModel true "更新后的用户信息"
// @Success 200 {object} Response
// @Failure 400 {object} Response
// @Failure 404 {object} Response
// @Router /user/{id} [put]
func _update(c *gin.Context) {
	id := c.Param("id")
	for index, user := range users {
		if strconv.Itoa(user.ID) == id {
			users = append(users[:index], users[index+1:]...)
			var updatedUser UserModel
			if err := c.ShouldBindJSON(&updatedUser); err != nil {
				c.JSON(http.StatusBadRequest, Response{Code: http.StatusBadRequest, Msg: err.Error()})
				return
			}
			updatedUser.ID = user.ID
			users = append(users, updatedUser)
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

// @Summary 删除用户
// @Description 根据ID删除一个用户
// @Tags User
// @Produce json
// @Param id path string true "用户ID"
// @Success 200 {object} Response
// @Failure 404 {object} Response
// @Router /user/{id} [delete]
func _delete(c *gin.Context) {
	id := c.Param("id")
	for index, user := range users {
		if strconv.Itoa(user.ID) == id {
			users = append(users[:index], users[index+1:]...)
			c.JSON(http.StatusOK, Response{Code: http.StatusOK, Msg: "success"})
			return
		}
	}
	c.JSON(http.StatusNotFound, Response{Code: http.StatusNotFound, Msg: "user not found"})
}

// @title User Management API
// @version 1.0
// @description This is a sample User Management API using Gin framework.

// @host localhost:8080
// @BasePath
func main() {
	// 创建gin路由
	router := gin.Default()
	// 启用跨域请求, 允许所有源。一般写在路由最上方
	router.Use(cors.Default())
	// Swagger UI endpoint
	router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	// 定义user的路由分组
	userGroup := router.Group("/user")
	{
		userGroup.GET("/", _list)
		userGroup.POST("/", _create)
		userGroup.GET("/:id", _get)
		userGroup.PUT("/:id", _update)
		userGroup.DELETE("/:id", _delete)
	}

	// 启动HTTP服务器并监听在8080端口
	router.Run(":8080")
}

总结

本文首先阐述了如何运用Goland集成开发环境,结合Gin Web框架搭建基础服务器架构。继而,我们定义了代表用户数据的结构体以及用于封装响应结果的返回结构体。在此基础上,针对用户实体设计并实现了涵盖创建(Create)、读取(Read)、更新(Update)与删除(Delete)功能的全套CRUD接口。

为了确保上述接口的正确性与功能性,我们采用了Apifox工具进行全面的接口验证测试。这一过程包括但不限于发送适当的HTTP请求至各接口端点,分析接收到的响应数据以确认其与预期行为相符,以及检查返回状态码、数据格式等是否符合接口规范。

最后,为进一步提升项目文档化程度与可维护性,我们为所构建的API接口集添加了详细的Swagger文档。此举不仅为开发者提供了直观易懂的交互式接口说明,还通过标准化的格式描述了各个接口的路由、请求方法、参数、响应结构及HTTP状态码等关键信息,便于团队成员及外部合作者理解接口逻辑、进行调试与集成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值