带有MQ输入节点的IIB流的事务开始监视事件将生成MQ消息的base64编码的字节数组。现在,我想编写一个重构此字节数组的Java程序,以便可以读取标头和正文。
base64 MQ消息如下:
TUQgIAIAAAAAAAAACAAAAP////8AAAAAEQEAALgEAABNUUhSRjIgIAQAAAABAAAAQU1RIENFTUJSQSAgICAgIKVV+Fslx7YCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENFTUJSQSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhbmllbCAgICAgIBYBBRUAAADiboF1+wHSKOpNUf3pAwAAAAAAAAAAAAALICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICALAAAAMC45XGNvbW1vblxqZGtcYmluXGphdmF3LmV4ZTIwMTgxMTI1MTQzNjEyNDcgICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA/////1JGSCAAAAACAAAAvAAAAREAAAS4TVFTVFIgICAAAAAAAAAEuAAAACA8bWNkPjxNc2Q+am1zX3RleHQ8L01zZD48L21jZD4gIAAAAEg8am1zPjxEc3Q+cXVldWU6Ly8vTU9OSTwvRHN0PjxUbXM+MTU0MzE1NjU3MjQ1NjwvVG1zPjxEbHY+MjwvRGx2Pjwvam1zPiAAAAAkPHVzcj48VGhlS2V5PlRoZVZhbHVlPC9UaGVLZXk+PC91c3I+PGZvbz5iYXI8L2Zvbz4=
我进行了以下测试以使用Java解析此问题:
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Test;
import com.ibm.mq.headers.CCSID;
import com.ibm.mq.headers.MQHeaderList;
import com.ibm.mq.headers.MQMD;
import com.ibm.mq.headers.MQRFH2;
public class MqMsgTest {
@Test
public void allGood() throws Exception {
String msgBase64 = IOUtils.toString(getClass().getResourceAsStream("/mq-msg.base64"), "UTF-8");
byte[] msgBytes = DatatypeConverter.parseBase64Binary(msgBase64);
DataInputStream msgStream = new DataInputStream(new ByteArrayInputStream(msgBytes));
MQMD mqmd = new MQMD(msgStream);
Assert.assertEquals("MQHRF2 ", mqmd.getFormat());
Assert.assertEquals("daniel ", mqmd.getUserIdentifier());
MQRFH2 mqrfh2 = new MQRFH2(msgStream);
Assert.assertEquals("TheValue", mqrfh2.getStringFieldValue("usr", "TheKey"));
String body = IOUtils.toString(msgStream, CCSID.getCodepage(mqrfh2.nextCharacterSet()));
Assert.assertEquals("<foo>bar</foo>", body);
}
@Test
public void doesNotWork() throws Exception {
String msgBase64 = IOUtils.toString(getClass().getResourceAsStream("/mq-msg.base64"), "UTF-8");
byte[] msgBytes = DatatypeConverter.parseBase64Binary(msgBase64);
DataInputStream msgStream = new DataInputStream(new ByteArrayInputStream(msgBytes));
MQHeaderList headers = new MQHeaderList(msgStream, true);
Assert.assertEquals(2, headers.size());
}
}
allGood()
测试很好地解析了标头和正文。但是,如果消息不包含RFH2标头,则失败。 doesNotWork()
测试应以通用方式解析标头,但无法正常工作。
如何灵活地解析base64编码的MQ消息,以便可以访问标头和正文?
答案 0 :(得分:0)
具有MQ输入的IIB流的事务开始监视事件 节点生成MQ消息的base64编码的字节数组。现在我 想写一个重构此字节数组的Java程序 所以我可以阅读标题和正文。
为什么?为什么要合并MQMD和MQRFH2结构,然后仅使用Base64对其进行编码,以便仅使用Java程序将其提取出来?
这听起来像是一个非常糟糕的设计。
我将您的Base64消息放入了一个输出十六进制转储的程序中:
import tesserocr
from PIL import Image
import pytesseract
import matplotlib as plt
import cv2
import imutils
import numpy as np
image = cv2.imread(r'c:\ahmed\test3.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray,30,40,40)
#gray = cv2.GaussianBlur(gray,(1,1), 0)
gray =cv2.fastNlMeansDenoising(gray ,None, 4, 7, 21)
image = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,11,2)
k = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
blur = cv2.medianBlur(image,3)
erode = cv2.erode(blur, k)
dilat = cv2.dilate(erode,k)
cv2.imshow("gray", dilat)
#cv2.imshow("dilation", img_dilation)
#thresh = cv2.Canny(thresh, 70, 200)
#crop_img = gray[215:215+315, 783:783+684]
#cv2.imshow("cropped", crop_img)
#resize = imutils.resize(blur, width = 460)
#cv2.imshow("resize", resize)
text = pytesseract.image_to_string(dilat, lang='ara')
print(text)
with open(r"c:\ahmed\file.txt", "w", encoding="utf-8") as myfile:
myfile.write(text)
cv2.waitKey(0)
解码后的消息以364字节的MQMD开始,然后是202字节的MQRFH2结构。
MQHeaderList类对于解析MQMessage非常挑剔。消息必须以已知的MQ类之一开头,否则它将引发异常。使用MQHeaderList类处理问题消息可能只会导致更多问题。
最好像我一样以十六进制形式简单地转储消息,然后让支持人员或开发人员找出问题所在。
答案 1 :(得分:0)
MQHeaderList类不是魔杖,但是,我希望IBM实际上将其用途扩展为包括每个MQ标头。您的问题是您假设MQHeaderList类可以做的事情超出其范围。 MQHeaderList类只能处理11个内部MQ头/结构(aka类)。看到这里:https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.dev.doc/q030880_.htm
即MQRFH,MQRFH2,MQCIH,MQDLH,MQIIH,MQRMH,MQSAPH,MQWIH,MQXQH,MQDH和MQEPH
如您所见,MQMD不在列表中。因此,您解码的Base64消息将不适用于MQHeaderList类。
此外,您应该在这里阅读我对MQRFH2是嵌入式消息的评论:Issue While Setting MQRFH2 header in IBM MQ
您必须插入并插入IIB创建的数据流。这是完成工作的一些基本代码:
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import javax.xml.bind.DatatypeConverter;
import com.ibm.mq.headers.MQMD;
import com.ibm.mq.headers.MQRFH2;
public class Test_IIB_Data
{
public static void main(String[] args)
{
String msgBase64 = "TUQgIAIAAAAAAAAACAAAAP////8AAAAAEQEAALgEAABNUUhSRjIgIAQAAAABAAAAQU1RIENFTUJSQSAgICAgIKVV+Fslx7YCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENFTUJSQSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhbmllbCAgICAgIBYBBRUAAADiboF1+wHSKOpNUf3pAwAAAAAAAAAAAAALICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICALAAAAMC45XGNvbW1vblxqZGtcYmluXGphdmF3LmV4ZTIwMTgxMTI1MTQzNjEyNDcgICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA/////1JGSCAAAAACAAAAvAAAAREAAAS4TVFTVFIgICAAAAAAAAAEuAAAACA8bWNkPjxNc2Q+am1zX3RleHQ8L01zZD48L21jZD4gIAAAAEg8am1zPjxEc3Q+cXVldWU6Ly8vTU9OSTwvRHN0PjxUbXM+MTU0MzE1NjU3MjQ1NjwvVG1zPjxEbHY+MjwvRGx2Pjwvam1zPiAAAAAkPHVzcj48VGhlS2V5PlRoZVZhbHVlPC9UaGVLZXk+PC91c3I+PGZvbz5iYXI8L2Zvbz4=";
try
{
byte[] msgBytes = DatatypeConverter.parseBase64Binary(msgBase64);
DataInputStream msgStream = new DataInputStream(new ByteArrayInputStream(msgBytes));
MQMD md = new MQMD(msgStream);
System.out.println("md.getFormat="+md.getFormat());
System.out.println("md.getPutApplName="+md.getPutApplName());
System.out.println("md.getUserIdentifier="+md.getUserIdentifier());
MQRFH2 rfh2 = new MQRFH2(msgStream);
System.out.println("rfh2.getFormat="+rfh2.getFormat());
System.out.println("rfh2.usr.TheKey="+rfh2.getStringFieldValue("usr", "TheKey"));
int bodyLen = msgBytes.length - rfh2.getStrucLength() - md.size();
byte[] body = new byte[bodyLen];
msgStream.read(body);
System.out.println("body="+new String(body));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
运行时,输出应为:
md.getFormat=MQHRF2
md.getPutApplName=0.9\common\jdk\bin\javaw.exe
md.getUserIdentifier=daniel
rfh2.getFormat=MQSTR
rfh2.usr.TheKey=TheValue
body=<foo>bar</foo>