正在显示
10 个修改的文件
包含
465 行增加
和
128 行删除
@@ -33,6 +33,7 @@ | @@ -33,6 +33,7 @@ | ||
33 | <dependency> | 33 | <dependency> |
34 | <groupId>org.springframework.boot</groupId> | 34 | <groupId>org.springframework.boot</groupId> |
35 | <artifactId>spring-boot-starter-amqp</artifactId> | 35 | <artifactId>spring-boot-starter-amqp</artifactId> |
36 | + <version>2.1.8.RELEASE</version> | ||
36 | </dependency> | 37 | </dependency> |
37 | <!-- SpringBoot end --> | 38 | <!-- SpringBoot end --> |
38 | <!-- SpringCloud start --> | 39 | <!-- SpringCloud start --> |
@@ -69,6 +70,11 @@ | @@ -69,6 +70,11 @@ | ||
69 | <!-- SpringCloud end --> | 70 | <!-- SpringCloud end --> |
70 | <!-- database start --> | 71 | <!-- database start --> |
71 | <dependency> | 72 | <dependency> |
73 | + <groupId>org.springframework.boot</groupId> | ||
74 | + <artifactId>spring-boot-starter-data-redis</artifactId> | ||
75 | + </dependency> | ||
76 | + | ||
77 | + <dependency> | ||
72 | <groupId>org.mybatis.spring.boot</groupId> | 78 | <groupId>org.mybatis.spring.boot</groupId> |
73 | <artifactId>mybatis-spring-boot-starter</artifactId> | 79 | <artifactId>mybatis-spring-boot-starter</artifactId> |
74 | <version>2.1.1</version> | 80 | <version>2.1.1</version> |
@@ -128,6 +134,11 @@ | @@ -128,6 +134,11 @@ | ||
128 | </dependency> | 134 | </dependency> |
129 | 135 | ||
130 | <dependency> | 136 | <dependency> |
137 | + <groupId>org.apache.commons</groupId> | ||
138 | + <artifactId>commons-pool2</artifactId> | ||
139 | + </dependency> | ||
140 | + | ||
141 | + <dependency> | ||
131 | <groupId>org.springframework.boot</groupId> | 142 | <groupId>org.springframework.boot</groupId> |
132 | <artifactId>spring-boot-starter-test</artifactId> | 143 | <artifactId>spring-boot-starter-test</artifactId> |
133 | <scope>test</scope> | 144 | <scope>test</scope> |
1 | package com.sunyo.wlpt.message.bus.service.controller; | 1 | package com.sunyo.wlpt.message.bus.service.controller; |
2 | 2 | ||
3 | +import com.sunyo.wlpt.message.bus.service.rabbit.test.TestProduct; | ||
4 | +import com.sunyo.wlpt.message.bus.service.rabbit.utils.DirectUtils; | ||
5 | +import com.sunyo.wlpt.message.bus.service.rabbit.utils.RabbitUtils; | ||
3 | import org.springframework.web.bind.annotation.CrossOrigin; | 6 | import org.springframework.web.bind.annotation.CrossOrigin; |
7 | +import org.springframework.web.bind.annotation.GetMapping; | ||
4 | import org.springframework.web.bind.annotation.RequestMapping; | 8 | import org.springframework.web.bind.annotation.RequestMapping; |
5 | import org.springframework.web.bind.annotation.RestController; | 9 | import org.springframework.web.bind.annotation.RestController; |
6 | 10 | ||
11 | +import javax.annotation.Resource; | ||
12 | +import java.io.IOException; | ||
13 | +import java.util.concurrent.TimeoutException; | ||
14 | + | ||
7 | /** | 15 | /** |
8 | * @author 子诚 | 16 | * @author 子诚 |
9 | * Description: | 17 | * Description: |
@@ -14,5 +22,27 @@ import org.springframework.web.bind.annotation.RestController; | @@ -14,5 +22,27 @@ import org.springframework.web.bind.annotation.RestController; | ||
14 | @RestController | 22 | @RestController |
15 | public class RabbitController { | 23 | public class RabbitController { |
16 | 24 | ||
25 | + @Resource | ||
26 | + private TestProduct testProduct; | ||
27 | + | ||
28 | + @Resource | ||
29 | + private RabbitUtils rabbitUtils; | ||
30 | + | ||
31 | + @Resource | ||
32 | + private DirectUtils directUtils; | ||
33 | + | ||
34 | + @GetMapping("/test/product") | ||
35 | + public void product() throws IOException, TimeoutException | ||
36 | + { | ||
37 | + rabbitUtils.createExchange("E_zicheng"); | ||
38 | + rabbitUtils.createQueue("Q_zicheng"); | ||
39 | + rabbitUtils.createBing("E_zicheng","Q_zicheng","R_zicheng"); | ||
40 | + directUtils.directProducer("E_zicheng", "R_zicheng", "2020-7-21,进行测试->" + Math.random() * 100); | ||
41 | + } | ||
17 | 42 | ||
43 | + @GetMapping("/test/consumer") | ||
44 | + public void consumer() throws IOException, TimeoutException | ||
45 | + { | ||
46 | + directUtils.directConsumer("Q_zicheng", "E_zicheng", "R_zicheng"); | ||
47 | + } | ||
18 | } | 48 | } |
src/main/java/com/sunyo/wlpt/message/bus/service/rabbit/DirectExchangeRabbitConfig.java
已删除
100644 → 0
1 | -package com.sunyo.wlpt.message.bus.service.rabbit; | ||
2 | - | ||
3 | -import org.springframework.amqp.core.Binding; | ||
4 | -import org.springframework.amqp.core.BindingBuilder; | ||
5 | -import org.springframework.amqp.core.DirectExchange; | ||
6 | -import org.springframework.amqp.core.Queue; | ||
7 | -import org.springframework.context.annotation.Bean; | ||
8 | -import org.springframework.context.annotation.Configuration; | ||
9 | - | ||
10 | -/** | ||
11 | - * @author 子诚 | ||
12 | - * Description:交换机类型是direct(直连)的rabbit的配置文件 | ||
13 | - * 时间:2020/7/16 16:20 | ||
14 | - */ | ||
15 | -@Configuration | ||
16 | -public class DirectExchangeRabbitConfig { | ||
17 | - // 定义直连交换机 | ||
18 | - public static final String DIRECT_EXCHANGE_NAME = "E_direct"; | ||
19 | - | ||
20 | - private static final String queue4BindingKey1 = "big"; | ||
21 | - private static final String queue4BindingKey2 = "small"; | ||
22 | - private static final String queue5BindingKey = "cat"; | ||
23 | - | ||
24 | - // 声明直连交换机 | ||
25 | - @Bean | ||
26 | - public DirectExchange directExchange() { | ||
27 | - return new DirectExchange(DIRECT_EXCHANGE_NAME); | ||
28 | - } | ||
29 | - | ||
30 | - // 声明消息队列 | ||
31 | - @Bean | ||
32 | - public Queue messageQueue4() { | ||
33 | - return new Queue("queue4"); | ||
34 | - | ||
35 | - } | ||
36 | - | ||
37 | - @Bean | ||
38 | - public Queue messageQueue5() { | ||
39 | - return new Queue("queue5"); | ||
40 | - } | ||
41 | - | ||
42 | - // 向直连交换机上绑定队列 | ||
43 | - @Bean | ||
44 | - Binding bindingQueue4Exchange1(Queue messageQueue4, DirectExchange directExchange) { | ||
45 | - return BindingBuilder.bind( messageQueue4 ) | ||
46 | - .to( directExchange ) | ||
47 | - .with( queue4BindingKey1 ); | ||
48 | - } | ||
49 | - | ||
50 | - @Bean | ||
51 | - Binding bindingQueue4Exchange2(Queue messageQueue4, DirectExchange directExchange) { | ||
52 | - return BindingBuilder.bind( messageQueue4 ) | ||
53 | - .to( directExchange ) | ||
54 | - .with( queue4BindingKey2 ); | ||
55 | - } | ||
56 | - | ||
57 | - @Bean | ||
58 | - Binding bindingQueue5Exchange(Queue messageQueue5, DirectExchange directExchange) { | ||
59 | - return BindingBuilder.bind( messageQueue5 ) | ||
60 | - .to( directExchange ) | ||
61 | - .with( queue5BindingKey ); | ||
62 | - } | ||
63 | -} |
src/main/java/com/sunyo/wlpt/message/bus/service/rabbit/config/PublisherConfirmAndReturnConfig.java
0 → 100644
1 | +package com.sunyo.wlpt.message.bus.service.rabbit.config; | ||
2 | + | ||
3 | +import lombok.extern.slf4j.Slf4j; | ||
4 | +import org.springframework.amqp.core.Message; | ||
5 | +import org.springframework.amqp.rabbit.connection.CorrelationData; | ||
6 | +import org.springframework.amqp.rabbit.core.RabbitTemplate; | ||
7 | + | ||
8 | +import javax.annotation.Resource; | ||
9 | + | ||
10 | +/** | ||
11 | + * @author 子诚 | ||
12 | + * Description:开启消息可靠性(confirm和return机制) | ||
13 | + * 时间:2020/7/20 9:30 | ||
14 | + */ | ||
15 | +@Slf4j | ||
16 | +//@Component | ||
17 | +public class PublisherConfirmAndReturnConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback { | ||
18 | + | ||
19 | + @Resource | ||
20 | + private RabbitTemplate rabbitTemplate; | ||
21 | + | ||
22 | + /** | ||
23 | + * 初始化的方法,设置当前上下文(下面的两个方法),为confirm和return机制的回滚事件 | ||
24 | + */ | ||
25 | +// @PostConstruct | ||
26 | + public void initMethod() { | ||
27 | + rabbitTemplate.setConfirmCallback(this); | ||
28 | + rabbitTemplate.setReturnCallback(this); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public void confirm(CorrelationData correlationData, boolean ack, String cause) { | ||
33 | + // 根据手动ack来确定 | ||
34 | + if (ack) { | ||
35 | + log.info("消息发送至exchange,成功"); | ||
36 | + } else { | ||
37 | + log.error("消息发送至exchange,失败"); | ||
38 | + } | ||
39 | + } | ||
40 | + | ||
41 | + @Override | ||
42 | + public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { | ||
43 | + log.error("消息从exchange分发到queue,失败"); | ||
44 | + } | ||
45 | +} |
1 | +package com.sunyo.wlpt.message.bus.service.rabbit.test; | ||
2 | + | ||
3 | +import com.rabbitmq.client.Channel; | ||
4 | +import lombok.extern.slf4j.Slf4j; | ||
5 | +import org.springframework.amqp.core.Message; | ||
6 | +import org.springframework.beans.factory.annotation.Autowired; | ||
7 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
8 | +import org.springframework.stereotype.Component; | ||
9 | + | ||
10 | +import java.io.IOException; | ||
11 | +import java.util.concurrent.TimeUnit; | ||
12 | + | ||
13 | + | ||
14 | +/** | ||
15 | + * @author 子诚 | ||
16 | + * Description:测试-消息-消费者 | ||
17 | + * 时间:2020/7/20 11:09 | ||
18 | + */ | ||
19 | +@Slf4j | ||
20 | +@Component | ||
21 | +public class TestConsumer { | ||
22 | + | ||
23 | + @Autowired | ||
24 | + private StringRedisTemplate redisTemplate; | ||
25 | + | ||
26 | + | ||
27 | +// @RabbitListener(queues = "Q_test") | ||
28 | + public void getMessage(String msg, Channel channel, Message message) throws IOException { | ||
29 | + try { | ||
30 | + // 0、获取messageId | ||
31 | + String messageId = (String) message.getMessageProperties().getHeaders().get("spring_returned_message_correlation"); | ||
32 | + // 1、设置key到redis,设置缓存时间为10秒 | ||
33 | + if (redisTemplate.opsForValue().setIfAbsent(messageId, "0", 10, TimeUnit.SECONDS)) { | ||
34 | + // 2、消费消息 | ||
35 | + log.info("成功消费了消息:" + msg); | ||
36 | + // 3、设置key的value为1 | ||
37 | + redisTemplate.opsForValue().set(messageId, "1", 10, TimeUnit.SECONDS); | ||
38 | + // 4、手动ack | ||
39 | + channel.basicAck(message.getMessageProperties().getDeliveryTag(), true); | ||
40 | + } else { | ||
41 | + // 获取redis中的value,如果是1,就手动ack。如果是0,就什么也不做(是0代表着,正在被消费中) | ||
42 | + if ("1".equalsIgnoreCase(redisTemplate.opsForValue().get(messageId))) { | ||
43 | + // 手动ack,第一个参数是所确认消息的标识,第二参数是是否批量确认 | ||
44 | + channel.basicAck(message.getMessageProperties().getDeliveryTag(), true); | ||
45 | + } | ||
46 | + } | ||
47 | + | ||
48 | + | ||
49 | + /** | ||
50 | + * 设置Qos机制 | ||
51 | + * 第一个参数:单条消息的大小(0表示即无限制) | ||
52 | + * 第二个参数:每次处理消息的数量 | ||
53 | + * 第三个参数:是否为consumer级别(false表示仅当前channel有效) | ||
54 | + */ | ||
55 | + | ||
56 | + // channel.basicQos(0, 1, false); | ||
57 | + } catch (Exception e) { | ||
58 | + channel.basicReject(message.getMessageProperties().getDeliveryTag(), false); | ||
59 | + log.error("消息ID:" + message.getMessageProperties().getHeaders().get("spring_returned_message_correlation")); | ||
60 | + log.error("接收消息发送错误:" + e.getMessage()); | ||
61 | + } | ||
62 | + | ||
63 | + } | ||
64 | +} |
1 | +package com.sunyo.wlpt.message.bus.service.rabbit.test; | ||
2 | + | ||
3 | +import com.sunyo.wlpt.message.bus.service.utils.IdUtils; | ||
4 | +import lombok.extern.slf4j.Slf4j; | ||
5 | +import org.springframework.amqp.rabbit.connection.CorrelationData; | ||
6 | +import org.springframework.amqp.rabbit.core.RabbitTemplate; | ||
7 | +import org.springframework.stereotype.Component; | ||
8 | + | ||
9 | +import javax.annotation.Resource; | ||
10 | +import java.io.IOException; | ||
11 | + | ||
12 | +/** | ||
13 | + * @author 子诚 | ||
14 | + * Description:测试-消息-生产者 | ||
15 | + * 时间:2020/7/20 11:08 | ||
16 | + */ | ||
17 | +@Slf4j | ||
18 | +@Component | ||
19 | +public class TestProduct { | ||
20 | + | ||
21 | + @Resource | ||
22 | + private RabbitTemplate rabbitTemplate; | ||
23 | + | ||
24 | + /** | ||
25 | + * @param exchangeName 交换机名称 | ||
26 | + * @param routingKeyName 路由键名称 | ||
27 | + * @param msg 发送的消息 | ||
28 | + */ | ||
29 | + public void sentMessage(String exchangeName, String routingKeyName, String msg) throws IOException { | ||
30 | + CorrelationData messageId = new CorrelationData(IdUtils.generateId()); | ||
31 | + rabbitTemplate.convertAndSend(exchangeName, routingKeyName, msg, messageId); | ||
32 | + log.info("成功发送消息-> {};到交换机->{};路由键为 ->{};", msg, exchangeName, routingKeyName); | ||
33 | + | ||
34 | + } | ||
35 | + | ||
36 | +} |
1 | +package com.sunyo.wlpt.message.bus.service.rabbit.utils; | ||
2 | + | ||
3 | +import com.rabbitmq.client.*; | ||
4 | +import com.sunyo.wlpt.message.bus.service.utils.IdUtils; | ||
5 | +import lombok.extern.slf4j.Slf4j; | ||
6 | +import org.springframework.beans.factory.annotation.Autowired; | ||
7 | +import org.springframework.beans.factory.annotation.Value; | ||
8 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
9 | +import org.springframework.stereotype.Component; | ||
10 | + | ||
11 | +import javax.annotation.PostConstruct; | ||
12 | +import java.io.IOException; | ||
13 | +import java.util.concurrent.TimeUnit; | ||
14 | +import java.util.concurrent.TimeoutException; | ||
15 | + | ||
16 | +/** | ||
17 | + * @author 子诚 | ||
18 | + * Description: | ||
19 | + * 时间:2020/7/21 9:32 | ||
20 | + */ | ||
21 | +@Slf4j | ||
22 | +@Component | ||
23 | +public class DirectUtils { | ||
24 | + | ||
25 | + @Autowired | ||
26 | + private StringRedisTemplate redisTemplate; | ||
27 | + | ||
28 | + @Value("${spring.rabbitmq.host}") | ||
29 | + private String host; | ||
30 | + | ||
31 | + @Value("${spring.rabbitmq.port}") | ||
32 | + private int port; | ||
33 | + | ||
34 | + @Value("${spring.rabbitmq.username}") | ||
35 | + private String username; | ||
36 | + | ||
37 | + @Value("${spring.rabbitmq.password}") | ||
38 | + private String password; | ||
39 | + | ||
40 | + @Value("${spring.rabbitmq.virtual-host}") | ||
41 | + private String vHost; | ||
42 | + | ||
43 | + /** | ||
44 | + * @return 链接 rabbitmq | ||
45 | + * @throws IOException IO异常 | ||
46 | + * @throws TimeoutException 超时异常 | ||
47 | + */ | ||
48 | + @PostConstruct | ||
49 | + public Connection getConnection() throws IOException, TimeoutException | ||
50 | + { | ||
51 | + //定义连接工厂 | ||
52 | + ConnectionFactory factory = new ConnectionFactory(); | ||
53 | + //设置服务地址 | ||
54 | + factory.setHost(host); | ||
55 | + //端口,amqp协议 端口 类似与mysql的3306 | ||
56 | + factory.setPort(port); | ||
57 | + //设置账号信息,用户名、密码、vhost | ||
58 | + factory.setVirtualHost(vHost); | ||
59 | + factory.setUsername(username); | ||
60 | + factory.setPassword(password); | ||
61 | + // 通过工程获取连接 | ||
62 | + Connection connection = factory.newConnection(); | ||
63 | + return connection; | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * 链接 RabbitMQ | ||
68 | + * | ||
69 | + * @param hostIp mq服务器Ip地址 | ||
70 | + * @param hostPort mq服务器端口号 | ||
71 | + * @param vHostName VirtualHost名称 | ||
72 | + * @param userName 登录账号 | ||
73 | + * @param password 登录密码 | ||
74 | + * @return 返回链接 | ||
75 | + * @throws Exception | ||
76 | + */ | ||
77 | + public static Connection getConnection(String hostIp, int hostPort, String vHostName, String userName, String password) throws Exception | ||
78 | + { | ||
79 | + //定义连接工厂 | ||
80 | + ConnectionFactory factory = new ConnectionFactory(); | ||
81 | + //设置服务地址 | ||
82 | + factory.setHost(hostIp); | ||
83 | + //端口 | ||
84 | + factory.setPort(hostPort); | ||
85 | + //设置账号信息,用户名、密码、vhost | ||
86 | + factory.setVirtualHost(vHostName); | ||
87 | + factory.setUsername(userName); | ||
88 | + factory.setPassword(password); | ||
89 | + // 通过工程获取连接 | ||
90 | + Connection connection = factory.newConnection(); | ||
91 | + return connection; | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * 关闭通道和关闭连接的工具方法 | ||
96 | + * | ||
97 | + * @param channel 通道 | ||
98 | + * @param conn 连接 | ||
99 | + */ | ||
100 | + public static void closeConnectionAndChanel(Channel channel, Connection conn) | ||
101 | + { | ||
102 | + try { | ||
103 | + if (channel != null) { | ||
104 | + channel.close(); | ||
105 | + } | ||
106 | + if (conn != null) { | ||
107 | + conn.close(); | ||
108 | + } | ||
109 | + } catch (Exception e) { | ||
110 | + e.printStackTrace(); | ||
111 | + } | ||
112 | + } | ||
113 | + | ||
114 | + | ||
115 | + /** | ||
116 | + * DirectExchange的 消息生产者 | ||
117 | + * | ||
118 | + * @param exchangeName 交换机名称 | ||
119 | + * @param routingKeyName 路由键名称 | ||
120 | + * @param msg 发送的消息 | ||
121 | + * @throws IOException | ||
122 | + * @throws TimeoutException | ||
123 | + */ | ||
124 | + public void directProducer(String exchangeName, String routingKeyName, String msg) throws IOException, TimeoutException | ||
125 | + { | ||
126 | + // 1、创建ConnectionFactory | ||
127 | + Connection connection = getConnection(); | ||
128 | + // 2、 通过Connection创建一个新的Channel | ||
129 | + Channel channel = connection.createChannel(); | ||
130 | + // 3、开启消息的确认机制(confirm:保证消息能够发送到 exchange) | ||
131 | + channel.confirmSelect(); | ||
132 | + // 4、避免消息被重复消费 | ||
133 | + AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() | ||
134 | + // 指定消息是否需要持久化,1:需要持久化;2:不需要持久化 | ||
135 | + .deliveryMode(1) | ||
136 | + // 设置全局唯一消息机制id(雪花id) | ||
137 | + .messageId(IdUtils.generateId()) | ||
138 | + .build(); | ||
139 | + // 5、开启 return 机制(保证消息,从 Exchange 分发到 Queue ) | ||
140 | + channel.addReturnListener(new ReturnListener() { | ||
141 | + @Override | ||
142 | + public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException | ||
143 | + { | ||
144 | + // 当消息没有从 Exchange 分发到 Queue 时,才会执行 | ||
145 | + log.error(new String(body, "UTF8") + "->没有从 Exchange 分发到Queue中"); | ||
146 | + } | ||
147 | + }); | ||
148 | + | ||
149 | + // 6、发送消息,并指定 mandatory 参数为true | ||
150 | + channel.basicPublish(exchangeName, routingKeyName, true, properties, msg.getBytes()); | ||
151 | + log.info("消息生产者,目标交换机:{};路由键:{};发送信息:{}", exchangeName, routingKeyName, msg); | ||
152 | + // 7、添加一个异步 confirm 确认监听,用于发送消息到Broker端之后,回送消息的监听 | ||
153 | + channel.addConfirmListener(new ConfirmListener() { | ||
154 | + // 发送成功 | ||
155 | + @Override | ||
156 | + public void handleAck(long deliveryTag, boolean multiple) throws IOException | ||
157 | + { | ||
158 | + log.info("消息发送成功,标识:{};是否是批量:{}", deliveryTag, multiple); | ||
159 | + } | ||
160 | + | ||
161 | + // 发送失败 | ||
162 | + @Override | ||
163 | + public void handleNack(long deliveryTag, boolean multiple) throws IOException | ||
164 | + { | ||
165 | + log.error("消息发送失败,标识:{};是否是批量:{}", deliveryTag, multiple); | ||
166 | + } | ||
167 | + }); | ||
168 | + // finally,关闭连接 | ||
169 | + closeConnectionAndChanel(channel, connection); | ||
170 | + } | ||
171 | + | ||
172 | + /** | ||
173 | + * DirectExchange的 消息消费者 | ||
174 | + * | ||
175 | + * @throws IOException IO异常 | ||
176 | + * @throws TimeoutException 超时异常 | ||
177 | + */ | ||
178 | + public void directConsumer(String queueName, String exchangeName, String routingKeyName) throws IOException, TimeoutException | ||
179 | + { | ||
180 | + // 1、创建ConnectionFactory | ||
181 | + Connection connection = getConnection(); | ||
182 | + // 2、 通过Connection创建一个新的Channel | ||
183 | + Channel channel = connection.createChannel(); | ||
184 | + // 3、设置绑定关系(队列、交换机名称、路由键名称) | ||
185 | + channel.queueBind(queueName, exchangeName, routingKeyName); | ||
186 | + // 一次只接受一条未确认的消息 | ||
187 | + channel.basicQos(1); | ||
188 | + // 4、开启监听Queue | ||
189 | + DefaultConsumer consumer = new DefaultConsumer(channel) { | ||
190 | + @Override | ||
191 | + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException | ||
192 | + { | ||
193 | + try { | ||
194 | + // 0、获取出全局唯一的 信息业务id(messageId) | ||
195 | + String messageId = properties.getMessageId(); | ||
196 | + // 必须保证 messageId 不为空,避免空指针异常 | ||
197 | + if (redisTemplate.opsForValue().setIfAbsent(messageId, "0", 10, TimeUnit.MINUTES)) { | ||
198 | + | ||
199 | + // 消费成功,将redis中的 messageId 对应的value修改为 1 | ||
200 | + redisTemplate.opsForValue().set(messageId, "1", 10, TimeUnit.MINUTES); | ||
201 | + // 手动ack | ||
202 | + channel.basicAck(envelope.getDeliveryTag(), false); | ||
203 | + | ||
204 | + log.info("接收到消息:" + new String(body, "UTF-8")); | ||
205 | + } else { | ||
206 | + // 获取redis中的value,如果是1,就手动ack。如果是0,就什么也不做(是0代表着,正在被消费中) | ||
207 | + if ("1".equalsIgnoreCase(redisTemplate.opsForValue().get(messageId))) { | ||
208 | + // 手动ack | ||
209 | + channel.basicAck(envelope.getDeliveryTag(), false); | ||
210 | + } | ||
211 | + } | ||
212 | + } catch (Exception e) { | ||
213 | + // 手动ack | ||
214 | + channel.basicAck(envelope.getDeliveryTag(), false); | ||
215 | + log.error("接收消息发送错误:" + e.getMessage()); | ||
216 | + } | ||
217 | + } | ||
218 | + }; | ||
219 | + // 消费消息 | ||
220 | + channel.basicConsume(queueName, false, consumer); | ||
221 | + } | ||
222 | +} | ||
223 | + | ||
224 | + |
1 | -package com.sunyo.wlpt.message.bus.service.rabbit; | 1 | +package com.sunyo.wlpt.message.bus.service.rabbit.utils; |
2 | 2 | ||
3 | import com.sunyo.wlpt.message.bus.service.domain.BusExchange; | 3 | import com.sunyo.wlpt.message.bus.service.domain.BusExchange; |
4 | import com.sunyo.wlpt.message.bus.service.domain.BusQueue; | 4 | import com.sunyo.wlpt.message.bus.service.domain.BusQueue; |
@@ -6,7 +6,6 @@ import com.sunyo.wlpt.message.bus.service.domain.UserMessageBinding; | @@ -6,7 +6,6 @@ import com.sunyo.wlpt.message.bus.service.domain.UserMessageBinding; | ||
6 | import lombok.extern.slf4j.Slf4j; | 6 | import lombok.extern.slf4j.Slf4j; |
7 | import org.springframework.amqp.core.*; | 7 | import org.springframework.amqp.core.*; |
8 | import org.springframework.amqp.rabbit.core.RabbitTemplate; | 8 | import org.springframework.amqp.rabbit.core.RabbitTemplate; |
9 | -import org.springframework.beans.factory.annotation.Value; | ||
10 | import org.springframework.cloud.context.config.annotation.RefreshScope; | 9 | import org.springframework.cloud.context.config.annotation.RefreshScope; |
11 | import org.springframework.stereotype.Component; | 10 | import org.springframework.stereotype.Component; |
12 | 11 | ||
@@ -20,16 +19,13 @@ import javax.annotation.Resource; | @@ -20,16 +19,13 @@ import javax.annotation.Resource; | ||
20 | @Slf4j | 19 | @Slf4j |
21 | @RefreshScope | 20 | @RefreshScope |
22 | @Component | 21 | @Component |
23 | -public class DirectRabbitUtils { | 22 | +public class RabbitUtils { |
24 | @Resource | 23 | @Resource |
25 | private AmqpAdmin amqpAdmin; | 24 | private AmqpAdmin amqpAdmin; |
26 | 25 | ||
27 | @Resource | 26 | @Resource |
28 | private RabbitTemplate rabbitTemplate; | 27 | private RabbitTemplate rabbitTemplate; |
29 | 28 | ||
30 | - @Value("${spring.rabbitmq.virtual-host}") | ||
31 | - private String v_host; | ||
32 | - | ||
33 | /** | 29 | /** |
34 | * 创建交换机(交换机名称,是否持久化,是否删除) | 30 | * 创建交换机(交换机名称,是否持久化,是否删除) |
35 | * | 31 | * |
@@ -77,6 +73,16 @@ public class DirectRabbitUtils { | @@ -77,6 +73,16 @@ public class DirectRabbitUtils { | ||
77 | } | 73 | } |
78 | 74 | ||
79 | /** | 75 | /** |
76 | + * 创建交换机,通过 exchangeName 创建 | ||
77 | + */ | ||
78 | + public void createExchange(String exchangeName) { | ||
79 | + amqpAdmin.declareExchange( | ||
80 | + new DirectExchange(exchangeName) | ||
81 | + ); | ||
82 | + log.info("创建了交换机:{};类型:{};", exchangeName, "DirectExchange"); | ||
83 | + } | ||
84 | + | ||
85 | + /** | ||
80 | * 根据交换机名称,删除虚拟机 | 86 | * 根据交换机名称,删除虚拟机 |
81 | * | 87 | * |
82 | * @param exchangeName 交换机名称 | 88 | * @param exchangeName 交换机名称 |
@@ -94,6 +100,19 @@ public class DirectRabbitUtils { | @@ -94,6 +100,19 @@ public class DirectRabbitUtils { | ||
94 | amqpAdmin.declareQueue( | 100 | amqpAdmin.declareQueue( |
95 | new Queue(busQueue.getQueueName(), busQueue.getDurability(), false, busQueue.getAutoDelete()) | 101 | new Queue(busQueue.getQueueName(), busQueue.getDurability(), false, busQueue.getAutoDelete()) |
96 | ); | 102 | ); |
103 | + log.info("创建了队列,队列名称->{}", busQueue.getQueueName()); | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
107 | + * 创建队列 | ||
108 | + * | ||
109 | + * @param queueName 队列名称 | ||
110 | + */ | ||
111 | + public void createQueue(String queueName) { | ||
112 | + amqpAdmin.declareQueue( | ||
113 | + new Queue(queueName) | ||
114 | + ); | ||
115 | + log.info("创建了队列,队列名称->{}", queueName); | ||
97 | } | 116 | } |
98 | 117 | ||
99 | /** | 118 | /** |
@@ -105,9 +124,29 @@ public class DirectRabbitUtils { | @@ -105,9 +124,29 @@ public class DirectRabbitUtils { | ||
105 | boolean flag = amqpAdmin.deleteQueue(queueName); | 124 | boolean flag = amqpAdmin.deleteQueue(queueName); |
106 | } | 125 | } |
107 | 126 | ||
127 | + /** | ||
128 | + * 创建绑定关系 | ||
129 | + * | ||
130 | + * @param userMessageBinding {@link UserMessageBinding} | ||
131 | + */ | ||
108 | public void createBing(UserMessageBinding userMessageBinding) { | 132 | public void createBing(UserMessageBinding userMessageBinding) { |
109 | amqpAdmin.declareBinding( | 133 | amqpAdmin.declareBinding( |
110 | new Binding(userMessageBinding.getQueueName(), Binding.DestinationType.QUEUE, userMessageBinding.getExchangeName(), userMessageBinding.getRoutingKeyName(), null) | 134 | new Binding(userMessageBinding.getQueueName(), Binding.DestinationType.QUEUE, userMessageBinding.getExchangeName(), userMessageBinding.getRoutingKeyName(), null) |
111 | ); | 135 | ); |
136 | + log.info("创建了绑定关系,交换机->{};队列->{};路由键->{}", userMessageBinding.getQueueName(), userMessageBinding.getExchangeName(), userMessageBinding.getRoutingKeyName()); | ||
137 | + } | ||
138 | + | ||
139 | + /** | ||
140 | + * 创建绑定关系 | ||
141 | + * | ||
142 | + * @param exchangeName 交换机名称 | ||
143 | + * @param queueName 队列名称 | ||
144 | + * @param routingKeyName 路由键名称 | ||
145 | + */ | ||
146 | + public void createBing(String exchangeName, String queueName, String routingKeyName) { | ||
147 | + amqpAdmin.declareBinding( | ||
148 | + new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, routingKeyName, null) | ||
149 | + ); | ||
150 | + log.info("创建了绑定关系,交换机->{};队列->{};路由键->{}", exchangeName, queueName, routingKeyName); | ||
112 | } | 151 | } |
113 | } | 152 | } |
1 | -package com.sunyo.wlpt.message.bus.service.utils; | ||
2 | - | ||
3 | -import com.rabbitmq.client.Channel; | ||
4 | -import com.rabbitmq.client.Connection; | ||
5 | -import com.rabbitmq.client.ConnectionFactory; | ||
6 | - | ||
7 | -/** | ||
8 | - * @author 子诚 | ||
9 | - * Description:RabbitMQ 的工具类 | ||
10 | - * 时间:2020/6/30 9:39 | ||
11 | - */ | ||
12 | -public class RabbitUtils { | ||
13 | - | ||
14 | - /** | ||
15 | - * 链接 RabbitMQ | ||
16 | - * | ||
17 | - * @param hostIp mq服务器Ip地址 | ||
18 | - * @param hostPort mq服务器端口号 | ||
19 | - * @param vHostName VirtualHost名称 | ||
20 | - * @param userName 登录账号 | ||
21 | - * @param password 登录密码 | ||
22 | - * @return 返回链接 | ||
23 | - * @throws Exception | ||
24 | - */ | ||
25 | - public static Connection getConnection(String hostIp, int hostPort, String vHostName, String userName, String password) throws Exception { | ||
26 | - //定义连接工厂 | ||
27 | - ConnectionFactory factory = new ConnectionFactory(); | ||
28 | - //设置服务地址 | ||
29 | - factory.setHost(hostIp); | ||
30 | - //端口 | ||
31 | - factory.setPort(hostPort); | ||
32 | - //设置账号信息,用户名、密码、vhost | ||
33 | - factory.setVirtualHost(vHostName); | ||
34 | - factory.setUsername(userName); | ||
35 | - factory.setPassword(password); | ||
36 | - // 通过工程获取连接 | ||
37 | - Connection connection = factory.newConnection(); | ||
38 | - return connection; | ||
39 | - } | ||
40 | - | ||
41 | - /** | ||
42 | - * 关闭通道和关闭连接的工具方法 | ||
43 | - * | ||
44 | - * @param channel 通道 | ||
45 | - * @param conn 连接 | ||
46 | - */ | ||
47 | - public static void closeConnectionAndChanel(Channel channel, Connection conn) { | ||
48 | - try { | ||
49 | - if (channel != null) { | ||
50 | - channel.close(); | ||
51 | - } | ||
52 | - if (conn != null) { | ||
53 | - conn.close(); | ||
54 | - } | ||
55 | - } catch (Exception e) { | ||
56 | - e.printStackTrace(); | ||
57 | - } | ||
58 | - } | ||
59 | -} |
-
请 注册 或 登录 后发表评论