如何避免在CXF或JAX-WS生成的Web服务客户端中指定WSDL位置?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何避免在CXF或JAX-WS生成的Web服务客户端中指定WSDL位置?相关的知识,希望对你有一定的参考价值。
当我使用来自CXF的wsdl2java(生成类似于wsimport的东西)生成一个webservice客户端时,通过maven,我的服务从这样的代码开始:
@WebServiceClient(name = "StatusManagement",
wsdlLocation = "c:/some_absolute_path_to_a_wsdl_file.wsdl",
targetNamespace = "http://tempuri.org/")
public class StatusManagement extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
static {
URL url = null;
try {
url = new URL("c:/some_absolute_path_to_a_wsdl_file.wsdl");
} catch (MalformedURLException e) {
System.err.println("Can not initialize the default wsdl from c:/some_absolute_path_to_a_wsdl_file.wsdl");
// e.printStackTrace();
}
WSDL_LOCATION = url;
}
硬编码的绝对路径真的很糟糕。生成的类不能在除我之外的任何其他计算机上工作。
第一个想法是将WSDL文件(以及它导入的所有内容,其他WSDL和XSD)放在jar文件和类路径中。但我们想避免这种情况。由于所有这些都是由基于WSDL和XSD的CXF和JAXB生成的,因此我们认为在运行时需要知道WSDL没有意义。
wsdlLocation属性旨在覆盖WSDL位置(至少这是我在某处获得的),默认值为“”。由于我们使用的是maven,我们尝试在CXF的配置中包含<wsdlLocation></wsdlLocation>
以尝试强制源生成器将wsdlLocation留空。但是,这只是使它忽略XML标记,因为它是空的。我们使用<wsdlLocation>" + "</wsdlLocation>
做了一个非常难看的可耻黑客。
这也改变了其他地方:
@WebServiceClient(name = "StatusManagement",
wsdlLocation = "" + "",
targetNamespace = "http://tempuri.org/")
public class StatusManagement extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
static {
URL url = null;
try {
url = new URL("" + "");
} catch (MalformedURLException e) {
System.err.println("Can not initialize the default wsdl from " + "");
// e.printStackTrace();
}
WSDL_LOCATION = url;
}
所以,我的问题是:
- 即使所有类都是由CXF和JAXB生成的,我们是否真的需要WSDL位置?如果是,为什么?
- 如果我们真的不需要WSDL位置,那么使CXF不生成并完全避免它的正确和干净的方法是什么?
- 我们可以通过该黑客获得哪些不良副作用?我们仍然无法测试看看会发生什么,所以如果有人可以提前说,那就太好了。
我终于在今天找到了这个问题的正确答案。
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${project.basedir}/src/main/resources/wsdl/FooService.wsdl</wsdl>
<wsdlLocation>classpath:wsdl/FooService.wsdl</wsdlLocation>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
请注意,我已将wsdlLocation
中的值与classpath:
作为前缀。这告诉插件wsdl将在类路径而不是绝对路径上。然后它将生成类似于此的代码:
@WebServiceClient(name = "FooService",
wsdlLocation = "classpath:wsdl/FooService.wsdl",
targetNamespace = "http://org/example/foo")
public class Foo_Service extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://org/example/foo", "Foo");
public final static QName FooSOAPOverHTTP = new QName("http://org/example/foo", "Foo_SOAPOverHTTP");
static {
URL url = Foo_Service.class.getClassLoader().getResource("wsdl/FooService.wsdl");
if (url == null) {
java.util.logging.Logger.getLogger(Foo_Service.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "classpath:wsdl/FooService.wsdl");
}
WSDL_LOCATION = url;
}
请注意,这仅适用于版本2.4.1或更高版本的cxf-codegen-plugin。
我们用
wsdlLocation = "WEB-INF/wsdl/WSDL.wsdl"
换句话说,使用相对于类路径的路径。
我相信在运行时可能需要WSDL来在编组/解组期间验证消息。
对于那些使用org.jvnet.jax-ws-commons:jaxws-maven-plugin
在构建时从WSDL生成客户端的人:
- 将WSDL放在
src/main/resources
中的某个位置 - 不要在
wsdlLocation
前加上classpath:
- 用
wsdlLocation
作为/
的前缀
例:
- WSDL存储在
/src/main/resources/foo/bar.wsdl
中 - 使用
jaxws-maven-plugin
和<wsdlDirectory>${basedir}/src/main/resources/foo</wsdlDirectory>
配置<wsdlLocation>/foo/bar.wsdl</wsdlLocation>
1)在某些情况下,是的。如果WSDL包含诸如策略之类的内容以及指示运行时行为的内容,那么在运行时可能需要WSDL。不会为与策略相关的事物生成工件。此外,在一些不起眼的RPC / Literal情况下,并非所有需要的命名空间都在生成的代码中输出(按照规范)。因此,他们需要wsdl。虽然模糊不清的案例。
2)我认为会有所作为。什么版本的CXF?这听起来像个bug。你可以在那里尝试一个空字符串(只是空格)。不确定这是否有效。也就是说,在您的代码中,您可以使用获取WSDL URL的构造函数并传递null。不会使用wsdl。
3)只是上面的限制。
是否有可能避免使用wsdl2java?您可以立即使用CXF FrontEnd API来调用SOAP Web服务。唯一的问题是您需要在客户端创建SEI和VO。这是一个示例代码。
package com.aranin.weblog4j.client;
import com.aranin.weblog4j.services.BookShelfService;
import com.aranin.weblog4j.vo.BookVO;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class DemoClient {
public static void main(String[] args){
String serviceUrl = "http://localhost:8080/weblog4jdemo/bookshelfservice";
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(BookShelfService.class);
factory.setAddress(serviceUrl);
BookShelfService bookService = (BookShelfService) factory.create();
//insert book
BookVO bookVO = new BookVO();
bookVO.setAuthor("Issac Asimov");
bookVO.setBookName("Foundation and Earth");
String result = bookService.insertBook(bookVO);
System.out.println("result : " + result);
bookVO = new BookVO();
bookVO.setAuthor("Issac Asimov");
bookVO.setBookName("Foundation and Empire");
result = bookService.insertBook(bookVO);
System.out.println("result : " + result);
bookVO = new BookVO();
bookVO.setAuthor("Arthur C Clarke");
bookVO.setBookName("Rama Revealed");
result = bookService.insertBook(bookVO);
System.out.println("result : " + result);
//retrieve book
bookVO = bookService.getBook("Foundation and Earth");
System.out.println("book name : " + bookVO.getBookName());
System.out.println("book author : " + bookVO.getAuthor());
}
}
你可以在这里看到完整的教程http://weblog4j.com/2012/05/01/developing-soap-web-service-using-apache-cxf/
我能够生成
static {
WSDL_LOCATION = null;
}
通过将pom文件配置为wsdlurl为null:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/service.wsdl</wsdl>
<extraargs>
<extraarg>-client</extraarg>
<extraarg>-wsdlLocation</extraarg>
<wsdlurl />
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
CXF 3.1.7的更新
在我的例子中,我将WSDL文件放在src/main/resources
中,并将此路径添加到Eclipse中的Srouces(右键单击Project-> Build Path - > Configure Build Path ...-> Source [Tab] - > Add Folder)。
这是我的pom
文件的样子,可以看出没有wsdlLocation
选项需要:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>classpath:wsdl/FOO_SERVICE.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java<以上是关于如何避免在CXF或JAX-WS生成的Web服务客户端中指定WSDL位置?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 oAuth 2.0 保护 apache cxf webservice(jax-ws)