快速掌握 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!"
}

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

相关推荐
evans在进步2 小时前
Spring Boot 启动流程与 @SpringBootApplication 核心原理详解
java·spring boot·后端
fatcoder2 小时前
玩转 Redis · Set 篇
前端·redis·后端
摇滚侠2 小时前
《SpringBoot 3:入门与应用实战》第 6 章 Spring Boot 最佳实践 阅读笔记 12
android·spring boot·笔记
掘金者阿豪2 小时前
你的公网 IP 是专线还是动态变化的?一文讲透动态 IP 与固定 IP 的那些事
前端·后端
超超不吵吵2 小时前
Java AI转型实战(八):RAG完整链路实战
后端
FfHUCisI2 小时前
Golang Redis 分布式锁
redis·分布式·golang
金立基包装胶水2 小时前
格拉辛纸热封后容易开胶怎么办?
大数据·笔记·其他
大厂码农老A2 小时前
汤森路透的座上宾?Qwen3.5-397B-A17B到底有什么本事?
前端·人工智能·后端
程序猿乐锅2 小时前
从 dsh 源码看「一切皆插件」与 Spring IoC
java·网络·数据库·人工智能·后端·spring
保持清醒的坐标系2 小时前
腾讯开源 teamai-cli:让全队 AI 工具用同一套"员工手册"
后端·github