Apache CXF avec WSDL First

L'application CXF-POJO que vous avez développée se traduit par un couplage très étroit entre le client et le serveur. Donner un accès direct à l'interface de service peut également poser de graves menaces pour la sécurité. Ainsi, un découplage entre le client et le serveur est généralement souhaité, ce qui est réalisé en utilisant WSDL (Web Services Description Language).

Nous écrivons l'interface du service Web dans un document WSDL basé sur XML. Nous utiliserons un outil pour mapper ce WSDL aux interfaces Apache CXF qui sont ensuite implémentées et utilisées par nos applications client et serveur. Pour assurer le découplage, commencer par un WSDL est un moyen préféré. Pour cela, vous devez d'abord apprendre un nouveau langage - WSDL. L'écriture de WSDL nécessite une approche prudente et il serait préférable que vous puissiez mieux comprendre ce sujet avant de commencer à travailler dessus.

Dans cette leçon, nous commencerons par définir une interface de service Web dans un document WSDL. Nous allons apprendre à utiliser CXF pour créer à la fois des applications serveur et client en commençant par WSDL. Nous allons garder l'application simple pour maintenir l'accent sur l'utilisation de CXF. Une fois l'application serveur créée, nous la publierons sur l'URL souhaitée à l'aide d'une classe CXF intégrée.

Tout d'abord, décrivons le WSDL que nous allons utiliser.

WSDL pour HelloWorld

Le webservice que nous allons implémenter aura une seule méthode web appelée greetings qui accepte un stringparamètre contenant le nom d'utilisateur et renvoie un message sous forme de chaîne à l'appelant après avoir ajouté un message d'accueil au nom d'utilisateur. Le wsdl complet est montré ci-dessous -

//Hello.wsdl
<?xml version = "1.0" encoding = "UTF-8"?>
<wsdl:definitions xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns = "http://helloworld.tutorialspoint.com/"
   xmlns:wsdl = "http://schemas.xmlsoap.org/wsdl/"
   xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
   name = "HelloWorld"
   targetNamespace = "http://helloworld.tutorialspoint.com/">
   <wsdl:types>
      <xsd:schema attributeFormDefault = "unqualified"
         elementFormDefault = "qualified"
         targetNamespace = "http://helloworld.tutorialspoint.com/">
         <xsd:element name = "greetings" type = "tns:greetings"/>
         <xsd:complexType name = "greetings">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "arg0" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
         <xsd:element name = "greetingsResponse"
         type = "tns:greetingsResponse"/>
         <xsd:complexType name = "greetingsResponse">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "return" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
      </xsd:schema>
   </wsdl:types>
   <wsdl:message name = "greetings">
      <wsdl:part element = "tns:greetings" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:message name = "greetingsResponse">
      <wsdl:part element = "tns:greetingsResponse" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:portType name = "HelloWorldPortType">
      <wsdl:operation name = "greetings">
         <wsdl:input message = "tns:greetings" name = "greetings">  </wsdl:input>
         <wsdl:output message = "tns:greetingsResponse" name = "greetingsResponse">
         </wsdl:output>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name = "HelloWorldSoapBinding" type = "tns:HelloWorldPortType">
      <soap:binding style = "document"
      transport = "http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name = "greetings">
         <soap:operation soapAction = "" style = "document"/>
         <wsdl:input name = "greetings"></wsdl:input>
         <wsdl:output name = "greetingsResponse">
            <soap:body use = "literal"/>
         </wsdl:output>
         </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name = "HelloWorldService">
      <wsdl:port binding = "tns:HelloWorldSoapBinding" name = "HelloWorldPort">
         <soap:address location = "http://localhost:9090/HelloServerPort"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

Notez que l'écriture d'un wsdl syntaxiquement correct a toujours été un défi pour les développeurs; il existe de nombreux outils et des éditeurs en ligne sont disponibles pour créer un wsdl. Ces éditeurs demandent les noms des messages que vous souhaitez implémenter ainsi que les paramètres que vous souhaitez passer dans un message et le type de message de retour que vous souhaitez que votre application cliente reçoive. Si vous connaissez la syntaxe wsdl, vous pouvez coder manuellement l'intégralité du document ou utiliser l'un des éditeurs pour créer le vôtre.

Dans le wsdl ci-dessus, nous avons défini un seul message appelé greetings. Le message est remis au service appeléHelloWorldService qui court à http://localhost:9090/HelloServerPort.

Avec cela, nous allons maintenant passer au développement du serveur. Avant de développer le serveur, nous devons générer une interface Apache CXF avec notre service Web. Cela doit être fait à partir du wsdl donné. Pour ce faire, vous utilisez un outil appeléwsdl2java.

