package mqMgr import ( "context" "errors" "fmt" "time" amqp "github.com/rabbitmq/amqp091-go" ) // Queue对象 type HSYQueue struct { conn *amqp.Connection channel *amqp.Channel // 队列名称 queueName string // 交换机 exchange string // routing Key routingKey string //MQ链接字符串 mqurl string } // 消息队列配置对象 type HSYQueueConfig struct { QueueName string Exchange string RoutingKey string Network string Port int UserName string Password string } // 创建新的Queue对象 func NewHSYQueue(queueName, exchange, routingKey, userName, password string, network string, port int) *HSYQueue { queueConfigObj := &HSYQueueConfig{ QueueName: queueName, Exchange: exchange, RoutingKey: routingKey, UserName: userName, Password: password, Network: network, Port: port, } return NewHSYQueueByConfig(queueConfigObj) } // 通过队列配置对象创建新的Queue对象 func NewHSYQueueByConfig(queueConfigObj *HSYQueueConfig) *HSYQueue { queueObj := &HSYQueue{ queueName: queueConfigObj.QueueName, exchange: queueConfigObj.Exchange, routingKey: queueConfigObj.RoutingKey, mqurl: fmt.Sprintf("amqp://%s:%s@%s:%d/", queueConfigObj.UserName, queueConfigObj.Password, queueConfigObj.Network, queueConfigObj.Port), } if err := queueObj.GetQueueAttributes(); err != nil { return nil } return queueObj } // 连接RabbitMQ服务器 func (this *HSYQueue) GetQueueAttributes() (err error) { this.conn, err = amqp.Dial(this.mqurl) if err != nil { return } this.channel, err = this.conn.Channel() if err != nil { return } return } // 释放连接 func (this *HSYQueue) ReleaseRes() { this.conn.Close() this.channel.Close() } // SendMessage 发送单条消息 func (this *HSYQueue) SendMessage(message string, ex string) (err error) { // 声明队列 _, err = this.channel.QueueDeclare( this.queueName, // 队列名 true, // 是否持久化 false, // 是否自动删除(前提是至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会自动删除。注意:生产者客户端创建这个队列,或者没有消费者客户端与这个队列连接时,都不会自动删除这个队列) false, // 是否为排他队列(排他的队列仅对“首次”声明的conn可见[一个conn中的其他channel也能访问该队列],conn结束后队列删除) false, // 是否阻塞 nil, // 额外属性 ) if err != nil { err = errors.New("声明队列失败") return } // 声明交换器 err = this.channel.ExchangeDeclare( this.exchange, //交换器名 ex, //exchange type:一般用fanout、direct、topic true, // 是否持久化 false, //是否自动删除(自动删除的前提是至少有一个队列或者交换器与这和交换器绑定,之后所有与这个交换器绑定的队列或者交换器都与此解绑) false, //设置是否内置的。true表示是内置的交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式 false, // 是否阻塞 nil, // 额外属性 ) if err != nil { err = errors.New("声明交换器失败") return } // Binding err = this.channel.QueueBind( this.queueName, // 绑定的队列名称 this.routingKey, // bindkey 用于消息路由分发的key this.exchange, // 绑定的exchange名 false, // 是否阻塞 nil, // 额外属性 ) if err != nil { err = errors.New("绑定队列和交换器失败") return } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() err = this.channel.PublishWithContext(ctx, this.exchange, this.routingKey, false, false, amqp.Publishing{ ContentType: "text/plain", Body: []byte(message), }) if err != nil { err = errors.New("发布消息失败") return } return } // ReceiveMessage 消费单条消息 func (this *HSYQueue) ReceiveMessage() (msgs <-chan amqp.Delivery, err error) { _, err = this.channel.QueueDeclare( this.queueName, // 队列名 true, // 是否持久化 false, // 是否自动删除(前提是至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会自动删除。注意:生产者客户端创建这个队列,或者没有消费者客户端与这个队列连接时,都不会自动删除这个队列) false, // 是否为排他队列(排他的队列仅对“首次”声明的conn可见[一个conn中的其他channel也能访问该队列],conn结束后队列删除) false, // 是否阻塞 nil, // 额外属性(我还不会用) ) if err != nil { err = errors.New("声明队列失败") return } msgs, err = this.channel.Consume( this.queueName, // 队列名 "", // 消费者名,用来区分多个消费者,以实现公平分发或均等分发策略 true, // 是否自动应答 false, // 是否排他 false, // 是否接收只同一个连接中的消息,若为true,则只能接收别的conn中发送的消息 true, // 队列消费是否阻塞 nil, // 额外属性 ) if err != nil { err = errors.New("获取消息失败") return } return }