JMS 客户机消息转换和编码
列出了用于执行 JMS 客户机消息转换和编码的方法以及每种转换类型的代码示例。
当在 JMS 消息中读取或写入 Java 原语或对象时,会进行转换和编码。 该转换称为 JMS 客户机数据转换,以将其与队列管理器数据转换和应用程序数据转换区分开来。 当从 JMS 消息读取数据或将数据写入消息时,将严格执行转换。 文本将在内部 16 位 Unicode 表示法 1 之间转换为用于消息中文本的字符集。 数字数据将转换为 Java 基本数字类型,并转换为针对消息定义的编码。 是否执行转换以及执行的转换类型取决于 JMS 消息类型以及读或写操作。
转换类型 | ||||
---|---|---|---|---|
消息类型 | 文本 | 数字 | 其他 | None |
JMSObjectMessage
|
getObject
setObject |
|||
JMSTextMessage
|
getText
setText |
|||
JMSBytesMessage
|
readUTF
writeUTF |
readDouble
readFloat readInt readLong readShort readUnsignedShort writeDouble writeFloat writeInt writeLong writeShort |
readBoolean
readObject writeBoolean writeObject |
readByte
readUnsignedByte readBytes readChar writeByte writeBytes writeChar |
JMSStreamMessage
|
readString
writeString |
readDouble
readFloat readInt readLong readShort writeDouble writeFloat writeInt writeLong writeShort |
readBoolean
readObject writeBoolean writeObject |
readByte
readBytes readChar writeByte writeBytes writeChar |
JMSMapMessage
|
getString
setString |
getDouble
getFloat getInt getLong getShort setDouble setFloat setInt setLong setShort |
getBoolean
getObject setBoolean setObject |
getByte
getBytes readChar setByte setBytes setChar |
- 文本
目标的缺省
CodedCharacterSetId
是 1208,UTF-8
。 缺省情况下,将从 Unicode 转换文本,并作为UTF-8
文本字符串进行发送。 接收时,文本将从客户机接收的消息中的编码字符集转换为 Unicode。setText 和 writeString 方法会将文本从 Unicode 转换为针对目标定义的字符集。 应用程序可通过设置消息属性 JMS_IBM_CHARACTER_SET,来覆盖目标字符集。 JMS_IBM_CHARACTER_SET,发送消息时必须是数字编码字符集标识 2 。
发送和接收 JMSTextmessage 中的代码片段会发送两条消息。 一条在为目标定义的字符集中发送,另一条在应用程序定义的字符集 37 中发送。
getText 和 readString 方法可将消息中的文本从消息中定义的字符集转换为 Unicode。 该方法使用消息属性 JMS_IBM_CHARACTER_SET 中定义的代码页。 除非消息为 MQ 型消息且不包含
MQRFH2
,否则将从MQRFH2.CodedCharacterSetId
映射代码页。 如果消息为 MQ 型消息且无MQRFH2
,那么将从MQMD.CodedCharacterSetId
映射代码页。图 5 中的代码片段接收发送到目标的消息。 消息中的文本将从代码页IBM®037
转换回 Unicode。注: 检查文本是否转换为编码字符集 37 的简单方法是使用 IBM MQ Explorer。 浏览队列并显示消息属性,然后进行检索。将 图 4 中的代码片段与 图 1中不正确的代码片段进行对比。 在不正确的片段中,文本字符串将转换两次,一次由应用程序转换,再次由 IBM MQ转换。
图 1。 不正确的代码页转换 TextMessage tmo = session.createTextMessage(); tmo.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 37); tmo.setText(new String("Sent in EBCDIC character set 37".getBytes(CCSID.getCodepage(37)))); producer.send(tmo);
writeUTF 方法可将文本从 Unicode 转换为 1208,
UTF-8
。 文本字符串以双字节长度开头。 文本字符串的最大长度是 65534 字节。 readUTF 方法可读取由 writeUTF 方法写入的消息中的项。 它会精确读取由 writeUTF 方法写入的字节数。- 数字
目标的缺省数字编码为
Native
。 Java 的Native
编码常量具有值 273x'00000111'
,这对于所有平台都是相同的。 在接收时,消息中的数字将正确转换为数字 Java 原语。 转换过程使用消息中定义的编码以及由读取方法返回的类型。发送方法可将由 set 和 write 添加到消息中的数字转换为针对目标定义的数字编码。 设置消息属性的应用程序可以为消息覆盖目标编码 JMS_IBM_ENCODING;例如:message.setIntProperty(WMQConstants.JMS_IBM_ENCODING, WMQConstants.WMQ_ENCODING_INTEGER_REVERSED);
get 和 read 数字方法可从消息中定义的数字编码转换消息中的数字。 它们将数字转换为 read 或 get 方法指定的类型; 请参阅 ENCODING 属性。 这些方法使用
JMS_IBM_ENCODING
中定义的编码。 除非消息为 MQ 型消息且不包含MQRFH2
,否则将从MQRFH2.Encoding
映射编码。 如果消息为 MQ 型消息且无MQRFH2
,那么这些方法将使用MQMD.Encoding
中定义的编码。- 其他
boolean 方法将
true
和false
编码为 JMSByteMessage, JMSStreamMessage和 JMSMapMessage中的x'01'
和x'00'
。UTF 方法可将 Unicode 编码和解码为
UTF-8
文本字符串。 字符串限于少于 65536 个字符,并以双字节长度字段开头。Object 方法可将原语类型包装为对象。 系统会对数字和文本类型进行编码或转换,如同使用数字和文本方法读写原语类型一样。
- None
readByte、readBytes、readUnsignedByte、writeByte 和 writeBytes 方法可在不进行转换的情况下,在应用程序与消息间获取或放置单个字节或字节数组。 readChar 和 writeChar 方法可在不进行转换的情况下,在应用程序与消息间获取和放置双字节 Unicode 字符。
通过使用 readBytes 和 writeBytes 方法,应用程序可以执行自己的代码点转换,如 在 JMSBytesMessage。
IBM MQ 不会在客户机中执行任何代码页转换,因为消息是 JMSBytesMessage,并且由于使用了 readBytes 和 writeBytes 方法。 但是,如果字节表示文本,请确保应用程序使用的代码页与目标的编码字符集匹配。 消息可能重新由队列管理器转换出口进行转换。 另一种可能性是,接收 JMS 客户机程序可能遵循以下约定: 使用消息中的
JMS_IBM_CHARACTER_SET
属性将表示消息中文本的任何字节数组转换为字符串或字符。在该示例中,客户机使用目标编码字符集进行转换:
bytes.writeBytes("In the destination code page".getBytes( CCSID.getCodepage(((MQDestination) destination) .getIntProperty(WMQConstants.WMQ_CCSID))));
或者,客户机可能已选择代码页,然后在消息的 JMS_IBM_CHARACTER_SET 属性中设置相应的编码字符集。 IBM MQ classes for Java 使用 JMS_IBM_CHARACTER_SET 在MQRFH2
或消息描述符MQMD
中的 JMS 属性中设置CodedCharacterSetId
字段:String codePage = CCSID.getCodepage(37); message.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, codePage); 3
如果将字节数组写入 JMSStringMessage 或 JMSMapMessage,那么 IBM MQ classes for JMS 不会执行数据转换,因为字节被输入为十六进制数据,而不是作为 JMSStringMessage 和 JMSMapMessage中的文本。
如果字节表示应用程序中的字符,那么您必须考虑要对消息读写哪些代码点。 图 2 中的代码遵循使用目标编码字符集的约定。 如果使用缺省字符集为 JVM 创建字符串,那么字节内容将取决于平台。 Windows 上的 JVM 通常具有缺省 Charset
windows-1252
和 UNIX,UTF-8
。 Windows 与 UNIX 之间的交换要求您选择用于以字节形式交换文本的显式代码页。图 2。 在 JMSStreamMessage 中使用目标字符集写入表示字符串的字节 StreamMessage smo = producer.session.createStreamMessage(); smo.writeBytes("123".getBytes(CCSID.getCodepage(((MQDestination) destination) .getIntProperty(WMQConstants.WMQ_CCSID))));
示例
发送和接收 JMSTextmessage
文本消息无法包含不同的字符集中的文本。 该示例显示了位于不同的字符集中且在两条不同的消息中发送的文本。
TextMessage tmo = session.createTextMessage();
tmo.setText("Sent in the character set defined for the destination");
producer.send(tmo);
TextMessage tmo = session.createTextMessage();
tmo.setIntProperty(WMQConstants.JMS_IBM_CHARACTER_SET, 37);
tmo.setText("Sent in EBCDIC character set 37");
producer.send(tmo);
TextMessage tmi = (TextMessage)consumer.receive();
System.out.println(tmi.getText());
...
Sent in the character set defined for the destination
编码示例
这些事例显示在为目标定义的编码中发送的数字。 请注意,必须将 JMSBytesMessage 的 JMS_IBM_ENCODING
属性设置为对目标指定的值。
StreamMessage smo = session.createStreamMessage();
smo.writeInt(256);
producer.send(smo);
...
StreamMessage smi = (StreamMessage)consumer.receive();
System.out.println(smi.readInt());
...
256
BytesMessage bmo = session.createBytesMessage();
bmo.writeInt(256);
int encoding = ((MQDestination) (destination)).getIntProperty
(WMQConstants.WMQ_ENCODING)
bmo.setIntProperty(WMQConstants.JMS_IBM_ENCODING, encoding);
producer.send(bmo);
...
BytesMessage bmi = (BytesMessage)consumer.receive();
System.out.println(bmi.readInt());
...
256
在 JMSBytesMessage 中发送和接收文本
图 8 中的代码在 BytesMessage中发送字符串。 为简便起见,示例发送单个字符串,JMSTextMessage 对于其更为适用。 要接收包含混合类型的文本字符串 (以字节为单位) 消息,必须知道该字符串的长度 (以字节为单位) ,在 图 9中称为 TEXT_LENGTH
。 即使对于字符数固定的字符串,字节表示长度也可能会更长。
BytesMessage bytes = session.createBytesMessage();
String codePage = CCSID.getCodepage(((MQDestination) destination)
.getIntProperty(WMQConstants.WMQ_CCSID));
bytes.writeBytes("In the destination code page".getBytes(codePage));
producer.send(bytes);
BytesMessage message = (BytesMessage)consumer.receive();
int TEXT_LENGTH = new Long(message.getBodyLength())).intValue();
byte[] textBytes = new byte[TEXT_LENGTH];
message.readBytes(textBytes, TEXT_LENGTH);
String codePage = message.getStringProperty(WMQConstants.JMS_IBM_CHARACTER_SET);
String textString = new String(textBytes, codePage);
SetStringProperty(WMQConstants.JMS_IBM_CHARACTER_SET, codePage)
当前仅接受数字字符集标识。