Le plugin wsdl2java

Comme nous utiliserons maven pour construire le projet, vous devrez ajouter le plugin suivant au pom.xml fichier.

<plugins>
   <plugin>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-codegen-plugin</artifactId>
      <version>3.3.0</version>
      <executions>
         <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
               <wsdlOptions>
                  <wsdlOption>
                     <wsdl>src/main/resources/hello.wsdl</wsdl>
                     <faultSerialVersionUID> 1 </faultSerialVersionUID>
                  </wsdlOption>
               </wsdlOptions>
            </configuration>
            <goals>
               <goal>wsdl2java</goal>
            </goals>
         </execution>
      </executions>
   </plugin>
</plugins>

Notez que nous spécifions l'emplacement du wsdl classer comme src/main/resources/Hello.wsdl. Vous devrez vous assurer que vous créez une structure de répertoires appropriée pour votre projet et ajoutez lehello.wsdl fichier dans le dossier spécifié.

le wsdl2javaplugin compilera ce wsdl et créera des classes Apache CXF dans un dossier prédéfini. La structure complète du projet est présentée ici pour votre référence.

Vous êtes maintenant prêt à créer un serveur en utilisant le wsdl2javaclasses générées. Les classes créées par wsdl2java sont illustrées dans la figure ci-dessous -

Interface de service générée

Dans la liste des classes générées, vous devez avoir remarqué que l'une d'elles est une interface Apache CXF - c'est HelloWorldPortType.java. Examinez ce fichier dans votre éditeur de code. Le contenu du fichier est affiché ici pour votre référence prête -

//HelloWorldPortType.java
package com.tutorialspoint.helloworld;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
/**
* This class was generated by Apache CXF 3.3.0
* 2019-02-11T12:05:55.220+05:30
* Generated source version: 3.3.0
*
*/

@WebService(targetNamespace = "http://helloworld.tutorialspoint.com/",
   name = "HelloWorldPortType")
