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

SAP CPI中用Groovy脚本处理Multipart/mixed采购申请Payload的方法

解决SAP CPI中Multipart/mixed Payload的字段替换与移除需求

没问题,我来帮你搞定这个需求!你的Payload是嵌套的multipart结构(batch包着changesets),每个changeset里是带JSON body的HTTP PATCH请求,咱们得拆解后逐个处理JSON,再重新组装回去。下面是具体实现方案和Groovy脚本:

核心处理逻辑

因为是嵌套的multipart格式,不能直接当成普通JSON处理,得按以下步骤来:

  • 解析外层的batch multipart,拆分出所有changeset子部件
  • 对每个changeset里的HTTP请求内容,分离出HTTP头和JSON body
  • 处理JSON:将PurReqnExternalSystemType的值替换为同层级的PurchasingDocumentCategory,然后删除PurchasingDocumentCategory字段
  • 把处理后的HTTP请求重新打包,再组装成完整的multipart payload

可直接复用的Groovy脚本

这个脚本已经适配了CPI的运行环境,内置依赖都不用额外加,直接复制到Groovy Script步骤里就行:

import com.sap.gateway.ip.core.customdev.util.Message
import org.apache.commons.mail.util.MimeMessageParser
import javax.mail.internet.MimeMessage
import javax.mail.Session
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart

def Message processData(Message message) {
    // 1. 读取原始Payload并解析为MIME消息
    def inputStream = message.getBody(InputStream)
    def session = Session.getDefaultInstance(new Properties())
    def mimeMessage = new MimeMessage(session, inputStream)
    
    // 2. 解析外层的batch multipart
    def outerMultipart = mimeMessage.getContent() as MimeMultipart
    def newOuterMultipart = new MimeMultipart("mixed")
    newOuterMultipart.setBoundary(outerMultipart.getBoundary()) // 保留原始边界,避免格式错误
    
    // 3. 遍历每个changeset部件
    for (int i = 0; i < outerMultipart.getCount(); i++) {
        def innerPart = outerMultipart.getBodyPart(i)
        def innerMultipart = innerPart.getContent() as MimeMultipart
        def newInnerMultipart = new MimeMultipart("mixed")
        newInnerMultipart.setBoundary(innerMultipart.getBoundary())
        
        // 4. 处理每个changeset里的HTTP请求
        for (int j = 0; j < innerMultipart.getCount(); j++) {
            def httpPart = innerMultipart.getBodyPart(j)
            def content = httpPart.getContent().toString()
            
            // 分离HTTP头和JSON body:找第一个空行分隔符
            def splitPos = content.indexOf("\r\n\r\n")
            if (splitPos > -1) {
                def httpHeaders = content.substring(0, splitPos)
                def jsonBody = content.substring(splitPos + 4)
                
                // 只处理JSON格式的body
                if (jsonBody.trim().startsWith("{")) {
                    def jsonSlurper = new groovy.json.JsonSlurper()
                    def jsonObj = jsonSlurper.parseText(jsonBody)
                    
                    // 检查目标字段是否存在,避免空指针
                    if (jsonObj.containsKey("PurchasingDocumentCategory") && jsonObj.containsKey("PurReqnExternalSystemType")) {
                        // 替换字段值
                        jsonObj.PurReqnExternalSystemType = jsonObj.PurchasingDocumentCategory
                        // 移除不需要的字段
                        jsonObj.remove("PurchasingDocumentCategory")
                    }
                    
                    // 把处理后的JSON转回字符串
                    def jsonBuilder = new groovy.json.JsonBuilder(jsonObj)
                    jsonBody = jsonBuilder.toString()
                }
                
                // 重新组装HTTP请求内容
                def newContent = httpHeaders + "\r\n\r\n" + jsonBody
                def newHttpPart = new MimeBodyPart()
                newHttpPart.setContent(newContent, httpPart.getContentType())
                newHttpPart.setHeader("content-transfer-encoding", httpPart.getHeader("content-transfer-encoding")[0])
                
                newInnerMultipart.addBodyPart(newHttpPart)
            } else {
                // 如果没有JSON内容,直接保留原部件
                newInnerMultipart.addBodyPart(httpPart)
            }
        }
        
        // 将处理后的changeset添加回外层multipart
        def newInnerPart = new MimeBodyPart()
        newInnerPart.setContent(newInnerMultipart, innerPart.getContentType())
        newOuterMultipart.addBodyPart(newInnerPart)
    }
    
    // 5. 把处理后的multipart转成字节流,设置回消息体
    def outputStream = new ByteArrayOutputStream()
    newOuterMultipart.writeTo(outputStream)
    message.setBody(outputStream.toByteArray())
    
    // 更新Content-Type头,确保边界正确
    message.setHeader("Content-Type", "multipart/mixed; boundary=" + newOuterMultipart.getBoundary())
    
    return message
}

脚本使用注意事项

  • 兼容性:脚本用了CPI内置的JavaMail和Apache Commons库,不需要额外导入依赖
  • 容错性:如果某个changeset里没有目标字段或者不是JSON格式,会直接跳过处理,不会影响其他部分
  • 边界保留:严格复用原始的boundary值,避免重新生成边界导致下游系统解析失败
  • 测试建议:可以先用你的示例Payload在CPI的测试环境跑一遍,检查处理后的JSON是否符合预期:比如第一个Item的PurReqnExternalSystemType应该变成B,第二个变成C,且PurchasingDocumentCategory字段被移除

在CPI流中的部署步骤

  1. 在你的集成流里,在接收Payload的步骤后面添加一个Groovy Script组件
  2. 把上面的代码粘贴到脚本编辑器中
  3. 保存并部署集成流,测试即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:07:07