因为工作需要使用到IBM MQ ,但是大家都知道IBM MQ购买是很贵的,所以打算直接java编写一个IBM MQ Client去和对方连接。因为自己没有了解过这个,所以想先从IBM的官网下载一个IBM MQ去简单连接测试一下,有兴趣的朋友可以自己去查询一下怎么安装下载,因为已经有很多帖子说明,在此不做介绍,简单附上下载地址
https://developer.ibm.com/messaging/mq-downloads/
这里主要说明一下怎么使用java 编写IBM MQ Client SSL双向通信
准备IBM_JAVA_SDK
需要的朋友可以去下面的地址下载,解压即可用
https://download.youkuaiyun.com/download/qq_26182739/10424618
了解 MQSeries classes for Java 编程,附上中文pdf文档说明,简单易懂
https://download.youkuaiyun.com/download/qq_26182739/10424746
前面准备做好后,开始上主要代码
//初始化消息工厂,connect()方法在下方,只贴出部分方法主要代码
SSLContext ctx = connect();
System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true");
try {
//MQ队列管理器设置
mqConnectionFactory.setHostName("127.0.0.1");
mqConnectionFactory.setPort(1414);
mqConnectionFactory.setQueueManager("QM.TEST.CLIENT.FPE001");
mqConnectionFactory.setChannel("test.01.TO.client.n");//通道名称
mqConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqConnectionFactory.setCCSID(1381);
//SSL相关配置
mqConnectionFactory.setSSLFipsRequired(true);
mqConnectionFactory.setSSLSocketFactory(ctx.getSocketFactory());
//TLS_RSA_WITH_AES_256_CBC_SHA256对应通道的 ssl Cipher Spec 的值
mqConnectionFactory.setSSLCipherSuite(JmqiUtils.toCipherSuite("TLS_RSA_WITH_AES_256_CBC_SHA256"));
//SSLPeerName请根据提供的证书信息填写,如果异常会提示正确的SSLPeerName
mqConnectionFactory.setSSLPeerName("CN=test.mq.client.cn, OU=CLIENT, O=MQ TEST, C=CN");
//连接方式为client
mqConnectionFactory.setMessageSelection(WMQConstants.WMQ_MSEL_CLIENT);
mqConnectionFactory.setMQConnectionOptions(WMQConstants.WMQ_CM_CLIENT);
logger.info("start create connection...");
//如果连接的时候,弹出检查是否支持该用户名、密码,请在此处设置相应的用户名,密码
connection = mqConnectionFactory.createConnection("username","password");
logger.info("finish create connection...");
connection.start();
logger.info("connection start...");
//自动通知
//对于同步消费者,Receive方法调用返回,且没有异常发生时,将自动对收到的消息予以确认.
//对于异步消息,当onMessage方法返回,且没有异常发生时,即对收到的消息自动确认
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
} catch (JMSException e) {
e.printStackTrace();
logger.error("fail connection:"+e.getMessage(),e);
init = false;
}
创建SSL 双向连接方法的内容
怎么创建密钥以及密钥库,请自行搜索,可以直接使用 keytool
keytool是jdk自带的一款ssl管理工具,使用方法请参考下面这篇博客,在此不做介绍
https://blog.youkuaiyun.com/fengwind1/article/details/52191520
/**
* @Title:MqApplication
* @Description:创建SSL双向连接
* @return
*/
public static SSLContext connect() {
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("TLSv1.2");
SSLContext.setDefault(ctx);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("IBMX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("IBMX509");
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore tks = KeyStore.getInstance("JKS");
String selfPasswd = "pass";
//客户端私钥文件、根证书、由CA签发的证书客户端证书
ks.load(new FileInputStream(CommonUtils.appHome()+"keyStore"+System.getProperty("file.separator")+"keyStore.jks"), selfPasswd.toCharArray());
//服务端公钥文件
tks.load(new FileInputStream(CommonUtils.appHome()+"keyStore"+System.getProperty("file.separator")+"trustStore.jks"), selfPasswd.toCharArray());
kmf.init(ks, selfPasswd.toCharArray());
tmf.init(tks);
TrustManager[] tm = tmf.getTrustManagers();
final X509TrustManager[] x509tm = Arrays.asList(tm).toArray(new X509TrustManager[tm.length]);
X509TrustManager[] x509tmArray = new X509TrustManager[] {
new X509TrustManager() {
/* (non Javadoc)
* @Title: getAcceptedIssuers
* @Description: 返回受身份验证同位体信任的认证中心的数组
* @return
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
@Override
public X509Certificate[] getAcceptedIssuers() {
return x509tm[0].getAcceptedIssuers();
}
/* (non Javadoc)
* @Title: checkClientTrusted
* @Description: 给出同位体提供的部分或完整的证书链,构建到可任的根的证书路径,并且返回是否可以确认和信任将其用于基于身份验证类型的客户端 SSL 身份验证
* @param chain
* @param authType
* @throws CertificateException
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String)
*/
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType){
for(int i=0;i<chain.length;i++) {
logger.info("-------------------Check client cert"+i+"/"+authType+"---------------------");
}
try {
x509tm[0].checkClientTrusted(chain, authType);
} catch (CertificateException e) {
logger.error("Check client Cert Exception:"+e.getMessage(),e);
}
}
/* (non Javadoc)
* @Title: checkServerTrusted
* @Description: 给出同位体提供的部分或完整的证书链,构建到可任的根的证书路径,并且返回是否可以确认和信任将其用于基于身份验证类型的服务器 SSL 身份验证
* @param chain 证书链
* @param authType 使用的密钥交换算法 RSAwith256
* @throws CertificateException 此证书链不受trustManager信任
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String)
*/
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType){
for(int i=0;i<chain.length;i++) {
logger.info("-------------------Check server cert"+i+"/"+authType+"---------------------");
}
try {
x509tm[0].checkServerTrusted(chain, authType);
logger.info("finish check server cert");
} catch (CertificateException e) {
logger.error("Check server Cert Exception:"+e.getMessage(),e);
e.printStackTrace();
}
}
}
};
ctx.init(kmf.getKeyManagers(), x509tmArray, null);
//返回支持的加密套件
// logger.info("Support CipherSuites:"+Arrays.asList(en.getSupportedCipherSuites()));
//返回启用的加密套件
// logger.info("Used CipherSuites:"+Arrays.asList(en.getEnabledCipherSuites()));
} catch (Exception e) {
e.printStackTrace();
logger.error("create ssl connection failer:"+e.getMessage(),e);
}
return ctx;
}
发送消息
public class JmsProducer {
private Log logger = LogFactory.getLog(getClass());
Connection connection = null;
Destination destination = null;
MessageProducer producer = null;
Session session = null;
String line = null;
private static int status = 1;
public void JmsProducer() {
}
public void sendMsg() {
try {
session = MqApplication.session;
//队列名称从配置文件读取 创建队列 client.TO.server.N
destination = session.createQueue(ConfigUtils.getConfig("mqManage/mq/outQueue"));//
//在jms会话中创建一个消息的生产者
producer = session.createProducer(destination);
//开始连接
logger.info("start read file msg...");
//读取文件信息
File file = new File(CommonUtils.appHome()+"keyStore"+System.getProperty("file.separator")+"message.xml");
BufferedReader in = new BufferedReader(new FileReader(file));
do {
line = in.readLine();
if (line!=null){
if(line.trim().length()==0){
break;
}
TextMessage message = session.createTextMessage(line);
//传递信息
producer.send(message);
logger.info("send msg:\n"+message);
}
}
while (line != null);
recordSuccess();
} catch (Exception e) {
logger.error("send msg wrong"+e.getMessage(),e);
status = -1;
} finally {
if (producer != null) {
try {
producer.close();
}
catch (JMSException jmsex) {
logger.error("Producer could not be closed.");
}
}
if (session != null) {
try {
session.close();
}
catch (JMSException jmsex) {
logger.error("Session could not be closed.");
}
}
if (connection != null) {
try {
connection.close();
}
catch (JMSException jmsex) {
System.exit(status);
return;
}
}
}
}
private void recordSuccess() {
logger.info("SUCCESS");
status = 0;
return;
}
}
接收消息
public class JmsConsumer {
private Log logger = LogFactory.getLog(getClass());
Connection connection = null;
Destination destination = null;
MessageConsumer consumer = null;
Session session = null;
String line = null;
private static int timeout = 15000;
private static int status = 1;
public void JmsConsumer() {
}
public void receiveMsg() {
try {
session = MqApplication.session;
//队列名称从配置文件读取 创建队列 server.TO.client.N
destination = session.createQueue(ConfigUtils.getConfig("mqManage/mq/inQueue"));
//在jms会话中创建一个消息的消费者
consumer = session.createConsumer(destination);
//开始连接
logger.info("start receive msg...");
//接收消息
Message message;
do {
message = consumer.receive(timeout);
if (message != null) {
logger.info("receive msg:\n"+message);
}
}
while (message != null);
recordSuccess();
} catch (Exception e) {
logger.error("read msg wrong"+e.getMessage());
status = -1;
} finally {
if (consumer != null) {
try {
consumer.close();
}
catch (JMSException jmsex) {
logger.error("consumer could not be closed.");
}
}
if (session != null) {
try {
session.close();
}
catch (JMSException jmsex) {
logger.error("Session could not be closed.");
}
}
if (connection != null) {
try {
connection.close();
}
catch (JMSException jmsex) {
System.exit(status);
return;
}
}
}
}
private void recordSuccess() {
logger.info("SUCCESS");
status = 0;
return;
}
}
这里只贴出部分主要代码,有问题请私信
有兴趣大家还可以看看另一篇文章
Spring 整合IBM MQ 包含多路通道:https://blog.youkuaiyun.com/qq_26182739/article/details/84346565