Как избежать необходимости указывать расположение WSDL в клиенте веб-службы, сгенерированном CXF или JAX-WS?
когда я создаю клиент webservice с помощью wsdl2java из CXF (который генерирует что-то похожее на wsimport), через 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 (плюс все, что он импортирует, другие WSDLs и XSDs) где-то в jar-файл и classpath. Но мы хотим этого избежать. Так как все эта вещь была сгенерирована CXF и JAXB на основе WSDLs и XSDs, мы не видим смысла в необходимости знать WSDL во время выполнения.
атрибут wsdlLocation предназначен для переопределения местоположения WSDL (по крайней мере, это то, что я где-то читал), и значение по умолчанию -"". Поскольку мы используем maven, мы попытались включить <wsdlLocation></wsdlLocation> внутри конфигурации CXF, чтобы попытаться заставить генератор источника оставить 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;
}
Итак, мои вопросы:
действительно ли нам нужно расположение WSDL, даже если все классы были сгенерированы CXF и JAXB? Если да, то почему?
если нам действительно не нужно расположение WSDL, каков правильный и чистый способ заставить CXF не генерировать его и избегать его полностью?
какие плохие побочные эффекты мы могли бы получить с этим Хак? Мы все еще не можем проверить это, чтобы посмотреть, что произойдет, поэтому, если кто-то может сказать заранее, было бы неплохо.
8 ответов:
Я, наконец, понял, правильный ответ на этот вопрос сегодня.
<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 может потребоваться во время выполнения для проверки сообщений во время Маршала/unmarshal.
1) в некоторых случаях, да. Если WSDL содержит такие вещи, как политики и такие, которые управляют поведением среды выполнения, то WSDL может потребоваться во время выполнения. Артефакты не создаются для связанных с политикой вещей и тому подобного. Кроме того, в некоторых неясных случаях RPC/Literal не все необходимые пространства имен выводятся в сгенерированном коде (по спецификации). Таким образом, wsdl будет необходим для них. Хотя непонятные случаи.
2) я думал что-то вроде будет работать. Какая версия CXF? Это звучит как ошибка. Вы можете попробовать пустую строку там (только пробелы). Не уверен, что это работает или нет. Тем не менее, в вашем коде вы можете использовать конструктор, который принимает URL-адрес WSDL и просто передает null. WSDL-файл не будет использоваться.
3) только ограничения выше.
для тех, кто использует
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>
возможно ли, что вы можете избежать использования wsdl2java? Вы можете сразу же использовать интерфейсные API CXF для вызова вашего веб-сервиса SOAP. Единственная загвоздка в том, что вам нужно создать свой SEI и VOs на вашем клиентском конце. Вот пример кода.
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-файла, чтобы иметь значение null для wsdlurl:
<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и добавил этот путь к моим Srouces в Eclipse (щелкните правой кнопкой мыши на Project-> Build Path -> Configure Build Path...- >Источник[Вкладка] - > Добавить Папку).вот как мой
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</goal> </goals> </execution> </executions> </plugin>и вот сгенерированный сервисом. Как видно URL-адрес получается из загрузчика классов, а не из Абсолюта File-Path
@WebServiceClient(name = "EventService", wsdlLocation = "classpath:wsdl/FOO_SERVICE.wsdl", targetNamespace = "http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/") public class EventService extends Service { public final static URL WSDL_LOCATION; public final static QName SERVICE = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventService"); public final static QName EventPort = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventPort"); static { URL url = EventService.class.getClassLoader().getResource("wsdl/FOO_SERVICE.wsdl"); if (url == null) { java.util.logging.Logger.getLogger(EventService.class.getName()) .log(java.util.logging.Level.INFO, "Can not initialize the default wsdl from {0}", "classpath:wsdl/FOO_SERVICE.wsdl"); } WSDL_LOCATION = url; }
серьезно, верхний ответ не работает для меня. пробовал cxf.версия 2.4.1 и 3.0.10. и создать абсолютный путь с wsdlLocation каждый раз.
мое решение-использовать на
apache-cxf-3.0.10\bin\с-wsdlLocation classpath:wsdl/QueryService.wsdl.деталь:
wsdl2java -encoding utf-8 -p com.jeiao.boss.testQueryService -impl -wsdlLocation classpath:wsdl/testQueryService.wsdl http://127.0.0.1:9999/platf/testQueryService?wsdl
Comments