@XmlSeeAlso({ObjectFactory.class})
public interface HelloWorldPortType {
   @WebMethod
   @RequestWrapper(localName = "greetings", targetNamespace =
      "http://helloworld.tutorialspoint.com/", className =
      "com.tutorialspoint.helloworld.Greetings")
      @ResponseWrapper(localName = "greetingsResponse", targetNamespace =
         "http://helloworld.tutorialspoint.com/", className =
         "com.tutorialspoint.helloworld.GreetingsResponse")
   @WebResult(name = "return", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
   public java.lang.String greetings(
      @WebParam(name = "arg0", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
      java.lang.String arg0
   );
}

Notez que l'interface contient une méthode appelée greetings. C'était un type de message dans notre wsdl. lewsdl2javatool a ajouté cette méthode à l'interface générée. Maintenant, vous pouvez comprendre que quels que soient les messages que vous écrivez dans votre wsdl, une méthode correspondante serait générée dans l'interface.

Maintenant, votre tâche serait d'implémenter toutes ces méthodes correspondant aux différents messages que vous avez définis dans votre wsdl. Notez que dans l'exemple précédent d'Apache CXF-First, nous avons commencé avec une interface Apache CXF pour notre service Web. Dans ce cas, l'interface Apache CXF est créée à partir de wsdl.

Implémentation de l'interface de service

L'implémentation de l'interface de service est triviale. La mise en œuvre complète est indiquée dans la liste ci-dessous -

//HelloWorldImpl.java
package com.tutorialspoint.helloworld;
public class HelloWorldImpl implements HelloWorldPortType {
   @Override
   public String greetings(String name) {
      return ("hi " + name);
   }
}

Le code implémente la méthode d'interface unique appelée greetings. La méthode prend un paramètre destring type, y ajoute un message "salut" et renvoie la chaîne résultante à l'appelant.

Ensuite, nous écrirons l'application serveur.

Développement du serveur

Le développement d'une application serveur est une fois de plus trivial. Ici, nous utiliserons le CXF fourniEndpointclasse pour publier notre service. Cela se fait dans les deux lignes de code suivantes -

HelloWorldPortType implementor = new HelloWorldImpl();
   Endpoint.publish("http://localhost:9090/HelloServerPort",
      implementor,
      new LoggingFeature());

Tout d'abord, nous créons un objet de notre classe d'implémenteur de service - HelloWorldImpl. Ensuite, nous passons cette référence en tant que deuxième paramètre aupublishméthode. Le premier paramètre est l'adresse à laquelle le service est publié - les clients utiliseraient cette URL pour accéder au service. La source complète de l'application serveur est donnée ici -

//Server.java
package com.tutorialspoint.helloworld;
import javax.xml.ws.Endpoint;
import org.apache.cxf.ext.logging.LoggingFeature;
public class Server {
   public static void main(String[] args) throws Exception {
      HelloWorldPortType implementor = new HelloWorldImpl();
      Endpoint.publish("http://localhost:9090/HelloServerPort",
         implementor,
         new LoggingFeature());
      System.out.println("Server ready...");
      Thread.sleep(5 * 60 * 1000);
      System.out.println("Server exiting");
      System.exit(0);
   }
}

Pour créer cette classe de serveur, vous devrez ajouter un profil de construction dans votre pom.xml. Ceci est montré ci-dessous -

<profile>
   <id>server</id>
   <build>
      <defaultGoal>test</defaultGoal>
      <plugins>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.6.0</version>
            <executions>
               <execution>
                  <phase>test</phase>
                  <goals>
                     <goal>java</goal>
                  </goals>
                  <configuration>
                     <mainClass>
                        com.tutorialspoint.helloworld.Server
                     </mainClass>
                  </configuration>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</profile>

Notez que le nom complet du Serverclass est spécifié dans la configuration. En outre, la balise de dépendance spécifie que nous utiliserons le serveur Web de jetée intégré pour déployer notre application serveur.

Déploiement du serveur

Enfin, pour déployer l'application serveur, vous devrez effectuer une autre modification dans pom.xml pour configurer votre application en tant qu'application Web. Le code que vous devez ajouter à votrepom.xml est donné ci-dessous -

<defaultGoal>install</defaultGoal>
<pluginManagement>
   <plugins>
      <plugin>
         <artifactId>maven-war-plugin</artifactId>
         <version>3.2.2</version>
         <configuration>
            <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
            <webResources>
               <resource>
                  <directory>src/main/resources</directory>
                  <targetPath>WEB-INF</targetPath>
                  <includes>
                     <include>*.wsdl</include>
                  </includes>
               </resource>
            </webResources>
         </configuration>
      </plugin>
   </plugins>
</pluginManagement>

Avant de déployer l'application, vous devez ajouter deux fichiers supplémentaires à votre projet. Ceux-ci sont indiqués dans la capture d'écran ci-dessous -

Ces fichiers sont des fichiers standard CXF qui définissent le mappage pour CXFServlet. Le code dans leweb.xml Le fichier est affiché ici pour votre référence rapide -

//cxf-servlet.xml
<web-app xmlns = "http://java.sun.com/xml/ns/javaee"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" version="2.5"
   xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <display-name>cxf</display-name>
   <servlet>
      <description>Apache CXF Endpoint</description>
      <display-name>cxf</display-name>
      <servlet-name>cxf</servlet-name>
      <servlet-class>
         org.apache.cxf.transport.servlet.CXFServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>cxf</servlet-name>
      <url-pattern>/services/*</url-pattern>
   </servlet-mapping>
   <session-config>
      <session-timeout>60</session-timeout>
   </session-config>
</web-app>

dans le cxf-servlet.xmlvous déclarez les propriétés du point de terminaison de votre service. Ceci est montré dans l'extrait de code ci-dessous -

<beans ...>
   <jaxws:endpoint xmlns:helloworld = "http://tutorialspoint.com/"
      id="helloHTTP"
      address = "http://localhost:9090/HelloServerPort"
      serviceName = "helloworld:HelloServiceService"
      endpointName = "helloworld:HelloServicePort">
   </jaxws:endpoint>
</beans>

Ici, nous définissons l'id de notre point de terminaison de service, l'adresse sur laquelle le service sera disponible, le nom du service et le nom du point de terminaison. Vous comprenez maintenant comment votre service est acheminé et traité par un servlet CXF.

Le pom.xml final

le pom.xmlinclut quelques dépendances supplémentaires. Plutôt que de décrire toutes les dépendances, nous avons inclus la version finale de pom.xml ci-dessous -

<?xml version="1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>cxf-wsdl</artifactId>
   <version>1.0</version>
   <packaging>jar</packaging>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
   </properties>
   <build>
      <defaultGoal>install</defaultGoal>
      <pluginManagement>
         <plugins>
            <plugin>
               <artifactId>maven-war-plugin</artifactId>
               <version>3.2.2</version>
               <configuration>
                  <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
                  <webResources>
                     <resource>
                        <directory>src/main/resources</directory>
                        <targetPath>WEB-INF</targetPath>
                        <includes>
                           <include>*.wsdl</include>
                        </includes>
                     </resource>
                  </webResources>
               </configuration>
            </plugin>
         </plugins>
      </pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-codegen-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
               <execution>
                  <id>generate-sources</id>
                  <phase>generate-sources</phase>
                  <configuration>
                     <wsdlOptions>
                        <wsdlOption>
                           <wsdl>src/main/resources/Hello.wsdl</wsdl>
                           <faultSerialVersionUID>1</faultSerialVersionUID>
                        </wsdlOption>
                     </wsdlOptions>
                  </configuration>
                  <goals>
                     <goal>wsdl2java</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <profiles>
      <profile>
         <id>server</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <version>1.6.0</version>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.tutorialspoint.helloworld.Server
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
         <dependencies>
            <dependency>
               <groupId>org.apache.cxf</groupId>
               <artifactId>cxf-rt-transports-http-jetty</artifactId>
               <version>3.3.0</version>
            </dependency>
         </dependencies>
      </profile>
      <profile>
         <id>client</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.tutorialspoint.helloworld.Client
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-frontend-jaxws</artifactId>
         <version>3.3.0</version>
      </dependency>
     
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-management</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-metrics</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf.xjc-utils</groupId>
         <artifactId>cxf-xjc-runtime</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-logging</artifactId>
         <version>3.3.0</version>
      </dependency>
     
     <dependency>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>exec-maven-plugin</artifactId>
         <version>1.6.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.8.0-beta2</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</project>

Notez qu'il comprend également un profil pour la création de clients que nous apprendrons bientôt dans les sections suivantes.

Exécution du service HelloWorld

Vous êtes maintenant prêt à exécuter l'application Web. Dans la fenêtre de commande, exécutez le script de construction à l'aide de la commande suivante.

mvn clean install

Cela générera les classes Apache CXF appropriées à partir de votre wsdl, compilera vos classes Apache CXF, déploiera le serveur sur le serveur de jetée intégré et exécutera votre application.

Vous verrez le message suivant sur la console -

INFO: Setting the server's publish address to be 
http://localhost:9090/HelloServerPort
Server ready...

Comme précédemment, vous pouvez tester le serveur en ouvrant l'URL du serveur dans votre navigateur.

Comme nous n'avons précisé aucune opération, seul un message d'erreur est renvoyé au navigateur par notre application. Maintenant, essayez d'ajouter le?wsdl à votre URL et vous verrez la sortie suivante -

Notre application serveur fonctionne donc comme prévu. Vous pouvez utiliser le client SOAP tel quePostman décrit précédemment pour tester davantage votre service.

La prochaine partie de ce tutoriel consiste à écrire un client qui utilise notre service.

Client en développement

L'écriture du client dans une application CXF est aussi importante que l'écriture d'un serveur. Voici le code complet pour le client qui se compose essentiellement de seulement trois lignes, le reste des lignes imprimant simplement les informations de service à l'utilisateur.

//Client.java
package com.tutorialspoint.helloworld;
public class Client {
   public static void main(String[] args) throws Exception {
      //Create the service client with its default wsdlurl
      HelloWorldService helloServiceService = new HelloWorldService();
      System.out.println("service: " +
         helloServiceService.getServiceName());
      System.out.println("wsdl location: " +
         helloServiceService.getWSDLDocumentLocation());
      HelloWorldPortType helloService =
         helloServiceService.getHelloWorldPort();
      System.out.println(helloService.greetings
      (System.getProperty("user.name")));
   }
}

Ici, nous créons simplement une instance de notre service HelloWorldService, récupérez son port en appelant getHelloWorldPort méthode, puis passez notre greetingsmessage à lui. Exécutez le client et vous verrez la sortie suivante -

service: {http://helloworld.tutorialspoint.com/}HelloWorldService
wsdl location: file:/Users/drsarang/Desktop/tutorialpoint/cxf-
wsdl/src/main/resources/Hello.wsdl
hi drsarang

Jusqu'à présent, vous avez appris à utiliser CXF avec les architectures Apache CXF-First et WSDL-First. Dans l'approche Apache CXF-First, vous avez utilisé un POJO avecServerFactoryBeanclasse des bibliothèques CXF pour créer un serveur. Pour créer un client que vous avez utiliséClientProxyFactoryBeanclasse de la bibliothèque CXF. Dans l'approche WSDL-First, vous avez utiliséEndpointclasse pour publier le service à l'URL souhaitée et à un implémenteur spécifié. Vous pouvez désormais étendre ces techniques pour intégrer différents protocoles et transports.