Apache CXF con WSDL primero

La aplicación CXF-POJO que ha desarrollado da como resultado un acoplamiento muy estrecho entre el cliente y el servidor. Dar acceso directo a la interfaz de servicio también puede plantear graves amenazas a la seguridad. Por lo tanto, generalmente se desea el desacoplamiento entre el cliente y el servidor, lo que se logra utilizando WSDL (Lenguaje de descripción de servicios web).

Escribimos la interfaz del servicio web en un documento WSDL que está basado en XML. Usaremos una herramienta para mapear este WSDL a las interfaces Apache CXF que luego son implementadas y utilizadas por nuestras aplicaciones cliente y servidor. Para proporcionar desacoplamiento, comenzar con un WSDL es una forma preferida. Para ello, primero debe aprender un nuevo idioma: WSDL. Escribir WSDL necesita un enfoque cuidadoso y sería mejor si pudiera comprender esto antes de comenzar a trabajar en él.

En esta lección, comenzaremos definiendo una interfaz de servicio web en un documento WSDL. Aprenderemos a usar CXF para crear aplicaciones tanto de servidor como de cliente comenzando con WSDL. Mantendremos la aplicación simple para mantener el enfoque en el uso de CXF. Una vez creada la aplicación del servidor, la publicaremos en la URL deseada utilizando una clase CXF incorporada.

Primero, describamos el WSDL que vamos a utilizar.

WSDL para HelloWorld

El servicio web que vamos a implementar tendrá un único método web llamado greetings que acepta un stringparámetro que contiene el nombre de usuario y devuelve un mensaje de cadena a la persona que llama después de agregar un mensaje de saludo al nombre de usuario. El wsdl completo se muestra a continuación:

//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>

Tenga en cuenta que escribir un wsdl sintácticamente correcto siempre ha sido un desafío para los desarrolladores; hay muchas herramientas y editores en línea disponibles para crear un wsdl. Estos editores solicitan los nombres de los mensajes que desea implementar junto con los parámetros que desea pasar en un mensaje y el tipo de mensaje de retorno que desea que reciba su aplicación cliente. Si conoce la sintaxis de wsdl, puede codificar manualmente todo el documento o usar uno de los editores para crear el suyo.

En el wsdl anterior, hemos definido un solo mensaje llamado greetings. El mensaje se entrega al servicio llamadoHelloWorldService que se está ejecutando en http://localhost:9090/HelloServerPort.

Con esto, ahora procederemos al desarrollo del servidor. Antes de desarrollar el servidor, necesitamos generar la interfaz Apache CXF para nuestro servicio web. Esto se debe hacer desde el wsdl dado. Para hacer esto, usa una herramienta llamadawsdl2java.

El complemento wsdl2java

Como usaremos maven para construir el proyecto, necesitará agregar el siguiente complemento al pom.xml archivo.

<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>

Tenga en cuenta que especificamos la ubicación del wsdl archivar como src/main/resources/Hello.wsdl. Tendrá que asegurarse de crear una estructura de directorio adecuada para su proyecto y agregar lo que se muestra anteriormente.hello.wsdl archivo a la carpeta especificada.

los wsdl2javaEl complemento compilará este wsdl y creará clases Apache CXF en una carpeta predefinida. La estructura completa del proyecto se muestra aquí para su referencia inmediata.

Ahora, está listo para crear un servidor usando el wsdl2javaclases generadas. Las clases que ha creado wsdl2java se muestran en la siguiente figura:

Interfaz de servicio generada

En la lista de clases generadas, debe haber notado que una de ellas es una interfaz Apache CXF; esto es HelloWorldPortType.java. Examine este archivo en su editor de código. El contenido del archivo se muestra aquí para su referencia inmediata:

//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
   );
}

Tenga en cuenta que la interfaz contiene un método llamado greetings. Este fue un tipo de mensaje en nuestro wsdl. loswsdl2javaLa herramienta ha agregado este método a la interfaz generada. Ahora, puede comprender que cualquier mensaje que escriba en su wsdl, se generará un método correspondiente en la interfaz.

Ahora, su tarea sería implementar todos estos métodos correspondientes a los diversos mensajes que ha definido en su wsdl. Tenga en cuenta que en el ejemplo anterior de Apache CXF-First, comenzamos con una interfaz Apache CXF para nuestro servicio web. En este caso, la interfaz Apache CXF se crea a partir de wsdl.

Implementación de la interfaz de servicio

