184 lines
5.4 KiB
Plaintext
184 lines
5.4 KiB
Plaintext
|
|
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
|
|||
|
|
}
|