优秀的编程知识分享平台

网站首页 > 技术文章 正文

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

nanyue 2024-10-03 23:36:35 技术文章 5 ℃

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 驱动程序中的数据交换和存储操作。


最近发表
标签列表