我目前正在用Java编写一个独立的soap请求/响应应用程序,并使用以下项目:https://gist.github.com/kdelfour/b2a449a1bac23e3baec8
我使用这个示例WSDL来开发代码:https://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php?wsdl
从上面的WSDL中,我试图调用操作:LatLonListCityNames,该操作具有以下soap请求:
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
<soapenv:Header/>
<soapenv:Body>
<ndf:LatLonListCityNames soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<displayLevel xsi:type="xsd:integer">1</displayLevel>
</ndf:LatLonListCityNames>
</soapenv:Body>
</soapenv:Envelope>
这是我下面的代码:
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* This is an example of a simple SOAP Client class to send request body to a
* SOAP Server.
*
* Useful when you want to test a SOAP server and you don't want to generate all
* SOAP client class from the WSDL.
*
* @author kdelfour
*/
public class ASimpleSOAPClient {
// Default logger
private static final Logger LOG = Logger.getLogger(ASimpleSOAPClient.class);
// The SOAP server URI
private String uriSOAPServer;
// The SOAP connection
private SOAPConnection soapConnection = null;
// If you want to add namespace to the header, follow this constant
private static final String PREFIX_NAMESPACE = "ndf";
private static final String NAMESPACE = "https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl";
/**
* A constructor who create a SOAP connection
*
* @param url
* the SOAP server URI
*/
public ASimpleSOAPClient(final String url) {
this.uriSOAPServer = url;
try {
createSOAPConnection();
} catch (UnsupportedOperationException | SOAPException e) {
LOG.error(e);
}
}
/**
* Send a SOAP request for a specific operation
*
* @param xmlRequestBody
* the body of the SOAP message
* @param operation
* the operation from the SOAP server invoked
* @return a response from the server
* @throws SOAPException
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public String sendMessageToSOAPServer(String xmlRequestBody, String operation) throws SOAPException, SAXException, IOException,
ParserConfigurationException {
// Send SOAP Message to SOAP Server
final SOAPElement stringToSOAPElement = stringToSOAPElement(xmlRequestBody);
final SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(stringToSOAPElement, operation), uriSOAPServer);
// Print SOAP Response
LOG.info("Response SOAP Message : " + soapResponse.toString());
return soapResponse.toString();
}
/**
* Create a SOAP connection
*
* @throws UnsupportedOperationException
* @throws SOAPException
*/
private void createSOAPConnection() throws UnsupportedOperationException,
SOAPException {
// Create SOAP Connection
SOAPConnectionFactory soapConnectionFactory;
soapConnectionFactory = SOAPConnectionFactory.newInstance();
soapConnection = soapConnectionFactory.createConnection();
}
/**
* Create a SOAP request
*
* @param body
* the body of the SOAP message
* @param operation
* the operation from the SOAP server invoked
* @return the SOAP message request completed
* @throws SOAPException
*/
private SOAPMessage createSOAPRequest(SOAPElement body, String operation)
throws SOAPException {
final MessageFactory messageFactory = MessageFactory.newInstance();
final SOAPMessage soapMessage = messageFactory.createMessage();
final SOAPPart soapPart = soapMessage.getSOAPPart();
// SOAP Envelope
final SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration(PREFIX_NAMESPACE, NAMESPACE);
// SOAP Body
final SOAPBody soapBody = envelope.getBody();
soapBody.addChildElement(body);
// Mime Headers
final MimeHeaders headers = soapMessage.getMimeHeaders();
LOG.info("SOAPAction : " + uriSOAPServer + operation);
headers.addHeader("SOAPAction", uriSOAPServer + operation);
soapMessage.saveChanges();
/* Print the request message */
LOG.info("Request SOAP Message :" + soapMessage.toString());
return soapMessage;
}
/**
* Transform a String to a SOAP element
*
* @param xmlRequestBody
* the string body representation
* @return a SOAP element
* @throws SOAPException
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
*/
private SOAPElement stringToSOAPElement(String xmlRequestBody)
throws SOAPException, SAXException, IOException,
ParserConfigurationException {
// Load the XML text into a DOM Document
final DocumentBuilderFactory builderFactory = DocumentBuilderFactory
.newInstance();
builderFactory.setNamespaceAware(true);
final InputStream stream = new ByteArrayInputStream(
xmlRequestBody.getBytes());
final Document doc = builderFactory.newDocumentBuilder().parse(stream);
// Use SAAJ to convert Document to SOAPElement
// Create SoapMessage
final MessageFactory msgFactory = MessageFactory.newInstance();
final SOAPMessage message = msgFactory.createMessage();
final SOAPBody soapBody = message.getSOAPBody();
// This returns the SOAPBodyElement that contains ONLY the Payload
return soapBody.addDocument(doc);
}
public static void main(String[] args) throws SOAPException, SAXException, IOException, ParserConfigurationException {
String url = "https://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php?wsdl";
ASimpleSOAPClient soapClient = new ASimpleSOAPClient(url);
String xmlMessage = "<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">rn" +
" <soapenv:Header/>rn" +
" <soapenv:Body>rn" +
" <ndf:LatLonListCityNames soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">rn" +
" <displayLevel xsi:type="xsd:integer">1</displayLevel>rn" +
" </ndf:LatLonListCityNames>rn" +
" </soapenv:Body>rn" +
"</soapenv:Envelope>";
String operation = "LatLonListCityNames";
soapClient.sendMessageToSOAPServer(xmlMessage, operation);
}
}
我尝试了xmlMessage的排列和组合,但最终总是出现不同的错误。我尝试过的一种变体是:
String xmlMessage = "<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">rn" +
" <soapenv:Header/>rn" +
" <soapenv:Body>rn" +
" <ndf:LatLonListCityNames soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">rn" +
" <displayLevel xsi:type="xsd:integer">1</displayLevel>rn" +
" </ndf:LatLonListCityNames>rn" +
" </soapenv:Body>rn" +
"</soapenv:Envelope>";
在这里,我从Envelop中删除了ndf前缀元素。这给了我一个不同的错误,如下所示:
[Fatal Error] :4:98: The prefix "ndf" for element "ndf:LatLonListCityNames" is not bound.
Exception in thread "main" org.xml.sax.SAXParseException; lineNumber: 4; columnNumber: 98; The prefix "ndf" for element "ndf:LatLonListCityNames" is not bound.
at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
at ASimpleSOAPClient.stringToSOAPElement(ASimpleSOAPClient.java:159)
at ASimpleSOAPClient.sendMessageToSOAPServer(ASimpleSOAPClient.java:78)
at ASimpleSOAPClient.main(ASimpleSOAPClient.java:183)
我不知道我在这里做错了什么。这里有什么线索吗?
提前感谢
此外,我已经尝试了以下代码:
import java.io.*;
import java.net.*;
public class AnotherSoapClient {
public static void main(String[] args) throws Exception {
String SOAPUrl = "https://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php?wsdl";
String xmlFile2Send = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ndf=\"https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl\">\r\n" + rn" +
" " <soapenv:Header/>\r\n" + rn" +
" " <soapenv:Body>\r\n" + rn" +
" " <ndf:LatLonListCityNames soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" + rn" +
" " <displayLevel xsi:type=\"xsd:integer\">1</displayLevel>\r\n" + rn" +
" " </ndf:LatLonListCityNames>\r\n" + rn" +
" " </soapenv:Body>\r\n" + rn" +
" "</soapenv:Envelope>";rn" +
" String operation = "LatLonListCityNames";
String SOAPAction = "LatLonListCityNames";
// Create the connection where we're going to send the file.
URL url = new URL(SOAPUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;
// Open the input file. After we copy it to a byte array, we can see
// how big it is so that we can set the HTTP Cotent-Length
// property. (See complete e-mail below for more on this.)
byte[] b = xmlFile2Send.getBytes();
// Set the appropriate HTTP parameters.
httpConn.setRequestProperty( "Content-Length",
String.valueOf( b.length ) );
httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction",SOAPAction);
httpConn.setRequestMethod( "POST" );
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
// Everything's set up; send the XML that was read in to b.
OutputStream out = httpConn.getOutputStream();
out.write( b );
out.close();
// Read the response and write it to standard out.
InputStreamReader isr =
new InputStreamReader(httpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
// copy method from From E.R. Harold's book "Java I/O"
public static void copy(InputStream in, OutputStream out)
throws IOException {
// do not allow other threads to read from the
// input or write to the output while copying is
// taking place
synchronized (in) {
synchronized (out) {
byte[] buffer = new byte[256];
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) break;
out.write(buffer, 0, bytesRead);
}
}
}
}
}
为此,我得到以下错误:
Exception in thread "main" java.net.ConnectException: Connection timed out: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at sun.security.ssl.SSLSocketImpl.connect(Unknown Source)
at sun.security.ssl.BaseSSLSocketImpl.connect(Unknown Source)
at sun.net.NetworkClient.doConnect(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.<init>(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.New(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)
at AnotherSoapClient.main(AnotherSoapClient.java:41)
我可以通过浏览器或soap ui访问url。我不确定我在这里发生了什么
再次感谢。
我无法修复第一个代码,但在第二个代码中,我可以按照以下答案添加代理配置,使其正常工作。我如何使HttpURLConnection使用代理?由于我能够通过我的拦截器工作,我将这个问题标记为已回答
您的代码存在多个潜在问题。将来你应该坚持你帖子中的一个特定问题和/或错误,这样我们才能清楚地回答。
用WSDL实现SOAP API可能很棘手,因为其中涉及到太多的元素。关于您的第一个错误示例:"前缀ndf…未绑定"-此错误意味着您违反了为此SOAP API定义的XML架构。你不能那样做。您要么需要提供/绑定ndf前缀,要么调整您的模式。这将修复您的XML解析器错误。这个问题很常见,你可以在这里找到更多信息:
xml模式验证错误";前缀不绑定";
导致ndf错误的代码的主要问题是:这是由于您从中删除了ndf模式声明
<soapenv:Envelope ...
在您的xmlMessage中。如果你把它从那里删除,你就不能把它放在标签名称中,比如你有的地方
<ndf:LatLonListCityNames soapenv:encodingStyle ...
您可以将所有内容标记到适当的命名空间(ndf、xsd等(,也可以删除它们。您也可以指示代码忽略解析器中的命名空间问题/验证,但随后您可能会在其他地方导致应用程序出现问题。
在提供的链接中有更多关于这方面的信息。您还将受益于web搜索"Javaxml名称空间",并对此进行进一步的阅读。
关于您的第二个错误示例:当你的代码试图连接到Weather.gov上的SSL/TLS服务器时,你收到了一个超时错误。你一直收到这个错误吗?如果是这样,你需要增加你的记录器详细程度,这样你就可以看到发生了什么。