百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Go 实现restful接口CRUD操作范例(go+gin+mongo)

wuantov 2025-07-19 23:13 8 浏览

Go 实现restful接口CRUD操作范例(go+gin+mongo)

以下是使用Gin和MongoDB实现RESTful API CRUD操作的示例代码。

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "strconv"

    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type Book struct {
    ID     primitive.ObjectID `json:"id" bson:"_id,omitempty"`
    Title  string             `json:"title" bson:"title"`
    Author string             `json:"author" bson:"author"`
}

var collection *mongo.Collection

func main() {
    // Connect to MongoDB
    clientOptions := options.Client().ApplyURI("mongodb://192.168.6.145:27017")
    client, err := mongo.Connect(context.Background(), clientOptions)
    if err != nil {
        log.Fatal(err)
    }

    // Check the connection
    err = client.Ping(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    collection = client.Database("books").Collection("books")

    // Create a Gin router
    router := gin.Default()

    // Define book routes group
    bookRoutes := router.Group("/v1/books")
    {
        bookRoutes.GET("", getBooks)
        bookRoutes.GET("/:id", getBook)
        bookRoutes.POST("", createBook)
        bookRoutes.PUT("/:id", updateBook)
        bookRoutes.DELETE("/:id", deleteBook)
    }

    // Start the server
    router.Run(":8080")
}

func getBooks(c *gin.Context) {
    // Find all books
    cursor, err := collection.Find(context.Background(), bson.M{})
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get books"})
        return
    }

    var books []Book
    if err := cursor.All(context.Background(), &books); err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get books"})
        return
    }

    c.JSON(http.StatusOK, books)
}

func getBook(c *gin.Context) {
    // Get the book ID from the URL parameters
    id, err := primitive.ObjectIDFromHex(c.Param("id"))
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid book ID"})
        return
    }

    // Find the book by ID
    var book Book
    err = collection.FindOne(context.Background(), bson.M{"_id": id}).Decode(&book)
    if err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Book not found"})
        return
    }

    c.JSON(http.StatusOK, book)
}

func createBook(c *gin.Context) {
    // Bind the JSON request body to a Book object
    var book Book
    if err := c.BindJSON(&book); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse request body"})
        return
    }

    // Insert the book into the database
    result, err := collection.InsertOne(context.Background(), book)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create book"})
        return
    }

    // Set the book ID
    book.ID = result.InsertedID.(primitive.ObjectID)

    c.JSON(http.StatusCreated, book)
}

func updateBook(c *gin.Context) { 
 // Get the book ID from the URL parameters 
 id, err := primitive.ObjectIDFromHex(c.Param("id"))
 if err != nil { 
  c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid book ID"}) 
  return  
 }
 // Bind the JSON request body to a Book object
 var book Book
 if err := c.BindJSON(&book); err != nil {
     c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse request body"})
     return
 }

 // Set the book ID
 book.ID = id

 // Update the book in the database
 result, err := collection.ReplaceOne(context.Background(), bson.M{"_id": id}, book)
 if err != nil {
     c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update book"})
     return
 }

 if result.MatchedCount == 0 {
     c.JSON(http.StatusNotFound, gin.H{"error": "Book not found"})
     return
 }

 c.JSON(http.StatusOK, book) 
}
func deleteBook(c *gin.Context) { 
 // Get the book ID from the URL parameters 
 id, err := primitive.ObjectIDFromHex(c.Param("id")) 
 if err != nil { 
  c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid book ID"}) 
  return 
 }
 // Delete the book from the database
 result, err := collection.DeleteOne(context.Background(), bson.M{"_id": id})
 if err != nil {
     c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete book"})
     return
 }

 if result.DeletedCount == 0 {
     c.JSON(http.StatusNotFound, gin.H{"error": "Book not found"})
     return
 }

 c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Book with ID %s has been deleted", id.Hex())})
}

以下代码注解:

