SAP CPI中用Groovy脚本处理Multipart/mixed采购申请Payload的方法
解决SAP CPI中Multipart/mixed Payload的字段替换与移除需求
没问题,我来帮你搞定这个需求!你的Payload是嵌套的multipart结构(batch包着changesets),每个changeset里是带JSON body的HTTP PATCH请求,咱们得拆解后逐个处理JSON,再重新组装回去。下面是具体实现方案和Groovy脚本:
核心处理逻辑
因为是嵌套的multipart格式,不能直接当成普通JSON处理,得按以下步骤来:
- 解析外层的
batchmultipart,拆分出所有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流中的部署步骤
- 在你的集成流里,在接收Payload的步骤后面添加一个Groovy Script组件
- 把上面的代码粘贴到脚本编辑器中
- 保存并部署集成流,测试即可
内容的提问来源于stack exchange,提问作者user928700
相关产品推荐
相关产品推荐

