一、服务如何安装rabbitmq
二、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
三、配置文件内容
spring.main.banner-mode=off
server.compression.enabled=true
#RabbitMq所在服务器IP
spring.rabbitmq.host=127.0.0.1
#连接端口号
spring.rabbitmq.port=5672
#用户名
spring.rabbitmq.username=root
#用户密码
spring.rabbitmq.password=123456
#消息队列名
rabbitmq.queue.names=queue1,queue2
四、配置类
@Slf4j
@Configuration(proxyBeanMethods = false)
public class AppBean implements BeanFactoryAware {
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private int port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Value(value = "${rabbitmq.queue.names}")
private Set<String> queueNames;
/**
* 创建消息队列
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.info("注册消息队列:" + queueNames);
for (String name : queueNames) {
DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) beanFactory;
Queue queue = new Queue(name);
listableBeanFactory.registerSingleton(name, queue);
}
}
@Bean
RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, Jackson2JsonMessageConverter converter) {
RabbitTemplate template = new RabbitTemplate();
template.setConnectionFactory(connectionFactory);
template.setMessageConverter(converter);
return template;
}
/**
* 使用 Jackson 转化器原因:
* 1. 使数据在远程以json的形式保存
* 2. 使不同的客户端接受相同类型的数据时,使数据能正常转换
*/
@Bean
Jackson2JsonMessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean(name = "connectionFactory")
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
return connectionFactory;
}
@Bean
Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> builder
.serializerByType(LocalDateTime.class, localDateTimeJsonSerializer())
.deserializerByType(LocalDateTime.class, localDateTimeJsonDeserializer());
}
/**
* NOTICE: 注意使用 秒级 时间戳
*/
private JsonSerializer<LocalDateTime> localDateTimeJsonSerializer() {
return new JsonSerializer<LocalDateTime>() {
@Override
public void serialize(LocalDateTime dateTime, JsonGenerator generator, SerializerProvider provider) throws IOException {
if (dateTime != null) {
long epochSecond = dateTime.toEpochSecond(ZoneOffset.ofHours(8));
generator.writeNumber(epochSecond);
}
}
};
}
/**
* NOTICE: 注意使用 秒级 时间戳
*/
private JsonDeserializer<LocalDateTime> localDateTimeJsonDeserializer() {
return new JsonDeserializer<LocalDateTime>() {
@Override
public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
long epochSecond = parser.getValueAsLong();
return LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.ofHours(8));
}
};
}
}
五、用户类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String name;
private String description;
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createBy;
}
六、发送类
@Service
public class SenderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public boolean send(String exchange, String key, User user) {
MessagePostProcessor message = new MessagePostProcessor() {
/**
* 设置消息头中的消息
*/
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setHeader("headMsg", "wjy");
// User类自动转化位字符串类型
message.getMessageProperties().setHeader("headContent", user);
return message;
}
};
System.out.println("send: " + exchange + " : " + user);
rabbitTemplate.convertAndSend(exchange, key , user, message);
return true;
}
}
七、接收类
最常用的交换机有三种:direct、topic、fanout。我分别叫他们:“直接连接交换机”,“主题路由匹配交换机”,“无路由交换机”
direct
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。
fanout
fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
topic
前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同。
它约定:
routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
binding key与routing key一样也是句点号“. ”分隔的字符串
binding key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
@Service
public class ReceiverService {
/**
* 只能完全匹配
*/
@RabbitListener(bindings = {@QueueBinding(
value = @Queue(value = "queue1"),
key = "exchange1",
exchange = @Exchange(name = "exchange1"))})
public void process1(@Payload User user, @Header(name = "headMsg") String headMsg, @Header(name = "headContent") String headContent) {
System.out.println("exchange1 DIRECT Receiver1 body: " + user);
System.out.println("exchange1 DIRECT Receiver1 head headMsg : " + headMsg);
System.out.println("exchange1 DIRECT Receiver1 head headContent : " + headContent);
}
/**
* 只能完全匹配
*/
@RabbitListener(bindings = {@QueueBinding(
value = @Queue(value = "queue2"),
key = "exchange1",
exchange = @Exchange(name = "exchange1"))})
public void process2(@Payload User user, @Header(name = "headMsg") String headMsg, @Header(name = "headContent") String headContent) {
System.out.println("exchange1 DIRECT Receiver2 body: " + user);
System.out.println("exchange1 DIRECT Receiver2 head headMsg : " + headMsg);
System.out.println("exchange1 DIRECT Receiver2 head headContent : " + headContent);
}
/**
* 只要属于“exchange2”交换机,就会转发
*/
@RabbitListener(bindings = {@QueueBinding(
value = @Queue(value = "queue1"),
exchange = @Exchange(name = "exchange2", type = ExchangeTypes.FANOUT))})
public void process3(@Payload User user, @Header(name = "headMsg") String headMsg, @Header(name = "headContent") String headContent) {
System.out.println("exchange2 FANOUT Receiver1 body: " + user);
System.out.println("exchange2 FANOUT Receiver1 head headMsg : " + headMsg);
System.out.println("exchange2 FANOUT Receiver1 head headContent : " + headContent);
}
/**
* 只要属于“exchange2”交换机,就会转发
*/
@RabbitListener(bindings = {@QueueBinding(
value = @Queue(value = "queue2"),
exchange = @Exchange(name = "exchange2", type = ExchangeTypes.FANOUT))})
public void process4(@Payload User user, @Header(name = "headMsg") String headMsg, @Header(name = "headContent") String headContent) {
System.out.println("exchange2 FANOUT Receiver2 body: " + user);
System.out.println("exchange2 FANOUT Receiver2 head headMsg : " + headMsg);
System.out.println("exchange2 FANOUT Receiver2 head headContent : " + headContent);
}
/**
* routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
* binding key与routing key一样也是句点号“. ”分隔的字符串
* binding key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
*
* 当前队列可以匹配的key有:exchange3,exchange3.s,exchange3.s.ds,exchange3.df.sf.gg
*/
@RabbitListener(bindings = {@QueueBinding(
value = @Queue(value = "queue1"),
key = "exchange3.#",
exchange = @Exchange(name = "exchange3", type = ExchangeTypes.TOPIC))})
public void process5(@Payload User user, @Header(name = "headMsg") String headMsg, @Header(name = "headContent") String headContent) {
System.out.println("exchange3 TOPIC Receiver1 body: " + user);
System.out.println("exchange3 TOPIC Receiver1 head headMsg : " + headMsg);
System.out.println("exchange3 TOPIC Receiver1 head headContent : " + headContent);
}
/**
* 当前队列可以匹配的key有:exchange3.s,exchange3.sdf
*/
@RabbitListener(bindings = {@QueueBinding(
value = @Queue(value = "queue2"),
key = "exchange3.*",
exchange = @Exchange(name = "exchange3", type = ExchangeTypes.TOPIC))})
public void process6(@Payload User user, @Header(name = "headMsg") String headMsg, @Header(name = "headContent") String headContent) {
System.out.println("exchange3 TOPIC Receiver2 body: " + user);
System.out.println("exchange3 TOPIC Receiver2 head headMsg : " + headMsg);
System.out.println("exchange3 TOPIC Receiver2 head headContent : " + headContent);
}
}
八、Api类
@RestController
@RequestMapping("/rabbitmq")
public class RabbitmqApi {
@Autowired
private SenderService sender;
@GetMapping("/sender/{exchange}/{name}/{des}")
public boolean sender(@PathVariable("exchange") String exchange, @RequestParam(required = false) String key, @PathVariable("name") String name, @PathVariable("des") String des) {
User user = new User(name, des, LocalDateTime.now());
System.out.println(user);
return sender.send(exchange, key, user);
}
}
代码地址:
https://github.com/3154834560/ampq_pub_sub