在这个代码中,使用 Golang + Gin + MongoDB 实现了一个简单的 RESTful API,用于管理书籍信息。以下是代码的主要部分注释解释:

  • 导入所需的包,包括 "fmt"、"net/http"、"github.com/gin-gonic/gin"、"go.mongodb.org/mongo-driver/bson" 和 "go.mongodb.org/mongo-driver/mongo"。
  • 定义了一个 Book 结构体,使用 bson 标签将结构体字段映射到 MongoDB 文档字段。ID 字段被定义为 primitive.ObjectID,它是 MongoDB 生成的唯一标识符。
  • 定义了一个全局变量 collection,用于表示将用于存储书籍对象的 MongoDB 集合。使用 init() 函数设置 MongoDB 客户端并创建集合对象。
  • 创建 Gin 路由器并定义了一个路由组,用于处理书籍 API 路由。每个路由使用 HTTP 方法和路由路径定义,并指定相应的路由处理函数。
  • 每个路由处理函数都接收一个名为 c 的 *gin.Context 参数,以访问请求和响应对象。使用 c.JSON() 函数将 JSON 响应发送回客户端,并指定 HTTP 状态码和响应体。
  • 在 createBook() 和 updateBook() 函数中,使用 c.BindJSON() 函数将请求体绑定到一个 Book 对象上。这个函数根据请求的 Content-Type 头部确定请求体的格式(JSON、XML 等),然后将请求体反序列化为 Book 对象。
  • 在 getBook() 函数中,使用 c.Param("id") 从 URL 参数中检索出书籍的 ID。使用 bson.M{"_id": id} 查询在数据库中查找指定 ID 的书籍。
  • 在 updateBook() 函数中,使用 $set 操作符仅更新书籍文档的 Title 和 Author 字段。使用 bson.M{"$set": bson.M{"title": book.Title, "author": book.Author}} 更新表达式更新数据库中的书籍。
  • 在 deleteBook() 函数中,使用 bson.M{"_id": id} 查询删除数据库中具有指定 ID 的书籍。
  • 在 main() 函数中,定义了一个监听地址和端口的 HTTP 服务器,并使用 router.Run() 函数启动服务器。
  • 在 createBook()、updateBook() 和 deleteBook() 函数中,使用 collection.InsertOne()、collection.UpdateOne() 和 collection.DeleteOne() 函数向 MongoDB 中的集合添加、更新和删除文档。
  • 在 getBooks() 函数中,使用 collection.Find() 函数查询集合中的所有文档。然后使用 c.JSON() 函数将响应作为 JSON 发送回客户端。
  • 在 getBook()、updateBook() 和 deleteBook() 函数中,使用 collection.FindOne() 函数查询集合中的单个文档,并使用 c.JSON() 函数将响应作为 JSON 发送回客户端。

这个代码演示了如何使用 Golang + Gin + MongoDB 实现一个简单的 RESTful API,提供了基本的 CRUD 功能。使用路由组可以更好地组织和管理 API 路由,并使用 MongoDB 驱动程序在 Golang 中进行 MongoDB 操作。

补充说明一下这个代码中使用的一些技术和函数:

  • Gin:Gin 是一个轻量级 Web 框架,具有快速路由和中间件支持,适合构建高性能 Web 应用程序。在这个代码中,我们使用 Gin 创建路由和处理 HTTP 请求和响应。
  • MongoDB:MongoDB 是一个文档型 NoSQL 数据库,具有灵活的文档模型和可扩展性。在这个代码中,我们使用 MongoDB 存储和管理书籍信息。
  • bson.M 和 bson.D:MongoDB 使用 BSON(二进制 JSON)格式存储数据,而 bson.M 和 bson.D 是 Golang 中用于表示 BSON 的映射和文档的类型。在这个代码中,我们使用 bson.M 和 bson.D 来构建 MongoDB 查询和更新操作的条件和表达式。
  • c.JSON():Gin 的上下文对象(gin.Context)提供了一些有用的函数,例如 c.JSON(),用于向客户端发送 JSON 响应。c.JSON() 函数接受一个 HTTP 状态码和一个结构体或 map,并将其序列化为 JSON 格式,然后发送到客户端。
  • c.Param():c.Param() 函数用于从 URL 参数中提取值。在这个代码中,我们使用 c.Param("id") 从 URL 中获取书籍的 ID。
  • c.BindJSON():c.BindJSON() 函数用于将请求体绑定到一个结构体上。在这个代码中,我们使用 c.BindJSON() 函数将请求体反序列化为 Book 对象。
  • collection.InsertOne()、collection.UpdateOne() 和 collection.DeleteOne():这些函数是 MongoDB Go 驱动程序中用于向集合中添加、更新和删除文档的函数。
  • collection.Find() 和 collection.FindOne():这些函数是 MongoDB Go 驱动程序中用于从集合中检索文档的函数。collection.Find() 函数返回一个游标,可以迭代文档结果集。而 collection.FindOne() 函数返回一个单个文档结果。

