Spring WS: Creación de Servicios Web con Spring

8
40086

Spring WS: Creación de Servicios Web con Spring

En el siguiente tutorial vamos a ver algunas de las aportaciones que nos ofrece Spring en relación a la construcción de Servicios Web.

Se presupone que el lector ya posee conocimientos de Servicios Web, Maven y Spring.

Indice de contenido:

  1. Introducción.
  2. Ejemplo de construcción de un Servicio Web con Spring.
    1. Entorno.
    2. Estructura del proyecto.
    3. Describiendo la petición al servicio web.
    4. Describiendo la respuesta del servicio web.
    5. Código fuente de las clases que componen el servicio Web.
    6. Archivo de configuración de Log4J: /WEB-ING/log4j.xml.
    7. Archivo de configuración de Spring 2 (\WEB-INF\bibliotecaWS-servlet.xml).
    8. Archivo de configuración y despliegue de la aplicación (/WEB-INF/web.xml).
    9. Archivo de configuración de Maven 2: pom.xml.
    10. Construcción y despliegue la aplicación.
  3. Ejemplo de construcción de un cliente (Axis2) para probar el servicio web.
  4. Ejemplo de construcción de un cliente (con Spring) para probar el servicio web.
  5. Referencias
  6. Conclusiones

Introducción

Todos estaremos de acuerdo en que las aplicaciones actuales no están aisladas, que hay necesidad (y deben) interoperar para resolver los problemas, es más, incluso aunque ahora no sea necesario, se debe diseñar una solución para que en caso de necesidad el impacto sea mínimo.

Un problema debería ser resuelto una vez y ser reutilizado por el resto de sistemas (con independencia de lenguajes de programación y arquitecturas) sin tener que volver que resolver el mismo problema implementando una y otra vez lo mismo en cada nueva aplicación…. (SOA).

En este tutorial vamos a ver un ejemplo de construcción de un servicio web usando el modelo contrato primero (Spring apuesta por este modelo).
Desde mi punto de vista la mejor forma de implementar un servicio Web, cuando de verdad se desea interoperabilidad… no quiero entrar en este tema si os interesa, podéis leer la siguientes webs que explican por que es mejor el modelo contrato primero frente a partir de una interfaz de programación:

Para terminar la introducción decir que Spring también tiene mucho que aportar en relación a otras técnicas de comunicación remota: RMI, Hessian y Burlap, HTTPInvoker. Pero se salen del ámbito de este tutorial.

Ejemplo de construcción de un Servicio Web con Spring:

A continuación vamos a ver un completo ejemplo en donde construiremos un Servicio Web que representa al motor de búsqueda de libros de una biblioteca. Las aplicaciones preguntarán sobre libros de una determinada categoría y nivel y el servicio devolverá aquellos libros disponibles que cumplen esos criterios de búsqueda.

Entorno

El siguiente ejemplo está construido en el siguiente entorno:

  • HP Pavilion.
  • Windows Vista Home Premium.
  • Eclipse Ganymede.
  • Java 6.
  • Maven 2.
  • Plugin Maven 4QE para Eclipse.

Estructura del proyecto:

Una de las muchas ventajas de Maven es que estandariza la estructura de los proyectos, es decir, cualquier persona con conocimientos de Maven tendría facilidad de comprender como se estructura y dónde está cada cosa dentro del proyecto.

Si nos fijamos hay un arquetipo Maven 2 para proyectos Spring WS: http://www.mavenrepository.com/artifact/org.springframework.ws/spring-ws-archetype

Yo cree el proyecto con el comando:

mvn archetype:create -DarchetypeGroupId=org.springframework.ws -DarchetypeArtifactId=spring-ws-archetype -DarchetypeVersion=1.5.6 -DgroupId=com.autentia.tutoriales -DartifactId=bibliotecaWS

Vosotros como ya lo tenéis hecho, simplemente tendréis que importarlo desde vuestro IDE favorito. Yo uso Eclipse Ganymede con el plugin Q4E para gestión de proyectos Maven.

Describiendo la petición al servicio web: booksInfoRequest.xml

¿Cómo nos gustaría que fueran los mensajes de solicitud o consulta de libros?… pues, por ejemplo así:

Una categoría y un nivel, en donde el nivel está restringido a ser: básico o medio o avanzado

