更多個人筆記見:
(注意點擊“繼續”,而不是“發現新項目”)
github個人筆記倉庫 https://github.com/ZHLOVEYY/IT_note
gitee 個人筆記倉庫 https://gitee.com/harryhack/it_note
個人學習,學習過程中還會不斷補充~ (后續會更新在github上)
文章目錄
- gin+gorm框架例子
- 服務端生產者
- 數據庫存儲
- 客戶端消費者
- 訪問測試
gin+gorm框架例子
post-platform/
├── main.go # Gin 服務(生產者)
├── rabbitmq.go # RabbitMQ 操作
├── models/
│ └── post.go # 帖子模型
├── db/
│ └── db.go # 數據庫連接和操作
├── consumer/
│ └── main.go # 消費者(存儲到 MySQL)
├── go.mod
└── go.sum
服務端生產者
- 定義 post.go
package modelstype Post struct {Title string `json:"title"`Content string `json:"content"`
}
gin 框架:"go get github.com/gin-gonic/gin"
- main.go:
package mainimport ("encoding/json""log""net/http""github.com/gin-gonic/gin""github.com/streadway/amqp"
)func failOnError(err error, msg string) {if err != nil {log.Fatalf("%s: %s", msg, err)}
}func main() {// 連接 RabbitMQconn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")failOnError(err, "Failed to connect to RabbitMQ")defer conn.Close()ch, err := conn.Channel()failOnError(err, "Failed to open a channel")defer ch.Close()q, err := ch.QueueDeclare("post_queue", false, false, false, false, nil)failOnError(err, "Failed to declare a queue")// 初始化 Ginr := gin.Default()// 提交帖子接口r.POST("/posts", func(c *gin.Context) {var post struct {Title string `json:"title" binding:"required"`Content string `json:"content" binding:"required"`}if err := c.ShouldBindJSON(&post); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 序列化帖子為 JSONpostData, err := json.Marshal(post)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to serialize post"})return}// 發送到 RabbitMQerr = ch.Publish("", // 交換機q.Name, // 隊列名稱false, // 強制false, // 立即amqp.Publishing{ContentType: "application/json",Body: postData,})if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to publish to RabbitMQ"})return}c.JSON(http.StatusOK, gin.H{"message": "Post submitted successfully"})})r.Run(":8081")
}
數據庫存儲
gorm 框架,需要 go get:
"gorm.io/driver/mysql""gorm.io/gorm"
- db.go
package dbimport ("log""test/model""gorm.io/driver/mysql""gorm.io/gorm"
)func InitDB() *gorm.DB {dsn := "root:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"//根據情況填寫password 和 dbname(具體的數據庫和密碼),這里用的本地 sqldb, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {log.Fatalf("Failed to connect to database: %v", err)}// 自動遷移,創建 posts 表err = db.AutoMigrate(&model.Post{})if err != nil {log.Fatalf("Failed to migrate database: %v", err)}return db
}
客戶端消費者
- consumer.go
package mainimport ("encoding/json""log""test/db""github.com/streadway/amqp"
)func failOnError(err error, msg string) {if err != nil {log.Fatalf("%s: %s", msg, err)}
}type Post struct {Title string `json:"title"`Content string `json:"content"`
}func main() {conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")failOnError(err, "Failed to connect to RabbitMQ")defer conn.Close()ch, err := conn.Channel()failOnError(err, "Failed to open a channel")defer ch.Close()q, err := ch.QueueDeclare("post_queue", false, false, false, false, nil)failOnError(err, "Failed to declare a queue")// 初始化數據庫db := db.InitDB()//消費消息msgs, err := ch.Consume(q.Name, "", true, false, false, false, nil)failOnError(err, "Failed to register a consumer")forever := make(chan bool)go func() {for d := range msgs {var posts Postif err := json.Unmarshal(d.Body, &posts); err != nil {log.Printf("Failed to unmarshal post: %v", err)continue}// 存儲到數據庫if err := db.Create(&posts).Error; err != nil {log.Printf("Failed to save post to database: %v", err)continue}log.Printf("Received post: Title=%s, Content=%s", posts.Title, posts.Content)// TODO: 存儲到數據庫(如 MySQL)}}()log.Printf(" [*] Waiting for posts. To exit press CTRL+C")<-forever // 等待程序退出,防止主線程退出,主動阻塞
}
gorm 中的 Create 是只要結構體的名字一樣就會找對應的表,所以結構體命名為 Post/Posts都可以,雖然和 model 中的不一樣,但是如果名字不一樣,Create 函數就“找不到”
訪問測試
分別終端運行程序后:
地址:http://localhost:8081/posts
發送內容:
{"title": "My First Post","content": "Hello, world!"
}
可以發現能正確送達,同時能存儲到數據庫中