bson.M 和bson.D作用解释

bson.M 和 bson.D 是 Golang 中用于表示 MongoDB BSON(Binary JSON)格式的映射和文档的类型。

  • bson.M:它是一个 map 类型,其中键是字符串,值可以是任意类型。在 MongoDB 中,bson.M 通常用于表示查询或更新条件。它支持嵌套结构,可以使用点号(".")来表示嵌套字段。例如,{"name.first": "Alice"} 表示一个嵌套在 name 字段下的 first 字段。
  • bson.D:它是一个有序的文档类型,其中每个元素都是一个键值对。在 MongoDB 中,bson.D 通常用于表示排序条件、投影条件、更新操作和聚合管道阶段。与 bson.M 不同,bson.D 是有序的,因此可以在其中指定字段的顺序。例如,bson.D{{"name", 1}, {"age", -1}} 表示按照 name 升序和 age 降序的顺序排序。

总的来说,bson.M 和 bson.D 都是用于在 Golang 和 MongoDB 之间进行数据交换的常用类型,它们简化了 MongoDB 的查询、更新、排序、投影等操作的实现过程,并提供了方便的 API 来操作 MongoDB 的 BSON 格式数据。

bson使用示例

这里给出几个 bson 使用示例,来更好地说明它的使用方法和作用。

创建一个 bson.M 对象:

doc := bson.M{
    "name": "Alice",
    "age":  25,
    "addr": bson.M{
        "city":    "Beijing",
        "country": "China",
    },
}

这里创建了一个 bson.M 对象,其中包含了 name、age 和 addr 三个字段。其中,addr 是一个嵌套的 bson.M 对象,它包含了 city 和 country 两个字段。这个 bson.M 对象可以用于 MongoDB 的查询或更新操作,例如:

// 查询 age 大于 20 岁的文档
collection.Find(bson.M{"age": bson.M{"$gt": 20}})

// 更新 name 为 Bob 的文档的 age 字段为 30
collection.UpdateOne(bson.M{"name": "Bob"}, bson.M{"$set": bson.M{"age": 30}})

创建一个 bson.D 对象:

doc := bson.D{
    {"name", "Bob"},
    {"age",  30},
    {"addr", bson.D{
        {"city",    "Beijing"},
        {"country", "China"},
    }},
}

这里创建了一个 bson.D 对象,其中包含了 name、age 和 addr 三个键值对。与 bson.M 不同的是,bson.D 是有序的,因此可以在其中指定键值对的顺序。这个 bson.D 对象可以用于 MongoDB 的排序、投影等操作,例如:

// 按照 age 降序排序并只返回 name 和 age 字段
collection.Find(bson.D{{"name", 1}, {"age", -1}}).Project(bson.D{{"name", 1}, {"age", 1}})

序列化和反序列化 bson:

// 将 bson.M 对象序列化为字节数组
data, err := bson.Marshal(doc)

// 将字节数组反序列化为 bson.M 对象
var result bson.M
err := bson.Unmarshal(data, &result)

这里使用 bson.Marshal() 函数将 bson.M 对象序列化为字节数组,然后使用 bson.Unmarshal() 函数将字节数组反序列化为 bson.M 对象。这个方法可以用于 MongoDB Go 驱动程序中的数据交换和存储操作。


相关推荐

SQL关联各种JOIN傻傻分不清楚,读这一篇就够了

在关系型数据库中支持多表关联,不同场景下通过不同join方式让分布在不同表中的数据呈现在同一个结果里。熟练使用sql联合查询是日常开发的基础工作。为了方便演示讲解,假设有两个表,一张是保存学生踢足球的...

MyBatis的SQL执行流程不清楚?看完这一篇就够了