La implementación de la interfaz de servicio es trivial. La implementación completa se muestra en la lista a continuación:

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

El código implementa el único método de interfaz llamado greetings. El método toma un parámetro destring type, antepone un mensaje "hola" y devuelve la cadena resultante a la persona que llama.

A continuación, escribiremos la aplicación del servidor.

Servidor de desarrollo

Desarrollar una aplicación de servidor es una vez más trivial. Aquí, usaremos el CXF suministradoEndpointclase para publicar nuestro servicio. Esto se hace en las siguientes dos líneas de código:

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

Primero, creamos un objeto de nuestra clase de implementador de servicios: HelloWorldImpl. Luego, pasamos esta referencia como un segundo parámetro alpublishmétodo. El primer parámetro es la dirección en la que se publica el servicio; los clientes usarían esta URL para acceder al servicio. Aquí se proporciona la fuente completa de la aplicación del servidor:

//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);
   }
}

Para construir esta clase de servidor, necesitará agregar un perfil de compilación en su pom.xml. Esto se muestra a continuación:

<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>

Tenga en cuenta que el nombre completo del ServerLa clase se especifica en la configuración. Además, la etiqueta de dependencia especifica que usaremos el servidor web embarcadero integrado para implementar nuestra aplicación de servidor.

Implementación del servidor

Finalmente, para implementar la aplicación del servidor, deberá realizar una modificación más en pom.xml para configurar su aplicación como una aplicación web. El código que necesita agregar a supom.xml se da a continuación -

<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>

Antes de implementar la aplicación, debe agregar dos archivos más a su proyecto. Estos se muestran en la captura de pantalla a continuación:

Estos archivos son archivos estándar CXF que definen la asignación para CXFServlet. El código dentro delweb.xml El archivo se muestra aquí para su referencia rápida -

//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>

En el cxf-servlet.xmldeclara las propiedades para el punto final de su servicio. Esto se muestra en el fragmento de código a continuación:

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

Aquí definimos la identificación de nuestro punto final de servicio, la dirección en la que estará disponible el servicio, el nombre del servicio y el nombre del punto final. Ahora, comprende cómo un servlet CXF enruta y procesa su servicio.

El pom.xml final

los pom.xmlincluye algunas dependencias más. En lugar de describir todas las dependencias, hemos incluido la versión final de pom.xml a continuación:

<?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>

Tenga en cuenta que también incluye un perfil para crear clientes que pronto aprenderemos en las secciones posteriores.

Ejecución del servicio HelloWorld

Ahora, está listo para ejecutar la aplicación web. En la ventana de comandos, ejecute el script de compilación con el siguiente comando.

mvn clean install

Esto generará las clases Apache CXF apropiadas desde su wsdl, compilará sus clases Apache CXF, implementará el servidor en el servidor embarcadero integrado y ejecutará su aplicación.

Verá el siguiente mensaje en la consola:

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

Como antes, puede probar el servidor abriendo la URL del servidor en su navegador.

Como no especificamos ninguna operación, nuestra aplicación solo devuelve un mensaje de error al navegador. Ahora, intente agregar el?wsdl a su URL y verá el siguiente resultado:

Entonces, nuestra aplicación de servidor se está ejecutando como se esperaba. Puede utilizar el cliente SOAP comoPostman descrito anteriormente para probar más su servicio.

La siguiente parte de este tutorial es escribir un cliente que utilice nuestro servicio.

Cliente en desarrollo

Escribir el cliente en una aplicación CXF es tan importante como escribir un servidor. Aquí está el código completo para el cliente que esencialmente consta de solo tres líneas, el resto de las líneas solo imprime la información del servicio para el usuario.

//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")));
   }
}

Aquí, simplemente creamos una instancia de nuestro servicio. HelloWorldService, consigue su puerto llamando getHelloWorldPort método, y luego pasar nuestro greetingsmensaje a él. Ejecute el cliente y verá el siguiente resultado:

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

Hasta ahora, ha aprendido a utilizar CXF con las arquitecturas Apache CXF-First y WSDL-First. En el enfoque Apache CXF-First, usó un POJO conServerFactoryBeanclass de las bibliotecas CXF para crear un servidor. Para crear un cliente que usasteClientProxyFactoryBeanclase de la biblioteca CXF. En el enfoque WSDL-First, usóEndpointclass para publicar el servicio en la URL deseada y un implementador especificado. Ahora puede ampliar estas técnicas para integrar diferentes protocolos y transportes.