快速掌握 GO 之 RabbitMQ 结合 gin+gorm 案例

更多个人笔记见:
github个人笔记仓库
gitee 个人笔记仓库

个人学习,学习过程中还会不断补充~ (后续会更新在github和 gitee上)

文章目录

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
GO 复制代码
package models

type Post struct {
    Title   string `json:"title"`
    Content string `json:"content"`
}

gin 框架:"go get github.com/gin-gonic/gin"

  • main.go:
GO 复制代码
package main

import (
	"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() {
	// 连接 RabbitMQ
	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")

	// 初始化 Gin
	r := 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
		}

		// 序列化帖子为 JSON
		postData, err := json.Marshal(post)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to serialize post"})
			return
		}

		// 发送到 RabbitMQ
		err = 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:

go 复制代码
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
  • db.go
GO 复制代码
package db

import (
	"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(具体的数据库和密码),这里用的本地 sql
	db, 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
GO 复制代码
package main

import (
	"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 Post
			if 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

发送内容:

json 复制代码
{
    "title": "My First Post",
    "content": "Hello, world!"
}

可以发现能正确送达,同时能存储到数据库中

相关推荐
南京**20 分钟前
python学习(一)
windows·python·学习
bobz96522 分钟前
透明代理
后端
这里有鱼汤22 分钟前
老祖宗没骗我,我把《周易》六十四卦丢给了大A股,市场居然回应了我
后端·python
陈随易25 分钟前
2025年100个产品计划之第7个(树图) - 目录结构生成工具
前端·后端·程序员
Victor35625 分钟前
MySQL(55)什么是覆盖索引?
后端
程序员爱钓鱼25 分钟前
Go语言依赖管理与版本控制-《Go语言实战指南》
后端·go·排序算法
义达29 分钟前
Anycast从原理到实践
后端·架构·云计算
Victor35629 分钟前
MySQL(56)什么是复合索引?
后端
Cache技术分享31 分钟前
96. Java 数字和字符串 - 比较字符串和字符串的各个部分
前端·后端
天天摸鱼的java工程师35 分钟前
为什么 ArrayList是线程不安全却在开发中被广泛使用?
java·后端·面试