说明:本项目开发前提是,在本地windows机器上搭建了MQ,并建立好发送队列管理器,本地队列,远程队列,发送通道;在阿里云服务器上也搭建了MQ,建立了接收队列管理器,接收通道。具体步骤见本人之前的博客。地址:https://blog.csdn.net/qq_34569497/article/details/81197910
此处,模拟场景是,本地Windows机器放入测试消息后,在springboot项目中通过程序连接阿里云MQ并接收到消息。同一台机器同一个队列管理器上发送和接收消息,见本人之前的博客。地址:https://blog.csdn.net/qq_34569497/article/details/81184177。
Windows服务器上MQ发送消息,通过springboot接收阿里云服务器上消息。
由于此处只是测试通过程序接收消息,故代码只有接收部分。
1.使用java连接阿里云MQ接收消息
1.1 项目pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibmmq</groupId>
<artifactId>ibmmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ibmmq</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
</dependency>
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId>
<version>9.0.5.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2 启动类IbmmqApplication.java
package com.ibmmq.ibmmq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement
public class IbmmqApplication {
public static void main(String[] args) {
SpringApplication.run(IbmmqApplication.class, args);
}
}
1.3 IBM MQ 基本配置文件 application.properties
project.mq.host=120.79.239.214
project.mq.port=1416
project.mq.queue-manager=QM_RECEIVE
project.mq.channel=SEND_RECEIVE_CHL
#project.mq.channel=SYSTEM.DEF.SVRCONN
#project.mq.channel=SEND_RECEIVE_CONN
project.mq.username=mqm
project.mq.password=lmf000
#project.mq.password=lmf888888
project.mq.receive-timeout=20000
#MQ安装服务器地址
project.mq.host=127.0.0.1
#端口
project.mq.port=1414
#(队列管理器名称)
project.mq.queue-manager=QM_APPLE
#(通道名称)
project.mq.channel=SYSTEM.DEF.SVRCONN
#创建的MQ用户
project.mq.username=mqm
#创建的MQ用户连接密码
project.mq.password=xxxxxx
project.mq.receive-timeout= 20000
1.4基本配置处理类JmsConfig.java
package com.ibmmq.ibmmq.test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.connection.JmsTransactionManager;
import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import com.ibm.mq.jms.MQQueueConnectionFactory;
import com.ibm.msg.client.wmq.WMQConstants;
@Configuration
public class JmsConfig {
@Value("${project.mq.host}")
private String host;
@Value("${project.mq.port}")
private Integer port;
@Value("${project.mq.queue-manager}")
private String queueManager;
@Value("${project.mq.channel}")
private String channel;
@Value("${project.mq.username}")
private String username;
@Value("${project.mq.password}")
private String password;
@Value("${project.mq.receive-timeout}")
private long receiveTimeout;
@Bean
public MQQueueConnectionFactory mqQueueConnectionFactory() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName(host);
try {
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setCCSID(1208);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(queueManager);
} catch (Exception e) {
e.printStackTrace();
}
return mqQueueConnectionFactory;
}
@Bean
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(MQQueueConnectionFactory mqQueueConnectionFactory) {
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
//用户认证需要没有可注释
/* userCredentialsConnectionFactoryAdapter.setUsername(username);
userCredentialsConnectionFactoryAdapter.setPassword(password);*/
userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
return userCredentialsConnectionFactoryAdapter;
}
@Bean
@Primary
public CachingConnectionFactory cachingConnectionFactory(UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
cachingConnectionFactory.setSessionCacheSize(500);
cachingConnectionFactory.setReconnectOnException(true);
return cachingConnectionFactory;
}
@Bean
public PlatformTransactionManager jmsTransactionManager(CachingConnectionFactory cachingConnectionFactory) {
JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
jmsTransactionManager.setConnectionFactory(cachingConnectionFactory);
return jmsTransactionManager;
}
@Bean
public JmsOperations jmsOperations(CachingConnectionFactory cachingConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
jmsTemplate.setReceiveTimeout(receiveTimeout);
return jmsTemplate;
}
}
1.5 接收消息类ReceiveMessage.java
(继承MessageListenerAdapter类且使用@JmsListener注解进行监听)
注意:此处若只使用@JmsListener注解监听,会出现监听消息获取不及时或者获取不到消息的情况,加上MessageListenerAdapter后便不会出现
package com.ibmmq.ibmmq.test;
import javax.jms.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;
//消息消费者的类上必须加上@Component,或者是@Service,这样的话,消息消费者类就会被委派给Listener类,原理类似于使用SessionAwareMessageListener以及MessageListenerAdapter来实现消息驱动POJO
@Component
public class ReceiveMessage extends MessageListenerAdapter{
@Autowired
JmsOperations jmsOperations;
@Override
@JmsListener(destination = "RLQ")
public void onMessage(Message message) {
String messageBody = new String(message.toString());
System.out.println("成功监听Q1消息队列,传来的值为:" + messageBody);
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.core.JmsOperations;
import org.springframework.stereotype.Component;
//消息消费者的类上必须加上@Component,或者是@Service,这样的话,消息消费者类就会被委派给Listener类,原理类似于使用SessionAwareMessageListener以及MessageListenerAdapter来实现消息驱动POJO
@Component
public class ReceiveMessageText{
@Autowired
JmsOperations jmsOperations;
@JmsListener(destination = "Q1")
public void onMessage(String text) {
System.out.println("成功监听Q1消息队列,传来的文本值为:" + text);
}
}
成功监听Q1消息队列,传来的文本值为:my message 我的消息...
1.7 错误解决
在网上查找了很多资料,最后,有篇文章说将配置中的project.mq.channel=SEND_RECEIVE_CHL改为以下即可,
project.mq.channel=SYSTEM.DEF.SVRCONN
改完后,确实程序可以正常监听并接收消息。但是,根据文章https://blog.csdn.net/haitaofeiyang/article/details/46897323中将到的“注意:我们不建议用户连接SYSTEM.DEF.*通道。这些系统定义的通道是定义其它用户通道的模板。不建议用户使用SYSTEM.DEF.*和SYSTEM.AUTO.*通道。”。
那么,要如何使用自定义的通道呢。
所以就想到了对比自己建立的通道和系统自带的通道,发现:
系统自带:
dis chl(SYSTEM.DEF.SVRCONN)
5 : dis chl(SYSTEM.DEF.SVRCONN)
AMQ8414: Display Channel details.
CHANNEL(SYSTEM.DEF.SVRCONN) CHLTYPE(SVRCONN)
ALTDATE(2018-07-25) ALTTIME(09.41.50)
CERTLABL( ) COMPHDR(NONE)
COMPMSG(NONE) DESCR( )
DISCINT(0) HBINT(300)
KAINT(AUTO) MAXINST(999999999)
MAXINSTC(999999999) MAXMSGL(4194304)
MCAUSER( ) MONCHL(QMGR)
RCVDATA( ) RCVEXIT( )
SCYDATA( ) SCYEXIT( )
SENDDATA( ) SENDEXIT( )
SHARECNV(10) SSLCAUTH(REQUIRED)
SSLCIPH( ) SSLPEER( )
自定义通道:
dis chl(SEND_RECEIVE_CHL)
6 : dis chl(SEND_RECEIVE_CHL)
AMQ8414: Display Channel details.
CHANNEL(SEND_RECEIVE_CHL) CHLTYPE(RCVR)
ALTDATE(2018-07-25) ALTTIME(09.51.03)
BATCHSZ(50) CERTLABL( )
COMPHDR(NONE) COMPMSG(NONE)
DESCR( ) HBINT(300)
KAINT(AUTO) MAXMSGL(4194304)
MCAUSER( ) MONCHL(QMGR)
MRDATA( ) MREXIT( )
MRRTY(10) MRTMR(1000)
MSGDATA( ) MSGEXIT( )
NPMSPEED(FAST) PUTAUT(DEF)
RCVDATA( ) RCVEXIT( )
RESETSEQ(NO) SCYDATA( )
SCYEXIT( ) SENDDATA( )
SENDEXIT( ) SEQWRAP(999999999)
SSLCAUTH(REQUIRED) SSLCIPH( )
SSLPEER( ) STATCHL(QMGR)
TRPTYPE(TCP) USEDLQ(YES)
对比可见,两者最大的不同即CHLTYPE,自定义的通道为RCVR,而系统自带的通道为SVRCONN。通过百度IBM MQ CHLTYPE类型,知道原来SVRCONN代表服务器连接通道,而RCVR代表接收方通道。
服务器连接通道就是给MQ客户端连接进来的一个标识入口,它和其他通道不一样,它是不需要启动的,如果有MQ客户端成功地通过这个服务器连接通道连接进来,它的状态就是活动的了。因此我们需要在阿里云上对应的队列管理器中建立服务器连接通道后,才可通过java进行连接。
创建服务器连接通道:
DEFINE CHANNEL(SEND_RECEIVE_CONN) CHLTYPE(SVRCONN) TRPTYPE(TCP)
要为受 SSL 保护的 IBM MessageSight 连接创建服务器连接通道:
DEFINE CHANNEL(SEND_RECEIVE_CONN) CHLTYPE(SVRCONN) TRPTYPE(TCP) SSLCIPH(cipherSpec)
创建好后,将java配置文件中channel改为:project.mq.channel=SEND_RECEIVE_CONN
再次启动服务,发现不再报错。
1.8 测试结果
本地远程中放入测试消息:
服务中监听到的消息:
成功监听Q1消息队列,传来的值为:
JMSMessage class: jms_text
JMSType: null
JMSDeliveryMode: 1
JMSDeliveryDelay: 0
JMSDeliveryTime: 0
JMSExpiration: 0
JMSPriority: 0
JMSMessageID: ID:414d5120514d5f53454e442020202020d71a595b24ad7a02
JMSTimestamp: 1532596311700
JMSCorrelationID: null
JMSDestination: null
JMSReplyTo: null
JMSRedelivered: false
JMSXAppID: Windows\bin64\MQExplorer.exe
JMSXDeliveryCount: 1
JMSXUserID: lmf
JMS_IBM_Character_Set: UTF-8
JMS_IBM_Encoding: 546
JMS_IBM_Format: MQSTR
JMS_IBM_MsgType: 8
JMS_IBM_PutApplType: 11
JMS_IBM_PutDate: 20180726
JMS_IBM_PutTime: 09115170
test my message
作者:1275012490 来源:CSDN 原文:https://blog.csdn.net/qq_34569497/article/details/81223958?utm_source=copy
package com.my.mqserver.mqserver.util;
import com.ibm.mq.*;
public class MQUtil {
private String qManager; // QueueManager名
private MQQueueManager qMgr; // 队列管理器名称
private MQQueue qQueue; // 消息通道
String HOST_NAME; // 主机名,在这里我填写了IP地址
int PORT = 0; // 端口号
String Q_NAME; // 本地队列
String CHANNEL; // 连接通道
int CCSID;
String Msg;
/**
* 初始化
*/
public void init() {
try {
/* HOST_NAME = "127.0.0.1";
PORT = 1414;
qManager = "QM_APPLE";
Q_NAME = "Q1";
CHANNEL = "QM_ORANGE.QM_APPLE";
CCSID = 1383; // 表示是简体中文,
MQEnvironment.hostname = HOST_NAME;
MQEnvironment.port = PORT;
MQEnvironment.channel = "SYSTEM.DEF.SVRCONN"; */
HOST_NAME = "127.0.0.1";
PORT = 1414;
qManager = "QM_APPLE";
Q_NAME = "Q1";
CHANNEL = "QM_ORANGE.QM_APPLE";
CCSID = 1383; // 表示是简体中文,
MQEnvironment.hostname = HOST_NAME;
MQEnvironment.port = PORT;
MQEnvironment.channel = "SYSTEM.DEF.SVRCONN";
MQEnvironment.CCSID = CCSID;
qMgr = new MQQueueManager(qManager);
int qOptioin = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_INQUIRE | MQC.MQOO_OUTPUT;
qQueue = qMgr.accessQueue(Q_NAME, qOptioin);
} catch (MQException e) {
e.printStackTrace();
System.out.println("发生了一起异常,异常原因:" + e.reasonCode);
}
}
void finalizer() {
try {
qQueue.close();
qMgr.disconnect();
} catch (MQException e) {
System.out.println("发生了一起异常,异常原因:" + e.reasonCode);
}
}
/*
* 获取消息
*/
public void GetMsg() throws ClassNotFoundException {
try {
MQMessage revMessage = new MQMessage();
MQGetMessageOptions gmo = new MQGetMessageOptions();
revMessage.characterSet=CCSID;
revMessage.encoding=CCSID;
gmo.options += MQC.MQPMO_SYNCPOINT;
qQueue.get(revMessage, gmo);
String revString = revMessage.readStringOfByteLength(revMessage.getMessageLength());
System.out.println("接收到的内容:"+revString);
} catch (RuntimeException e) {
e.printStackTrace();
} catch (MQException e) {
if (e.reasonCode != 2033) // 没有消息
{
System.out.println("发生了一起异常,异常原因:" + e.reasonCode);
e.printStackTrace();
}
} catch (java.io.IOException e) {
System.out.println("发生了一起IO异常:" + e);
e.printStackTrace();
}
}
/**
* 发送消息
*
*/
public void SendMsg(String msgStr) {
try {
MQMessage qMsg = new MQMessage();
qMsg.encoding=CCSID;
qMsg.characterSet=CCSID;
qMsg.writeString(msgStr);
MQPutMessageOptions pmo = new MQPutMessageOptions();
qQueue.put(qMsg, pmo);
System.out.println("消息发送成功!发送的内容是:" + msgStr);
} catch (MQException e) {
System.out.println("发生了一起异常,异常原因:" + e.reasonCode);
} catch (java.io.IOException e) {
System.out.println("发生了一起IO异常:" + e);
}
}
public static void main(String[] args) {
MQUtil mqst = new MQUtil();
mqst.init();
try {
mqst.SendMsg("你好,我是一条测试消息!");
//mqst.GetMsg();
} catch (Exception e) {
e.printStackTrace();
}
mqst.finalizer();
}
}