因为项目中需要使用mq进行模块解耦操作,项目为SSM项目 找了好久没有相关源码,所以按照网上的文章自己集成了一个:
一、载入依赖
<dependency>
<groupId>com.alibaba.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>3.2.6</version>
</dependency>
二、配置创建spring-context-rocketmq.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd" >
<description>RocketMQ Configuration</description>
<!-- 加载配置属性文件 --> 此处可以省略,是因为我们系统载入配置文件
<context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" />
//配置消费者类(监听类)
<bean id="messageListeners" class="com.thinkgem.jeesite.common.utils.RocketMq.RocketMqConsumer"></bean>
<!-- 配置消费者 -->
<bean id="rocketmqConsumer" class="com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer" init-method="start" destroy-method="shutdown">
<property name="consumerGroup" value="PushConsumer2"/>//订阅组名
<property name="namesrvAddr" value="${rocketMQ.address}"/>//mq地址
<property name="messageListener" ref="messageListeners"/>
<property name="subscription">
<map>
<entry key="PushTopic">//组名
<value>*</value>
</entry>
</map>
</property>
</bean>
//生产者配置
<bean id="rocketMqProducer" class="com.thinkgem.jeesite.common.utils.RocketMq.RocketMqProducer" init-method="init" destroy-method="destroy">
<property name="producerGroup" value="PushConsumer"/>
<property name="namesrvAddr" value="${rocketMQ.address}"/>
</bean>
</beans>
此处有几个坑没有注意,记录一下以防止重复犯错:
1、启动SpringMVC后生产者、消费者均没有进行初始化
原因是因为XML声明是多加了: default-lazy-init="true" 删除即可
2、生产者发送消息后,监听者没有监听到消息,管理后台查询无订阅组:
原因是因为生产者、消费者的Group Value重复了,导致冲突。名称分别区分即可解决
三、配置生产者、消费者管理类
import java.io.UnsupportedEncodingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.alibaba.rocketmq.common.message.Message;
public class RocketMqProducer {
private final static Logger logger = LoggerFactory.getLogger(RocketMqProducer.class);
private static DefaultMQProducer defaultMQProducer;
private String producerGroup;
private String namesrvAddr;
/**
* Spring bean init-method
*/
public void init() throws MQClientException {
// 参数信息
logger.info("DefaultMQProducer initialize!");
logger.info(producerGroup);
logger.info(namesrvAddr);
// 初始化
defaultMQProducer = new DefaultMQProducer(producerGroup);
defaultMQProducer.setNamesrvAddr(namesrvAddr);
defaultMQProducer.setInstanceName(String.valueOf(System.currentTimeMillis()));
defaultMQProducer.start();
logger.info("DefaultMQProudcer start success!");
}
/**
* Spring bean destroy-method
*/
public void destroy() {
defaultMQProducer.shutdown();
}
public DefaultMQProducer getDefaultMQProducer() {
return defaultMQProducer;
}
// ---------------setter -----------------
public void setProducerGroup(String producerGroup) {
this.producerGroup = producerGroup;
}
public void setNamesrvAddr(String namesrvAddr) {
this.namesrvAddr = namesrvAddr;
}
/**
* rocketmq发送消息方法
*
* @param topic 组名
* @param tagName 同一个topic下的不同 分支,同一个消费者只能取一个组的下的不同的tag分支
* @param key 保持唯一
* @param msgBody消息体
* @return
*/
public static void sendMsgIntime(String topic, String tagName, String key, String msgBody) {
Message msg = null;
try {
msg = new Message(topic,tagName,key,msgBody.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
String result = defaultMQProducer.send(msg).toString();
logger.info("send rockmq topic:" + topic + " " + result);
} catch (Exception e) {
logger.error("send rockmq error topic:" + topic + new String(msgBody), e);
}
}
}
package com.thinkgem.jeesite.common.utils.RocketMq;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.common.message.MessageExt;
public class RocketMqConsumer implements MessageListenerConcurrently{
private static final Logger log = LoggerFactory.getLogger(RocketMqConsumer.class);
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt messageExt : msgs) {
log.info("# {}", messageExt);
try {
String body = new String(messageExt.getBody(), "UTF-8");
log.info("# {}", body);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//System.out.println(messageExt.toString());
//System.out.println(new String(messageExt.getBody()));
}
log.info("# getDelayLevelWhenNextConsume={} , getMessageQueue={} , getDelayLevelWhenNextConsume={}", context.getDelayLevelWhenNextConsume(), context.getMessageQueue(), context.getDelayLevelWhenNextConsume());
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}
注:MQ发送中文会出现乱码的问题,使用msgBody.getBytes("UTF-8")即可解决
四、测试调试类:
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.common.message.Message;
import com.thinkgem.jeesite.common.utils.RocketMq.RocketMqProducer;
@Controller
@RequestMapping(value = "${frontPath}/mq")
public class TestMqController {
private static Logger logger = LoggerFactory.getLogger(TestMqController.class);
@Autowired
private RocketMqProducer rocketMqProducer;
@RequestMapping("/getLoginfo")
public String helloWord(){
String consumerStr = "666";
logger.info("消费信息:" +consumerStr);
//发送消息
Map<String, Object> msg = new HashMap<>();
msg.put("carNum", "浙A888888");
msg.put("code", "778882222");
RocketMqProducer.sendMsgIntime("PushTopic",
"push",
"",
JSON.toJSONString(msg));
return "消费信息:" +consumerStr;
}
}
调用:/f/mq/getLoginfo 成功接收消息
2021-05-22 19:18:53,233 DEBUG [jeesite.modules.sys.interceptor.LogInterceptor] - 开始计时: 07:18:53.233 URI: /f/mq/getLoginfo
2021-05-22 19:18:53,247 INFO [modules.cms.web.front.TestMqController] - 消费信息:666
2021-05-22 19:18:53,257 INFO [jeesite.common.utils.RocketMq.RocketMqProducer] - send rockmq topic:PushTopic SendResult [sendStatus=SEND_OK, msgId=A9FEC16200002A9F000000000000044C, messageQueue=MessageQueue [topic=PushTopic, brokerName=PC-20180613WXLB, queueId=0], queueOffset=3]
2021-05-22 19:18:53,262 INFO [jeesite.common.utils.RocketMq.RocketMqConsumer] - # MessageExt [queueId=0, storeSize=185, queueOffset=3, sysFlag=0, bornTimestamp=1621682333251, bornHost=/169.254.193.98:59821, storeTimestamp=1621682333254, storeHost=/169.254.193.98:10911, msgId=A9FEC16200002A9F000000000000044C, commitLogOffset=1100, bodyCRC=974590328, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message [topic=PushTopic, flag=0, properties={CLUSTER=DefaultCluster, TAGS=push, WAIT=true, MAX_OFFSET=4, MIN_OFFSET=0}, body=42]]
2021-05-22 19:18:53,262 INFO [jeesite.common.utils.RocketMq.RocketMqConsumer] - # {"carNum":"浙A888888","code":"778882222"}
2021-05-22 19:18:53,262 INFO [jeesite.common.utils.RocketMq.RocketMqConsumer] - # getDelayLevelWhenNextConsume=0 , getMessageQueue=MessageQueue [topic=PushTopic, brokerName=PC-20180613WXLB, queueId=0] , getDelayLevelWhenNextConsume=0
2021-05-22 19:18:53,270 INFO [jeesite.modules.sys.interceptor.LogInterceptor] - ViewName: 消费信息:666