[英]Building a SOAP client in Java
我想将Java的SOAP API与Java一起使用,以校准一种方法:
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<GetReturnAnalysis xmlns="http://www.address.com/integration">
<entityCode>186D3CAD-0841</entityCode>
</GetReturnAnalysis>
</env:Body>
</env:Envelope>
为了做到这一点,我创建了以下类:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "GetReturnAnalysis")
public class GetReturnAnalysisRequest {
@XmlElement(name = "entityCode")
protected String entityCode;
@XmlAttribute(name="xmlns", required = true)
public final static String xmlns="http://www.address.com/integration";
public GetReturnAnalysisRequest(String entityCode) {
this.entityCode = entityCode;
}
public GetReturnAnalysisRequest() { }
public String getEntityCode() {
return entityCode;
}
public void setEntityCode(String entityCode) {
this.entityCode = entityCode;
}
}
并做了以下代码来构建要发送的消息:
private SOAPMessage createSOAPRequest(GetReturnAnalysis request) throws SOAPException, JAXBException, IOException, ParserConfigurationException, SAXException {
MessageFactory messageFactory = MessageFactory.newInstance("SOAP 1.2 Protocol");
SOAPMessage message = messageFactory.createMessage();
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
message.getSOAPHeader().detachNode();
SOAPBody body = envelope.getBody();
String requestString = XmlHelper.toOutputString(request);
Document doc = convertStringToDocument(requestString);
body.addDocument(doc);
message.writeTo(System.out);
message.saveChanges();
message.writeTo(System.out);
return message;
}
(在此代码中内部调用的方法):
public static <T> String toOutputString(T type) throws IOException {
Validate.notNull(type, "Java type not defined!");
try {
StringWriter os = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(type.getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(type, os);
System.out.println(os.toString());
return os.toString();
} catch (JAXBException e) {
throw new IOException(e);
}
}
private Document convertStringToDocument(String xml) throws SAXException, IOException, ParserConfigurationException {
return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
}
以我的观点,它应该起作用。 但是,它会生成这样的XML:
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<GetReturnAnalysis xmlns="">
<entityCode>186D3CAD-0841</entityCode>
</GetReturnAnalysis>
</env:Body>
</env:Envelope>
服务器不接受它,因为它没有填写xmlns =“ http://www.address.com/integration”属性。 我想知道这是否归因于属性(xmlns)的名称...但是,这是服务器期望的名称,因为它是第三方API,所以我无法更改它。
我也尝试使它与众不同,声明了这样的类:
@XmlRootElement(name = "GetReturnAnalysis", namespace = "http://www.address.com/integration")
public class GetReturnAnalysisRequest { ...
但是,当我添加到消息中(body.addDocument方法)时,它会检索到错误(那里不应该有名称空间)。
您可能已经注意到,在代码上,我放置了两个message.writeTo(用于调试,位于createSOAPRequest方法上)。 第一个正确地给了我XML,第二个正确地给了我XML,在我调用“保存”之后,我在GetReturnAnalysis上得到了xmlns属性为空的xml。
我想知道您是否可以帮助我。 我是SOAP的新手,在这个问题上遇到了很多麻烦...
更新1
我已经使用邮递员成功发送了以下XML消息:
<?xml version="1.0" encoding="utf-8"?>
<env:Envelope xmlns="http://www.address.com/integration" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<GetReturnAnalysis >
<entityCode>186D3CAD-0841</entityCode>
</GetReturnAnalysis>
</env:Body>
</env:Envelope>
所以我对代码做了一些小的更改,更改了类
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "GetReturnAnalysis")
public class GetReturnAnalysisRequest {
@XmlElement(name = "entityCode")
protected String entityCode;
public GetReturnAnalysisRequest(String entityCode) {
this.entityCode = entityCode;
}
public GetReturnAnalysisRequest() { }
public String getEntityCode() {
return entityCode;
}
public void setEntityCode(String entityCode) {
this.entityCode = entityCode;
}
}
和create SOAP request方法:
private SOAPMessage createSOAPRequest(GetReturnAnalysis request) throws SOAPException, JAXBException, IOException, ParserConfigurationException, SAXException {
MessageFactory messageFactory = MessageFactory.newInstance("SOAP 1.2 Protocol");
SOAPMessage message = messageFactory.createMessage();
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("", "http://www.address.com/integration");
envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
message.getSOAPHeader().detachNode();
SOAPBody body = envelope.getBody();
String requestString = XmlHelper.toOutputString(request);
Document doc = convertStringToDocument(requestString);
body.addDocument(doc);
message.writeTo(System.out);
message.saveChanges();
message.writeTo(System.out);
return message;
}
但是,由于某些不确定的原因,当我调用message.saveChanges时,GetReturnAnalysis类最终如下所示:
<GetReturnAnalysis xmlns="">
<EntityCode>186D3CAD-0841</EntityCode>
</GetReturnAnalysis>ityCode>
并且空的xmlns属性将覆盖我提供的整体名称空间。 我想知道为什么会这样吗? 它不能简单地保存我想要保存的字符串,而无需更改吗?
您的代码中有几个问题
命名空间定义:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "GetReturnAnalysis", namespace = "http://www.address.com/integration")
public class GetReturnAnalysisRequest {
@XmlElement(name = "entityCode", namespace = "http://www.address.com/integration")
protected String entityCode;
public GetReturnAnalysisRequest(String entityCode) {
this.entityCode = entityCode;
}
public GetReturnAnalysisRequest() { }
public String getEntityCode() {
return entityCode;
}
public void setEntityCode(String entityCode) {
this.entityCode = entityCode;
}
}
第二-将文档构建器设置为名称空间感知
String requestString = toOutputString(request);
Document doc = convertStringToDocument(requestString);
body.addDocument(doc);
message.writeTo(System.out);
--
private Document convertStringToDocument(String xml) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setNamespaceAware(true);
return docFactory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
}
使用框架
要真正使用Web服务,您应该使用框架。 我建议使用CXF (我的首选)或Axis2 。 然后,您可以定义服务接口并生成正确的wsdl和客户端类,并且获得对其他可选协议和扩展(例如安全性)的支持。
直接处理XML我仅在特殊情况下建议使用,例如RPC文字,自定义安全性或其他不再受支持的协议。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.