推荐学习真香警告!Alibaba珍藏版mybatis手写文档,刷起来全网独家的“MySQL高级知识”集合,骨灰级收藏,手慢则无前言MyBatis可能很多人都一直在用,但是MyBatis的SQL执行...

SQL优化这十条,面试的时候你都答对了吗?

尽量不要在要给在SQL语句的where子句中使用函数,这样会使索引失效。如果已经确定查询结果只有一条数据(当表中数据的该字段是唯一的),在查询SQL末尾增加limit1,这样MySQL的查询执行引...

SQL查询Excel结果数据还可这样输出到窗体控件ListBox和ListView

上一期作品,我们分享了通过SQL查询Excel的结果数据输出到Excel自身的工作表区域。大家估计应该感觉到了SQL查询的强大功能,它对精确或模糊查询均无畏惧,优点是查询检索效率高,将查询结果输出的形...

数据库|SQLServer数据库:模糊查询的三种情况

哈喽,你好啊,我是雷工!就是字面意思,当数据库的查询条件并不是十分具体时就用到模糊查询,比如查询姓氏为雷的人名,就需要从姓名列模糊查询。01like关键字查询当使用like关键字进行查询时,字段中的...

数据库教程-SQL Server多条件模糊查询

表单查询是以数据存储管理为基础的信息管理系统各业务功能实现的基础,也是数据库CRUD操作的重点与难点,尤其是多表连接查询、条件查询、分组查询、聚合函数等的综合应用。本文以某一比赛样式要求为基础,对数据...

如何利用教育网站源码成功搭建在线教育网站

如今是一个信息化时代,人们都想接受各种各样的教育,在线教育也就因此发展了起来,并且逐渐成为了一种趋势。而成熟的在线教育网站皆是由高质量的教育网站源码搭建而成的。如何利用教育网站源码成功搭建在线教育网站...

宝塔搭建WordPress跨境电商外贸商城模板汉化woodmart7.5.1源码

大家好啊,欢迎来到web测评。本期给大家带来一套php开发的WoodmartV7.5.1汉化主题|跨境电商|外贸商城|产品展示网站模板WordPress主题,是wordpress开发的。上次是谁要的系...

小狐狸ChatGPT付费创作系统V2.4.7全开源版 (vue全开源端)

测试环境:Nginx1.20+PHP7.4+MySQL5.7本版本为官方的最新开源包对应V2.4.7版本,包含了前后端所有开源包,是目前最新全开源版本,需要二开的这部分朋友也有选择了,如果不需要二...

php宝塔搭建部署thinkphp红色大气装修公司官网php源码

大家好啊,欢迎来到web测评。本期给大家带来一套php开发的thinkphp红色大气装修公司官网源码,上次是谁要的系统项目啊,帮你找到了,还说不会搭建,让我帮忙录制一期教程,趁着今天有空,简单的录制测...

php宝塔搭建免登录积分商城系统php源码

大家好啊,欢迎来到web测评。本期给大家带来一套php开发的免登录积分商城系统php源码,上次是谁要的系统项目啊,帮你找到了,还说不会搭建,让我帮忙录制一期教程,趁着今天有空,简单的录制测试了一下,部...

零代码搭建接口收费平台——接口大师YesApi

主流的API接口收费模式目前各大API接口平台,采用的收费模式主可以分为:免费接口、免费试用、接口流量套餐、先充值后按量计费的模式。例如,聚合数据的API收费模式是:按接口流量套餐。例如身份证二要素...

php宝塔搭建部署实战抽奖系统开源php源码

大家好啊,我是测评君,欢迎来到web测评。本期给大家带来一套抽奖系统开源php源码。感兴趣的朋友可以自行下载学习。技术架构PHP5.4+nginx+mysql5.7+JS+CSS+...

【推荐】一款开源个人与企业私有化部署使用的在线知识库管理平台

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!项目介绍zyplayer-doc是一款基于Java+Vue开源、专注于个人与企业私有化部署使用的在线知识库管...

网上的付费文档无法下载?这几个方法10秒搞定,任意免费复制

工作或者学习过程中,我们很多时候需要在网上找资料,但是想要的资料却要付费或者提示无法下载怎么办?别怕,这几个方法,让你10秒就能搞定付费文档,任意复制。1.打印界面复制遇到文档需要付费或者无法复制的...