这是我使用的一个适用于我(特别是通过
http和
https)的方法。Oracle JDK 1.8.0_51的JAX-WS与
Apache CXF 3.1.1创建的类一起工作。
请注意,无论如何,远程WSDL仅在第一次调用时获取。根据使用模式(长时间运行的程序),这可能完全可以接受。
基础知识:
- 从远程主机下载WSDL并存储为文件:
wget --output-document=wsdl_raw.xml $WSDL_URL
- 您可能希望使用
xmllint --format wsdl_raw.xml > wsdl.xml
进行漂亮的格式化
- 使用命令行工具生成客户端类:
./cxf/bin/wsdl2java -d output/ -client -validate wsdl.xml
并导入到您的项目中
请确认WSDL文件中同时存在http和https的服务定义。在我的情况下,提供者没有为https提供一个服务定义(但接受https流量),因此我不得不手动添加。类似以下内容应该包含在WSDL中:
<wsdl:service name="fooservice">
<wsdl:port binding="tns:fooserviceSoapBinding" name="FooBarWebServicePort">
<soap:address location="http://ws.example.com/a/b/FooBarWebService"/>
</wsdl:port>
</wsdl:service>
<wsdl:service name="fooservice-secured">
<wsdl:port binding="tns:fooserviceSoapBinding" name="FooBarWebServicePort">
<soap:address location="https://ws.example.com/a/b/FooBarWebService"/>
</wsdl:port>
</wsdl:service>
CXF应该生成一个实现javax.xml.ws.Service
接口的类,命名为Fooservice
,并具有适当的构造函数:
public class Fooservice extends Service {
public Fooservice(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public Fooservice(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public Fooservice() {
super(WSDL_LOCATION, SERVICE);
}
...etc...
在你的代码中(这里是一些易于阅读的Groovy代码),你初始化了上述的
Service
实例,然后调用一个端口。在这里,根据名为
secure
的标志,我们使用
https或
http:
static final String NAMESPACE = 'com.example.ws.a.b'
static final QName SERVICE_NAME_HTTP = new QName(NAMESPACE, 'fooservice')
static final QName SERVICE_NAME_HTTPS = new QName(NAMESPACE, 'fooservice-secured')
Fooservice wsService
File wsdlfile = new File('/somewhere/on/disk/wsdl.xml')
URI wsdlLocationUri = java.nio.file.Paths(wsdlfile.getCanonicalPath()).toUri()
if (secure) {
wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTPS)
}
else {
wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTP)
}
SomeServicePort port = wsService.getSomeServicePort()
port.doStuff()
另一种方法是在与用于服务调用的连接分开的连接上下载WSDL(使用
tcpdump -n -nn -s0 -A -i eth0 'tcp port 80'
观察流量),只需执行以下操作:
URI wsdlLocationUri
if (secure) {
wsdlLocationUri = new URI('https://ws.example.com/a/b/FooBarWebService?wsdl')
}
else {
wsdlLocationUri = new URI('http://ws.example.com/a/b/FooBarWebService?wsdl')
}
Fooservice wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTP)
SomeServicePort port = wsService.getSomeServicePort()
port.doStuff()
请注意,如果
wsdlLocationUri
指定了
https,那么这实际上会正确使用
https,尽管
wsService
已经使用
SERVICE_NAME_HTTP
进行初始化。(不确定为什么-服务是否使用检索WSDL资源所采用的方案?)
就是这样。
要调试连接,请传递:
-Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true
-Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dump=true
在命令行中向JVM传递参数,这将把http连接代码的信息写入stdout(不幸的是,不写入java.util.logging
。Oracle,请注意!)。