这是对我有用的一个(特别是通过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
名为 example的类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')
// If the file is missing there will be an exception at connect
// time from sun.net.www.protocol.file.FileURLConnection.connect
// It should be possible to denote a resource on the classpath
// instead of a file-on-disk. Not sure how, maybe by adding a handler
// for a 'resource:' URL scheme?
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()
另一种方法是在与用于服务调用(用于tcpdump -n -nn -s0 -A -i eth0 'tcp port 80'
观察流量)的连接不同的连接上下载 WSDL,只需执行以下操作:
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()
请注意,如果指定https ,这实际上正确使用https,尽管事实上已经使用. (不知道为什么 - 服务是否使用用于检索 WSDL 资源的方案?)wsdlLocationUri
wsService
SERVICE_NAME_HTTP
就是这样。
要调试连接,请通过:
-Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true
-Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dump=true
在命令行上到 JVM。这会将来自 http 连接代码的信息写入标准输出(不幸的是,不是java.util.logging
。Oracle,拜托!)。