Ahora lo definimos con un XML Schema: booksInfoRequest.xsd

¿Qué nó sabes hacerlo o no te apetece?, pues mira esté tutorial: Ver tutorial.

Describiendo la respuesta del servicio web: booksInfoResponse.xml

¿Cómo nos gustaría que fueran los mensajes de respuesta?… pues, por ejemplo así (con N libros):

N libros en donde cada uno está definido por una editorial, un título (ambos texto libre), un número de páginas y un precio (ambos números positivos).

Ahora lo definimos con un XML Schema: booksInfoResponse.xsd

Definir el Web Service: /WEB-INF/bibliotecaWS.xsd

Sencillo, unimos los XML Schema anteriores y el resto lo configuramos en Spring. Es decir, se podría decir que en conjunto es como el WSDL del servicio Web, es más, de hecho se generará automáticamente.

Código fuente de las clases que componen el servicio Web.

A continuación iremos viendo las clases que componen el proyecto.

NOTA: Lo voy a hacer a mano, pero las clases Libro, BookInfoRequest y BookInfoResponse podrían de muchas formas ser generadas automáticamente desde los XSD.
Por ejemplo, en el siguiente enlace http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=xmlBeans mi compañero Alejandro García os explica una de ellas.

com.autentia.tutoriales.spring.ws.entity.Libro:

com.autentia.tutoriales.spring.ws.entity.BooksInfoRequest:

com.autentia.tutoriales.spring.ws.entity.BooksInfoResponse:

com.autentia.tutoriales.spring.ws.IRequestProcessor:

Cuando el servicio web reciba una petición, la lógica de negorio real de tratamiento
de la misma será realizada por alguna clase que implemente esta interfaz.

com.autentia.tutoriales.spring.ws.DummyRequestProcessor:

Implementación sencilla de la interfaz IRequestProcessor para este este ejemplo.

com.autentia.tutoriales.spring.ws.BookInfoEndPoint:

EndPoint del WS, recibe las peticiones de consulta de libros (peticiones XML), las convierte en objetos
y delega su procesamiento a un IRequestProcessor.

Yo he elegido hacerlo con DOM (mensajes completos en memoria…), pero hay otras muchas implementaciones que nos permiten implementarlo con Stax, SAX, JDOM…
Simplemente deberemos leer, procesar y constuir en base a DOM los XML.

Archivo de configuración de Log4J: /WEB-ING/log4j.xml:

A continuación exponemos el archivo de configuración de Log4J. Los mensajes con nivel WARN o superior irán a parar a un archivo y el resto (de cualquier nivel DEBUG, INFO, etc.) a otro.

Archivo de configuración de Spring 2 (\WEB-INF\bibliotecaWS-servlet.xml):

Atención, el nombre del archivo es importante, debe ser igual que el nombre del servlet que verémos más adelante y luego «-servlet.xml».

El archivo está autocomentado.

Archivo de configuración y despliegue de la aplicación (/WEB-INF/web.xml):

Las peticiones SOAP serán atendidas por el servlet org.springframework.ws.transport.http.MessageDispatcherServlet

Archivo de configuración de Maven 2: pom.xml:

A continuación exponemos el archivo de configuración de Maven, se presupone que el lector ya tiene nociones de Maven.

Construcción y despliegue la aplicación:

A continuación ejecutamos el siguiente comando Maven: mvn package y desplegamos el archivo generado target\bibliotecaWS-1.0-SNAPSHOT.war en
nuestro servidor preferido (JBoss, Tomcat, WebLogic, WebSphere, Jetty, etc..).

Ejemplo de construcción de un cliente (Axis2) para probar el servicio web.

