Comment éviter d’avoir à spécifier l’emplacement WSDL dans un client de service Web généré par CXF ou JAX-WS?

Lorsque je génère un client de service Web à l’aide de wsdl2java depuis CXF (qui génère quelque chose de similaire à wsimport), via maven, mes services commencent par des codes comme celui-ci:

@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; } 

Le chemin absolu codé en dur est vraiment nul. La classe générée ne fonctionnera dans aucun autre ordinateur que le mien.

La première idée est de placer le fichier WSDL (plus tout ce qu’il importe, d’autres fichiers WSDL et XSD) quelque part dans un fichier jar et le classpath. Mais nous voulons éviter cela. Étant donné que tout ce qui a été généré par CXF et JAXB dans les WSDL et les XSD, nous ne voyons aucun intérêt à connaître le WSDL à l’exécution.

L’atsortingbut wsdlLocation est destiné à remplacer l’emplacement WSDL (du moins c’est ce que j’ai lu quelque part), et sa valeur par défaut est “”. Comme nous utilisons maven, nous avons essayé d’inclure dans la configuration de CXF pour essayer de forcer le générateur source à laisser le champ wsdlLocation. Cependant, cela le fait simplement ignorer la balise XML car elle est vide. Nous avons fait un piratage vraiment honteux, en utilisant " + " .

Cela change aussi d’autres endroits:

 @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; } 

Donc, mes questions sont:

  1. Avons-nous vraiment besoin d’un emplacement WSDL même si toutes les classes ont été générées par CXF et JAXB? Si oui, pourquoi?

  2. Si nous n’avons pas vraiment besoin de l’emplacement WSDL, quel est le moyen approprié et propre de faire en sorte que CXF ne le génère pas et l’évite complètement?

  3. Quels effets secondaires on pourrait avoir avec ce bidouillage? Nous ne pouvons toujours pas tester cela pour voir ce qui se passe, alors si quelqu’un pouvait le dire à l’avance, ce serait bien.

    J’ai finalement trouvé la bonne réponse à cette question aujourd’hui.

      org.apache.cxf cxf-codegen-plugin ${cxf.version}   generate-sources generate-sources  ${project.build.directory}/generated-sources/cxf   ${project.basedir}/src/main/resources/wsdl/FooService.wsdl classpath:wsdl/FooService.wsdl     wsdl2java     

    Notez que j’ai préfixé la valeur dans wsdlLocation avec classpath: wsdlLocation Cela indique au plug-in que le fichier wsdl sera sur le chemin de classe au lieu d’un chemin absolu. Ensuite, il générera un code similaire à celui-ci:

     @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; } 

    Nous utilisons

     wsdlLocation = "WEB-INF/wsdl/WSDL.wsdl" 

    En d’autres termes, utilisez un chemin relatif au classpath.

    Je crois que le WSDL peut être nécessaire lors de l’exécution pour la validation des messages lors du marshal / unmarshal.

    1) Dans certains cas, oui. Si le fichier WSDL contient des éléments tels que des règles et que ces éléments dirigent le comportement d’exécution, le fichier WSDL peut être requirejs au moment de l’exécution. Les artefacts ne sont pas générés pour les choses liées aux politiques et autres. De plus, dans certains cas obscurs de RPC / Literal, tous les espaces de noms nécessaires ne sont pas générés dans le code généré (par spécification). Ainsi, le wsdl serait nécessaire pour eux. Obscure des cas cependant.

    2) Je pensais que quelque chose comme ça marcherait. Quelle version de CXF? Cela ressemble à un bug. Vous pouvez essayer une chaîne vide là-dedans (juste des espaces). Je ne sais pas si cela fonctionne ou non. Cela dit, dans votre code, vous pouvez utiliser le constructeur qui prend l’URL WSDL et ne transmet que null. Le wsdl ne serait pas utilisé.

    3) Juste les limitations ci-dessus.

    Pour ceux qui utilisent org.jvnet.jax-ws-commons:jaxws-maven-plugin pour générer un client à partir de WSDL au moment de la construction:

    • Placez le WSDL quelque part dans votre src/main/resources
    • Ne wsdlLocation pas le wsdlLocation avec classpath:
    • Ne wsdlLocation avec /

    Exemple:

    • WSDL est stocké dans /src/main/resources/foo/bar.wsdl
    • Configurez jaxws-maven-plugin avec ${basedir}/src/main/resources/foo et /foo/bar.wsdl

    Est-il possible que vous puissiez éviter d’utiliser wsdl2java? Vous pouvez immédiatement utiliser les API CXF FrontEnd pour appeler votre service Web SOAP. Le seul problème est que vous devez créer votre SEI et vos VO sur votre client. Voici un exemple de code.

     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(Ssortingng[] args){ Ssortingng 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"); Ssortingng 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); //resortingeve book bookVO = bookService.getBook("Foundation and Earth"); System.out.println("book name : " + bookVO.getBookName()); System.out.println("book author : " + bookVO.getAuthor()); } } 

    Vous pouvez voir le tutoriel complet ici http://weblog4j.com/2012/05/01/developing-soap-web-service-using-apache-cxf/

    J’ai pu générer

     static { WSDL_LOCATION = null; } 

    en configurant le fichier pom pour avoir un null pour wsdlurl:

       org.apache.cxf cxf-codegen-plugin   generate-sources generate-sources  ${basedir}/target/generated/src/main/java   ${basedir}/src/main/resources/service.wsdl  -client -wsdlLocation       wsdl2java     

    Mise à jour pour CXF 3.1.7

    Dans mon cas, j’ai mis les fichiers WSDL dans src/main/resources et ajouté ce chemin à mes Srouces dans Eclipse (Clic droit sur Project-> Build Path -> Configure Build Path …-> Source [Tab] -> Ajouter un dossier ).

    Voici à quoi ressemble mon fichier pom et comme on peut le voir, il n’y a AUCUNE option wsdlLocation nécessaire:

       org.apache.cxf cxf-codegen-plugin ${cxf.version}   generate-sources generate-sources  ${project.build.directory}/generated/cxf   classpath:wsdl/FOO_SERVICE.wsdl     wsdl2java     

    Et voici le service généré. Comme on peut le voir, l’URL provient de ClassLoader et non du fichier absolu.

     @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; } 

    Sérieusement, la meilleure réponse ne fonctionne pas pour moi. essayé cxf.version 2.4.1 et 3.0.10. et générer un chemin absolu avec wsdlLocation chaque fois.

    Ma solution consiste à utiliser la commande wsdl2java dans le wsdl2java la wsdl2java apache-cxf-3.0.10\bin\ avec -wsdlLocation classpath:wsdl/QueryService.wsdl .

    Détail:

      wsdl2java -encoding utf-8 -p com.jeiao.boss.testQueryService -impl -wsdlLocation classpath:wsdl/testQueryService.wsdl http://127.0.0.1:9999/platf/testQueryService?wsdl