You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IBM MQ读取XML消息报2110错误 无法转字符串渲染UI

问题背景

从IBM MQ拉取XML消息转字符串渲染到UI时,抛出异常:com.IBM.mq.MQException: MQJE001: Completion Code '1', Reason '2110'。
消息格式为MQSTR时可正常渲染,需调整代码兼容XML格式MQ消息的字符串读取。
原实现代码:

MQQueueManager _queueManager = null;
int port = inputPort;
String hostname = host;
String channel = chanel;
String qManager = queuemanager;
String inputQName = queuename;

MQEnvironment.hostname = hostname;
MQEnvironment.channel = channel;
MQEnvironment.port = port;

_queueManager = new MQQueueManager(qManager);

int openOptions = MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING +  MQC.MQOO_BROWSE;

MQQueue queue = _queueManager.accessQueue( inputQName,
        openOptions,
        null, // default q manager
        null, // no dynamic q name
        null ); // no alternate user id

System.out.println("MQRead is now connected.\n");
int depth = queue.getCurrentDepth();
System.out.println("Current depth: " + depth + "\n");

if (depth == 0)
{
    System.out.println("Depth is zero");
}

MQGetMessageOptions getOptions = new MQGetMessageOptions();
getOptions.options = MQC.MQGMO_NO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING + MQC.MQGMO_CONVERT + MQC.MQGMO_BROWSE_NEXT;

ArrayList<MessageDTO> myMessages = new ArrayList<>();

while(true)
{
    MQMessage message = new MQMessage();

    try
    {
        queue.get(message, getOptions);
        byte[] b = new byte[message.getMessageLength()];
        message.readFully(b);

        System.out.println (new MQHeaderList (message, false));

        String newMessage =  new String(b);
        MessageDTO newMsg = new MessageDTO();
        newMsg.setMessage(newMessage);
        Random rand = new Random();
        newMsg.setMessageNumber(rand.nextInt());

        myMessages.add(newMsg);

        model.addAttribute("myMessages", myMessages);
        System.out.println(myMessages);
        message.clearMessage();
    }
    catch (IOException e)
    {
        System.out.println("IOException during GET: " + e.getMessage());
        break;
    }
    catch (MQException e)
    {
        if (e.completionCode == 2 && e.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) {
            if (depth > 0)
            {
                System.out.println("All messages read.");
            }
        }
        else
        {
            System.out.println("GET Exception: " + e);
        }
        break;
    } catch (MQDataException e) {
        e.printStackTrace();
    }

}
queue.close();
_queueManager.disconnect();
根因分析
  • 2110错误码对应MQRC_FORMAT_ERROR:代码中配置了MQC.MQGMO_CONVERT参数要求MQ客户端自动做消息格式转换,但XML消息的format字段不是内置的MQSTR字符串类型,MQ无对应转换规则直接抛出异常。
  • 原有字节转字符串逻辑未指定字符集,遇到非默认编码的消息会出现乱码。
  • 读取字节时用message.getMessageLength()会把消息头长度算入,若消息带RFH2等格式头会把头部内容读入payload,导致XML解析失败。
修复步骤
  1. 移除消息获取参数中的MQC.MQGMO_CONVERT,关闭MQ自动格式转换,直接读取原始字节。
  2. 读取内容时使用getDataLength()获取纯payload长度,跳过消息头部分。
  3. 从消息属性中读取消息自带的CCSID(字符集标识),用对应编码将字节转为字符串,避免乱码。

调整后的核心读取逻辑

// 修改消息获取参数,移除MQC.MQGMO_CONVERT
MQGetMessageOptions getOptions = new MQGetMessageOptions();
getOptions.options = MQC.MQGMO_NO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING + MQC.MQGMO_BROWSE_NEXT;

// 消息读取逻辑替换
try
{
    queue.get(message, getOptions);
    // 解析并跳过MQ消息头
    new MQHeaderList(message, false);
    
    // 仅读取payload部分字节
    byte[] b = new byte[message.getDataLength()];
    message.readFully(b);
    
    // 按消息自带字符集转字符串
    String msgCharset = CCSID.getCodepage(message.characterSet);
    String newMessage = new String(b, msgCharset);
    
    // 原有业务逻辑保持不变
    MessageDTO newMsg = new MessageDTO();
    newMsg.setMessage(newMessage);
    Random rand = new Random();
    newMsg.setMessageNumber(rand.nextInt());

    myMessages.add(newMsg);
    model.addAttribute("myMessages", myMessages);
    message.clearMessage();
}
// 原有异常捕获、队列关闭逻辑无需修改

可选简化方案

如果确认消息发送方使用固定字符集(如UTF-8)写入XML内容,可直接指定字符集转换,无需动态读取CCSID:
String newMessage = new String(b, StandardCharsets.UTF_8);

内容的提问来源于stack exchange,提问作者MaroBhunu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:42:05