当我通过 maven 使用 CXF 中的 wsdl2java(生成类似于 wsimport 的东西)生成 Web 服务客户端时,我的服务以如下代码开始:
@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,因此我们尝试<wsdlLocation></wsdlLocation>在 CXF 的配置中包含以尝试强制源生成器将 wsdlLocation 留空。但是,这只是让它忽略 XML 标记,因为它是空的。我们做了一个非常丑陋可耻的黑客攻击,使用<wsdlLocation>" + "</wsdlLocation>.
<wsdlLocation></wsdlLocation>
<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 不生成它并完全避免它的正确和干净的方法是什么?
我们可以用那个 hack 得到什么不好的副作用?我们仍然无法对其进行测试以了解会发生什么,因此如果有人可以提前说,那就太好了。
今天终于找到了这个问题的正确答案。
<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 将位于类路径而不是绝对路径上。然后它会生成类似这样的代码:
wsdlLocation
classpath:
@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。