Java JAX-WS 客户端:访问本地 WSDL 的正确路径是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4163586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JAX-WS client : what's the correct path to access the local WSDL?
提问by
The problem is I need to build a web service client from a file I'm been provided. I've stored this file on the local file system and, while I keep the WSDL file in the correct file system folder, everything is fine. When I deploy it to a server or remove the WSDL from the file system folder the proxy can't find the WSDL and rises an error. I've searched the web and I've found the following posts yet I'm not been able to make it work:
JAX-WS Loading WSDL from jar
http://www.java.net/forum/topic/glassfish/metro-and-jaxb/client-jar-cant-find-local-wsdl-0
http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html
问题是我需要从我提供的文件中构建一个 Web 服务客户端。我已将此文件存储在本地文件系统上,虽然我将 WSDL 文件保存在正确的文件系统文件夹中,但一切正常。当我将它部署到服务器或从文件系统文件夹中删除 WSDL 时,代理找不到 WSDL 并引发错误。我在网上搜索过,我发现了以下帖子,但我无法让它工作:
JAX-WS 从 jar 加载 WSDL
http://www.java.net/forum/topic/glassfish/metro -and-jaxb/client-jar-cant-find-local-wsdl-0
http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html
I'm using NetBeans 6.1 (this is a legacy application I've to update with this new web service client). Below is the JAX-WS proxy class :
我使用的是 NetBeans 6.1(这是一个遗留应用程序,我必须使用这个新的 Web 服务客户端进行更新)。下面是 JAX-WS 代理类:
@WebServiceClient(name = "SOAService", targetNamespace = "http://soaservice.eci.ibm.com/", wsdlLocation = "file:/C:/local/path/to/wsdl/SOAService.wsdl")
public class SOAService
extends Service
{
private final static URL SOASERVICE_WSDL_LOCATION;
private final static Logger logger = Logger.getLogger(com.ibm.eci.soaservice.SOAService.class.getName());
static {
URL url = null;
try {
URL baseUrl;
baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
SOASERVICE_WSDL_LOCATION = url;
}
public SOAService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public SOAService() {
super(SOASERVICE_WSDL_LOCATION, new QName("http://soaservice.eci.ibm.com/", "SOAService"));
}
/**
* @return
* returns SOAServiceSoap
*/
@WebEndpoint(name = "SOAServiceSOAP")
public SOAServiceSoap getSOAServiceSOAP() {
return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class);
}
/**
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* @return
* returns SOAServiceSoap
*/
@WebEndpoint(name = "SOAServiceSOAP")
public SOAServiceSoap getSOAServiceSOAP(WebServiceFeature... features) {
return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class, features);
}
}
This is my code to use the proxy :
这是我使用代理的代码:
WebServiceClient annotation = SOAService.class.getAnnotation(WebServiceClient.class);
// trying to replicate proxy settings
URL baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource("");//note : proxy uses "."
URL url = new URL(baseUrl, "/WEB-INF/wsdl/client/SOAService.wsdl");
//URL wsdlUrl = this.getClass().getResource("/META-INF/wsdl/SOAService.wsdl");
SOAService serviceObj = new SOAService(url, new QName(annotation.targetNamespace(), annotation.name()));
proxy = serviceObj.getSOAServiceSOAP();
/* baseUrl;
//classes\com\ibm\eci\soaservice
//URL url = new URL(baseUrl, "../../../../wsdl/SOAService.wsdl");
proxy = new SOAService().getSOAServiceSOAP();*/
//updating service endpoint
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WebServiceUrl);
NetBeans put a copy of the WSDL in web-inf/wsdl/client/SOAService, so I don't want to add it to META-INFtoo. Service classes are in WEB-INF/classes/com/ibm/eci/soaservice/and baseurl variable contains the filesystem full path to it (c:\path\to\the\project...\soaservice ). The above code raises the error:
NetBeans 将 WSDL 的副本放在web-inf/wsdl/client/SOAService 中,所以我也不想将其添加到META-INF 中。服务类位于WEB-INF/classes/com/ibm/eci/soaservice/ 中,并且 baseurl 变量包含文件系统的完整路径(c:\path\to\the\project...\soaservice)。上面的代码引发了错误:
javax.xml.ws.WebServiceException: Failed to access the WSDL at: file:/WEB-INF/wsdl/client/SOAService.wsdl. It failed with: \WEB-INF\wsdl\client\SOAService.wsdl (cannot find the path)
javax.xml.ws.WebServiceException:无法访问位于以下位置的 WSDL:文件:/WEB-INF/wsdl/client/SOAService.wsdl。它失败了:\WEB-INF\wsdl\client\SOAService.wsdl(找不到路径)
So, first of all, shall I update the wsdllocation of the proxy class? Then how do I tell the SOAService class in WEB-INF/classes/com/ibm/eci/soaservice to search for the WSDL in \WEB-INF\wsdl\client\SOAService.wsdl?
那么,首先,我应该更新代理类的wsdllocation吗?那么我如何告诉 WEB-INF/classes/com/ibm/eci/soaservice 中的 SOAService 类搜索 \WEB-INF\wsdl\client\SOAService.wsdl 中的 WSDL?
EDITED: I've found this other link - http://jianmingli.com/wp/?cat=41, which say to put the WSDL into the classpath. I'm ashamed to ask: how do I put it into the web application classpath?
编辑:我找到了另一个链接 - http://janmingli.com/wp/?cat=41,它说将 WSDL 放入类路径中。不好意思问:怎么放到web应用的classpath中呢?
采纳答案by
The best option is to use jax-ws-catalog.xml
最好的选择是使用 jax-ws-catalog.xml
When you compile the local WSDL file , override the WSDL location and set it to something like
编译本地 WSDL 文件时,覆盖 WSDL 位置并将其设置为类似
http://localhost/wsdl/SOAService.wsdl
Don't worry this is only a URI and not a URL , meaning you don't have to have the WSDL available at that address.
You can do this by passing the wsdllocation option to the wsdl to java compiler.
不要担心这只是一个 URI 而不是 URL ,这意味着您不必在该地址处获得可用的 WSDL。
您可以通过将 wsdllocation 选项传递给 wsdl to java 编译器来完成此操作。
Doing so will change your proxy code from
这样做会将您的代理代码从
static {
URL url = null;
try {
URL baseUrl;
baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
SOASERVICE_WSDL_LOCATION = url;
}
to
到
static {
URL url = null;
try {
URL baseUrl;
baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
url = new URL(baseUrl, "http://localhost/wsdl/SOAService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'http://localhost/wsdl/SOAService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
SOASERVICE_WSDL_LOCATION = url;
}
Notice file:// changed to http:// in the URL constructor.
注意 URL 构造函数中的 file:// 更改为 http:// 。
Now comes in jax-ws-catalog.xml. Without jax-ws-catalog.xml jax-ws will indeed try to load the WSDL from the location
现在出现在 jax-ws-catalog.xml 中。没有 jax-ws-catalog.xml jax-ws 确实会尝试从该位置加载 WSDL
http://localhost/wsdl/SOAService.wsdl并失败,因为没有这样的 WSDL 可用。
But with jax-ws-catalog.xml you can redirect jax-ws to a locally packaged WSDL whenever it tries to access the WSDL @
但是使用 jax-ws-catalog.xml 您可以将 jax-ws 重定向到本地打包的 WSDL,每当它尝试访问 WSDL @
http://localhost/wsdl/SOAService.wsdl.
Here's jax-ws-catalog.xml
这是 jax-ws-catalog.xml
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
<system systemId="http://localhost/wsdl/SOAService.wsdl"
uri="wsdl/SOAService.wsdl"/>
</catalog>
What you are doing is telling jax-ws that when ever it needs to load WSDL from
您正在做的是告诉 jax-ws 何时需要从中加载 WSDL
http://localhost/wsdl/SOAService.wsdl,它应该从本地路径 wsdl/SOAService.wsdl 加载它。
Now where should you put wsdl/SOAService.wsdl and jax-ws-catalog.xml ? That's the million dollar question isn't it ?
It should be in the META-INF directory of your application jar.
现在应该把 wsdl/SOAService.wsdl 和 jax-ws-catalog.xml 放在哪里?这是百万美元的问题,不是吗?
它应该在您的应用程序 jar 的 META-INF 目录中。
so something like this
所以像这样
ABCD.jar |__ META-INF |__ jax-ws-catalog.xml |__ wsdl |__ SOAService.wsdl
This way you don't even have to override the URL in your client that access the proxy. The WSDL is picked up from within your JAR, and you avoid having to have hard-coded filesystem paths in your code.
这样您甚至不必覆盖访问代理的客户端中的 URL。WSDL 是从 JAR 中提取的,因此您不必在代码中使用硬编码的文件系统路径。
More info on jax-ws-catalog.xml http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html
有关 jax-ws-catalog.xml 的更多信息 http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html
Hope that helps
希望有帮助
回答by mark
One other approach that we have taken successfully is to generate the WS client proxy code using wsimport (from Ant, as an Ant task) and specify the wsdlLocation attribute.
我们成功采用的另一种方法是使用 wsimport(来自 Ant,作为 Ant 任务)生成 WS 客户端代理代码并指定 wsdlLocation 属性。
<wsimport debug="true" keep="true" verbose="false" target="2.1" sourcedestdir="${generated.client}" wsdl="${src}${wsdl.file}" wsdlLocation="${wsdl.file}">
</wsimport>
Since we run this for a project w/ multiple WSDLs, the script resolves the $(wsdl.file} value dynamically which is set up to be /META-INF/wsdl/YourWebServiceName.wsdl relative to the JavaSource location (or /src, depending on how you have your project set up). During the build proess, the WSDL and XSDs files are copied to this location and packaged in the JAR file. (similar to the solution described by Bhasakar above)
由于我们为具有多个 WSDL 的项目运行此程序,因此脚本会动态解析 $(wsdl.file} 值,该值被设置为相对于 JavaSource 位置(或 /src,取决于你如何设置你的项目。在构建过程中,WSDL 和 XSDs 文件被复制到这个位置并打包在 JAR 文件中。(类似于上面 Bhasakar 描述的解决方案)
MyApp.jar
|__META-INF
|__wsdl
|__YourWebServiceName.wsdl
|__YourWebServiceName_schema1.xsd
|__YourWebServiceName_schmea2.xsd
Note: make sure the WSDL files are using relative refrerences to any imported XSDs and not http URLs:
注意:确保 WSDL 文件使用对任何导入的 XSD 的相对引用,而不是 http URL:
<types>
<xsd:schema>
<xsd:import namespace="http://valueobject.common.services.xyz.com/" schemaLocation="YourWebService_schema1.xsd"/>
</xsd:schema>
<xsd:schema>
<xsd:import namespace="http://exceptions.util.xyz.com/" schemaLocation="YourWebService_schema2.xsd"/>
</xsd:schema>
</types>
In the generatedcode, we find this:
在生成的代码中,我们发现:
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.2-b05-
* Generated source version: 2.1
*
*/
@WebServiceClient(name = "YourService", targetNamespace = "http://test.webservice.services.xyz.com/", wsdlLocation = "/META-INF/wsdl/YourService.wsdl")
public class YourService_Service
extends Service
{
private final static URL YOURWEBSERVICE_WSDL_LOCATION;
private final static WebServiceException YOURWEBSERVICE_EXCEPTION;
private final static QName YOURWEBSERVICE_QNAME = new QName("http://test.webservice.services.xyz.com/", "YourService");
static {
YOURWEBSERVICE_WSDL_LOCATION = com.xyz.services.webservice.test.YourService_Service.class.getResource("/META-INF/wsdl/YourService.wsdl");
WebServiceException e = null;
if (YOURWEBSERVICE_WSDL_LOCATION == null) {
e = new WebServiceException("Cannot find '/META-INF/wsdl/YourService.wsdl' wsdl. Place the resource correctly in the classpath.");
}
YOURWEBSERVICE_EXCEPTION = e;
}
public YourService_Service() {
super(__getWsdlLocation(), YOURWEBSERVICE_QNAME);
}
public YourService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
/**
*
* @return
* returns YourService
*/
@WebEndpoint(name = "YourServicePort")
public YourService getYourServicePort() {
return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class);
}
/**
*
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* @return
* returns YourService
*/
@WebEndpoint(name = "YourServicePort")
public YourService getYourServicePort(WebServiceFeature... features) {
return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class, features);
}
private static URL __getWsdlLocation() {
if (YOURWEBSERVICE_EXCEPTION!= null) {
throw YOURWEBSERVICE_EXCEPTION;
}
return YOURWEBSERVICE_WSDL_LOCATION;
}
}
Perhaps this might help too. It's just a different approach that does not use the "catalog" approach.
也许这也有帮助。这只是一种不使用“目录”方法的不同方法。
回答by Piko
Had the exactsame problem that is described herein. No matter what I did, following the above examples, to change the location of my WSDL file (in our case from a web server), it was still referencing the original location embedded within the source tree of the server process.
遇到了与此处描述的完全相同的问题。不管我做了什么,按照上面的例子,改变我的 WSDL 文件的位置(在我们的例子中是从 web 服务器),它仍然引用嵌入在服务器进程的源树中的原始位置。
After MANYhours trying to debug this, I noticed that the Exception was always being thrown from the exact same line (in my case 41). Finally this morning, I decided to just send my source client code to our trade partner so they can at least understand how the code looks, but perhaps build their own. To my shockand horrorI found a bunch of class files mixed in with my .java files within my client source tree. How bizarre!! I suspect these were a byproduct of the JAX-WS client builder tool.
之后MANY小时尝试调试这一点,我注意到,例外总是被从相同的一行抛出(在我的情况41)。最后,今天早上,我决定将我的源客户端代码发送给我们的贸易伙伴,这样他们至少可以了解代码的外观,但也许可以构建自己的代码。令我震惊和恐惧的是,我发现一堆类文件与我的客户端源代码树中的 .java 文件混合在一起。多么奇怪!!我怀疑这些是 JAX-WS 客户端构建器工具的副产品。
Once I zapped those silly .class files and performed a complete clean and rebuild of the client code, everything works perfectly!! Redonculous!!
一旦我删除了那些愚蠢的 .class 文件并执行了客户端代码的完全清理和重建,一切都完美无缺!太棒了!!
YMMV, Andrew
YMMV,安德鲁
回答by Hemus7
Thanks a ton for Bhaskar Karambelkar's answer which explains in detail and fixed my issue. But also I would like to re phrase the answer in three simple steps for someone who is in a hurry to fix
非常感谢 Bhaskar Karambelkar 的回答,它详细解释并解决了我的问题。但我也想通过三个简单的步骤重新表述答案,供急于修复的人使用
- Make your wsdl local location reference as
wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
- Create a META-INF folder right under the src. Put your wsdl file/s in a folder under META-INF, say META-INF/wsdl
Create an xml file jax-ws-catalog.xml under META-INF as below
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"> <system systemId="http://localhost/wsdl/yourwsdlname.wsdl" uri="wsdl/yourwsdlname.wsdl" /> </catalog>
- 将您的 wsdl 本地位置参考设为
wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
- 在 src 下创建一个 META-INF 文件夹。将您的 wsdl 文件/s 放在 META-INF 下的文件夹中,例如 META-INF/wsdl
在 META-INF 下创建一个 xml 文件 jax-ws-catalog.xml 如下
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"> <system systemId="http://localhost/wsdl/yourwsdlname.wsdl" uri="wsdl/yourwsdlname.wsdl" /> </catalog>
Now package your jar. No more reference to the local directory, it's all packaged and referenced within
现在打包你的jar。不再引用本地目录,全部打包并在其中引用
回答by Martin Devillers
For those of you using Spring, you can simply reference any classpath-resource using the classpath-protocol. So in case of the wsdlLocation, this becomes:
对于那些使用 Spring 的人,您可以使用 classpath-protocol 简单地引用任何 classpath-resource。所以在 wsdlLocation 的情况下,这变成:
<wsdlLocation>classpath:META-INF/webservice.wsdl</wsdlLocation>
Note that is not standard Java behavior. See also: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html
请注意,这不是标准的 Java 行为。另见:http: //docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html
回答by Shafiul
For those who are still coming for solution here, the easiest solution would be to use <wsdlLocation>
, without changing any code. Working steps are given below:
对于那些仍然在这里寻求解决方案的人,最简单的解决方案是使用<wsdlLocation>
,而无需更改任何代码。工作步骤如下:
- Put your wsdl to resource directory like :
src/main/resource
In pom file, add both wsdlDirectory and wsdlLocation(don't miss / at the beginning of wsdlLocation), like below. While wsdlDirectory is used to generate code and wsdlLocation is used at runtime to create dynamic proxy.
<wsdlDirectory>src/main/resources/mydir</wsdlDirectory> <wsdlLocation>/mydir/my.wsdl</wsdlLocation>
Then in your java code(with no-arg constructor):
MyPort myPort = new MyPortService().getMyPort();
For completeness, I am providing here full code generation part, with fluent api in generated code.
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>2.5</version> <dependencies> <dependency> <groupId>org.jvnet.jaxb2_commons</groupId> <artifactId>jaxb2-fluent-api</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-tools</artifactId> <version>2.3.0</version> </dependency> </dependencies> <executions> <execution> <id>wsdl-to-java-generator</id> <goals> <goal>wsimport</goal> </goals> <configuration> <xjcArgs> <xjcArg>-Xfluent-api</xjcArg> </xjcArgs> <keep>true</keep> <wsdlDirectory>src/main/resources/package</wsdlDirectory> <wsdlLocation>/package/my.wsdl</wsdlLocation> <sourceDestDir>${project.build.directory}/generated-sources/annotations/jaxb</sourceDestDir> <packageName>full.package.here</packageName> </configuration> </execution> </executions>
- 将您的 wsdl 放入资源目录,如:
src/main/resource
在 pom 文件中,同时添加 wsdlDirectory 和 wsdlLocation(不要错过 / 在 wsdlLocation 的开头),如下所示。wsdlDirectory 用于生成代码,而 wsdlLocation 在运行时用于创建动态代理。
<wsdlDirectory>src/main/resources/mydir</wsdlDirectory> <wsdlLocation>/mydir/my.wsdl</wsdlLocation>
然后在你的java代码中(使用无参数构造函数):
MyPort myPort = new MyPortService().getMyPort();
为了完整起见,我在这里提供了完整的代码生成部分,在生成的代码中使用了流畅的 api。
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>2.5</version> <dependencies> <dependency> <groupId>org.jvnet.jaxb2_commons</groupId> <artifactId>jaxb2-fluent-api</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-tools</artifactId> <version>2.3.0</version> </dependency> </dependencies> <executions> <execution> <id>wsdl-to-java-generator</id> <goals> <goal>wsimport</goal> </goals> <configuration> <xjcArgs> <xjcArg>-Xfluent-api</xjcArg> </xjcArgs> <keep>true</keep> <wsdlDirectory>src/main/resources/package</wsdlDirectory> <wsdlLocation>/package/my.wsdl</wsdlLocation> <sourceDestDir>${project.build.directory}/generated-sources/annotations/jaxb</sourceDestDir> <packageName>full.package.here</packageName> </configuration> </execution> </executions>