如何在 SOAPEnvelope 中添加命名空间声明
How can I add namespace declarations in a SOAPEnvelope
在我的 soap 应用程序中,我使用的是 apache cxf。
这是我的代码,它将向服务器提交数据。
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.bus.spring.SpringBusFactory;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.ws.security.wss4j.DefaultCryptoCoverageChecker;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
SpringBusFactory bf = new SpringBusFactory();
URL busFile = Submission.class.getResource(WSSEC_XML);
File f = new File(busFile.getPath());
Bus bus = bf.createBus(busFile.toString());
BusFactory.setDefaultBus(bus);
BusFactory.setThreadDefaultBus(bus);
DefaultCryptoCoverageChecker coverageChecker = new DefaultCryptoCoverageChecker();
coverageChecker.setSignBody(true);
coverageChecker.setSignTimestamp(true);
coverageChecker.setEncryptBody(true);
coverageChecker.setSignAddressingHeaders(true);
MyClaimservice service = new MyClaimservice();
Myclaims port = service.getMyClaimsSoap11();
BindingProvider provider = (BindingProvider) port;
provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, ENDPOINT_ADDRESS);
provider.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, SOAP_ACTION);
Client client = ClientProxy.getClient(port);
client.getOutInterceptors().add(new LoggingOutInterceptor());
client.getInInterceptors().add(new LoggingInInterceptor());
client.getInInterceptors().add(new WSS4JInInterceptor(getInProps()));
client.getOutInterceptors().add(new WSS4JOutInterceptor(getOutProps()));
client.getInInterceptors().add(coverageChecker);
SubmissionResponse response = port.submission(request);
我的请求数据是这样构成的
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
....
....
....
</soap:Envelope>
我需要向 <soap:Envelope>
添加额外的命名空间。我期望的数据应该是这样的,
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prefix1="url1" xmlns:prefix2="url2" xmlns:prefix3:"url3">
....
....
....
</soap:Envelope>
我尝试使用 Map 和 XpathExpressions 将这些前缀和命名空间 URL 添加到 DefaultCryptoCoverageChecker
。但似乎它没有对我的请求数据进行任何更改。
Map<String, String> prefixes = new HashMap<String, String>();
prefixes.put("prefix1", "url1");
prefixes.put("prefix2", "url2");
prefixes.put("prefix3", "url3");
prefixes.put("prefix4", "url4");
prefixes.put("prefix5", "url5");
List<XPathExpression> xpaths = Arrays.asList(
new XPathExpression("//prefix1:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix2:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix3:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix4:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix5:Envelope", CoverageType.SIGNED));
DefaultCryptoCoverageChecker coverageChecker = new DefaultCryptoCoverageChecker();
coverageChecker.addPrefixes(prefixes);
coverageChecker.addXPaths(xpaths);
coverageChecker.setSignBody(true);
coverageChecker.setSignTimestamp(true);
coverageChecker.setEncryptBody(true);
coverageChecker.setSignAddressingHeaders(true);
如有任何帮助,我们将不胜感激。
更新二:
我试过 Apache cxf 的转换功能。
Map<String, String> outTransformMap = Collections.singletonMap("{http://schemas.xmlsoap.org/soap/envelope/}Envelope", "Envelope");
TransformOutInterceptor transformOutInterceptor = new TransformOutInterceptor();
transformOutInterceptor.setOutTransformElements(outTransformMap);
client.getOutInterceptors().add(transformOutInterceptor);
根据 http://cxf.apache.org/docs/transformationfeature.html#TransformationFeature-JAX-WS,以上代码将从 Envelope
节点中删除该特定命名空间。我还可以通过查看 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/
被从 <soap:Envelope>
中删除来确认
我尝试将 transformOutInterceptor.setOutTransformElements(outTransformMap);
替换为 transformOutInterceptor.setOutAppendElements(outTransformMap);
,其中 outTransformMap
现在包含 Collections.singletonMap("{url1 (which I need to add)}Envelope", "Envelope");
。但它并没有将其作为新命名空间附加到 Envelope
。我在这里做错了什么。除了默认命名空间之外,向 <soap:Envelope>
添加其他命名空间真的很难吗?
在 cxf 论坛上挖掘后,我找到了答案。
Map<String, String> nsMap = new HashMap<>();
nsMap.put("prefix1", "url1");
nsMap.put("prefix2", "url2");
nsMap.put("prefix3", "url3");
nsMap.put("prefix4", "url4");
nsMap.put("prefix5", "http://www.w3.org/2001/04/xmlenc#");
Client client = ClientProxy.getClient(port);
client.getRequestContext().put("soap.env.ns.map", nsMap);
如果有人知道如何为 <soap:Header>
做同样的事情,我将不胜感激
您可以这样添加headers:
UserCredentials authHeader = new UserCredentials();
authHeader.setUsername(username);
authHeader.setPassword(password);
ArrayList<Header> headers = new ArrayList<Header>(1);
try {
Header soapHeader = new Header(new QName(TQIntegrationV2.TQIntegrationV2Soap.getNamespaceURI(), "UserCredentials"), authHeader, new JAXBDataBinding(UserCredentials.class));
headers.add(soapHeader);
} catch (JAXBException ex) {
LOGGER.error("Exception trying to serialize header: {}", ex);
}
client.getRequestContext().put(Header.HEADER_LIST, headers);
如果你不想,可以离开setUsername/setPassword。
在我的 soap 应用程序中,我使用的是 apache cxf。
这是我的代码,它将向服务器提交数据。
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.bus.spring.SpringBusFactory;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.ws.security.wss4j.DefaultCryptoCoverageChecker;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
SpringBusFactory bf = new SpringBusFactory();
URL busFile = Submission.class.getResource(WSSEC_XML);
File f = new File(busFile.getPath());
Bus bus = bf.createBus(busFile.toString());
BusFactory.setDefaultBus(bus);
BusFactory.setThreadDefaultBus(bus);
DefaultCryptoCoverageChecker coverageChecker = new DefaultCryptoCoverageChecker();
coverageChecker.setSignBody(true);
coverageChecker.setSignTimestamp(true);
coverageChecker.setEncryptBody(true);
coverageChecker.setSignAddressingHeaders(true);
MyClaimservice service = new MyClaimservice();
Myclaims port = service.getMyClaimsSoap11();
BindingProvider provider = (BindingProvider) port;
provider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, ENDPOINT_ADDRESS);
provider.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, SOAP_ACTION);
Client client = ClientProxy.getClient(port);
client.getOutInterceptors().add(new LoggingOutInterceptor());
client.getInInterceptors().add(new LoggingInInterceptor());
client.getInInterceptors().add(new WSS4JInInterceptor(getInProps()));
client.getOutInterceptors().add(new WSS4JOutInterceptor(getOutProps()));
client.getInInterceptors().add(coverageChecker);
SubmissionResponse response = port.submission(request);
我的请求数据是这样构成的
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
....
....
....
</soap:Envelope>
我需要向 <soap:Envelope>
添加额外的命名空间。我期望的数据应该是这样的,
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prefix1="url1" xmlns:prefix2="url2" xmlns:prefix3:"url3">
....
....
....
</soap:Envelope>
我尝试使用 Map 和 XpathExpressions 将这些前缀和命名空间 URL 添加到 DefaultCryptoCoverageChecker
。但似乎它没有对我的请求数据进行任何更改。
Map<String, String> prefixes = new HashMap<String, String>();
prefixes.put("prefix1", "url1");
prefixes.put("prefix2", "url2");
prefixes.put("prefix3", "url3");
prefixes.put("prefix4", "url4");
prefixes.put("prefix5", "url5");
List<XPathExpression> xpaths = Arrays.asList(
new XPathExpression("//prefix1:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix2:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix3:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix4:Envelope", CoverageType.SIGNED),
new XPathExpression("//prefix5:Envelope", CoverageType.SIGNED));
DefaultCryptoCoverageChecker coverageChecker = new DefaultCryptoCoverageChecker();
coverageChecker.addPrefixes(prefixes);
coverageChecker.addXPaths(xpaths);
coverageChecker.setSignBody(true);
coverageChecker.setSignTimestamp(true);
coverageChecker.setEncryptBody(true);
coverageChecker.setSignAddressingHeaders(true);
如有任何帮助,我们将不胜感激。
更新二:
我试过 Apache cxf 的转换功能。
Map<String, String> outTransformMap = Collections.singletonMap("{http://schemas.xmlsoap.org/soap/envelope/}Envelope", "Envelope");
TransformOutInterceptor transformOutInterceptor = new TransformOutInterceptor();
transformOutInterceptor.setOutTransformElements(outTransformMap);
client.getOutInterceptors().add(transformOutInterceptor);
根据 http://cxf.apache.org/docs/transformationfeature.html#TransformationFeature-JAX-WS,以上代码将从 Envelope
节点中删除该特定命名空间。我还可以通过查看 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/
被从 <soap:Envelope>
我尝试将 transformOutInterceptor.setOutTransformElements(outTransformMap);
替换为 transformOutInterceptor.setOutAppendElements(outTransformMap);
,其中 outTransformMap
现在包含 Collections.singletonMap("{url1 (which I need to add)}Envelope", "Envelope");
。但它并没有将其作为新命名空间附加到 Envelope
。我在这里做错了什么。除了默认命名空间之外,向 <soap:Envelope>
添加其他命名空间真的很难吗?
在 cxf 论坛上挖掘后,我找到了答案。
Map<String, String> nsMap = new HashMap<>();
nsMap.put("prefix1", "url1");
nsMap.put("prefix2", "url2");
nsMap.put("prefix3", "url3");
nsMap.put("prefix4", "url4");
nsMap.put("prefix5", "http://www.w3.org/2001/04/xmlenc#");
Client client = ClientProxy.getClient(port);
client.getRequestContext().put("soap.env.ns.map", nsMap);
如果有人知道如何为 <soap:Header>
您可以这样添加headers:
UserCredentials authHeader = new UserCredentials();
authHeader.setUsername(username);
authHeader.setPassword(password);
ArrayList<Header> headers = new ArrayList<Header>(1);
try {
Header soapHeader = new Header(new QName(TQIntegrationV2.TQIntegrationV2Soap.getNamespaceURI(), "UserCredentials"), authHeader, new JAXBDataBinding(UserCredentials.class));
headers.add(soapHeader);
} catch (JAXBException ex) {
LOGGER.error("Exception trying to serialize header: {}", ex);
}
client.getRequestContext().put(Header.HEADER_LIST, headers);
如果你不想,可以离开setUsername/setPassword。