Este apartado da por sentado que el usuario ya sabe algo de Axis2, así que no voy a explicar con sumo detalle que es cada cosa (puedes consultar otros tutoriales en http://www.adictosaltrabajo.com de como se instala, configura, etc).

Como dije anteriormente, el servicio Web está desplegado y es capaz de autodescribirse a generando su propio WSDL, pues bien vamos a crear un cliente automáticamente desde su WDSL.

El código fuente de este tutorial puede ser descargado desde aquí (proyecto Eclipse).


%AXIS2_HOME%/bin/wsdl2java -sp -s -p com.autentia.tutoriales.spring.ws.cliente -uri http://localhost:8080/bibliotecaWS/bibliotecaWS.wsdl

En donde:

  • -sp: Por el namespace axis2 por defecto pone un namespace ns1 pero nuestro en el WS el Payload no está qualificado (no tiene namespace). Puedes verlo tu mismo copiando y pegando la URL en tu navegador…
  • -s: No queremos ni necesitamos que nos genere funcionalidad de invocación asíncrona.
  • -p: En que paquete deseamos que nos genere las clases.

Invocando el servicio Web. com.autentia.tutoriales.spring.ws.cliente.BibliotecaWSApp:

Y para terminar, al ejecutar la aplicación anterior, nos produce la siguiente salida:

Ejemplo de construcción de un cliente (con Spring) para probar el servicio web.

Este apartado está descrito en el siguiente tutorial http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=spring_ws_client_example1.

Referencias

Conclusiones

Bueno, como veis Spring no deja de sorprendernos en cuanto a su potencia y ventajas en el desarrollo de software de calidad (bajo acomplamiento, alta cohesión, etc.)

Resaltar que Spring también proporciona mucha funcionalidad para consumir servicios Web (hacer clientes), pero prefiero dejar esto para otro tutorial o para que el lector investige al respecto, haga un tutorial y nos lo mande para que lo publiquemos :-).

Carlos García Pérez. Creador de MobileTest, un complemento educativo para los profesores y sus alumnos.

cgpcosmad@gmail.com

8 Comentarios

  1. Hola, efectivamente me faltaba el espacio de nombres.
    El servicio lo probé con un cliente java y un .Net y con el cliente java no tuve problemas pero con el .net no me reconoce el tipo de retorno y lo que hice fue cambiarle al archivo bibliotecaWS.xsd en la línea 27 ref por type y lo reconoció sin problemas.

  2. Buenas.

    Tengo una aplicación web con spring-mvc que funciona correctamente.
    Ahora querría que la aplicación sirviera unos cuantos métodos de lógica de negocio a través de servicios web.

    He seguido este tutorial al pie de la letra y al arrancar Spring me muestra la siguiente excepción por consola:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name \\\’partidaArancelariaWS\\\’ defined in ServletContext resource [/WEB-INF/partidaArancelariaWS-servlet.xml]: Invocation of init method failed; nested exception is WSDLException: faultCode=CONFIGURATION_ERROR: No Java extensionType found to represent a \\\'{http://schemas.xmlsoap.org/wsdl/soap12/}binding\\\’ element in the context of a \\\’javax.wsdl.Binding\\\’.:

    He descubierto que si en vez de soap 12 utilizo soap 11 arranca correctamente, el problema es que cuando pido la WSDL la consola me muestra el siguiente error:

    Could not complete request
    java.lang.AbstractMethodError: org.apache.xerces.dom.DeferredDocumentImpl.getXmlStandalone()Z
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.setDocumentInfo(DOM2TO.java:373)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(DOM2TO.java:127)

    Mi XSD es igual que la del ejemplo del tutorial.

    ¿Alguién podrá arrojar algo de luz a mi problema?

    MUCHISIMAS GRACIAS¡

  3. He ejecutado correctamente el aplicativo y funciona correctamente.
    En mi caso el web service que he construido solo permitirá que ciertos usuarios puedan consumir el servicio, una forma de restringir el acceso es identificando la IP del equipo que esta solicitando consumir el web service.
    Como identifico de quien consume el servicio. En otras palabras como identifico la IP de la maquina que esta solicitando el servicio.

    Gracias por tu apoyo.

  4. Hola LuigiBuilder

    Por ejemplo podrías hacer que dentro de un javax.servlet.Filter pregunta por la propiedad request.getRemoteAddr() para ver si es una IP válida o no.

    Si no lo lanzas una excepción para que la petición sea anulada, es decir no invocas el chain.doFilter(request, response)

    Saludos

  5. Gracias Carlos,
    Seguí tu sugerencia y logre identificar las IPs permitidas.
    Pero tengo otra duda, como puedo recuperar esa IP desde el mismo webservice para luego grabar en una tabla tanto los datos que enviaron en la consulta como la IP de la maquina que hizo la consulta.

    Gracias por todo.

Dejar respuesta

Please enter your comment!
Please enter your name here