En un post anterior vimos como
crear servicios web con Spring-WS, en esta ocación vamos a crear un cliente que consume ese servicio, usando Spring, JAX-WS y JAXB.
Spring-WS provee una API para Web service del lado del cliente que nos da acceso conducido por XML y tambien nos permite en la capa de servicios tratar directamente con objetos Java mediante el uso de marshallers y unmarshallers.
El paquete
org.springframework.ws.client.core provee las funcionalidades del nucleo para usar la API mencionada. Esta contiene las clases template que simplifican el uso de Web services, para ver mas información de webServiceTemplate puedes leer la documentacion de Spring
1. Creando la estructura de la aplicación
Al final nuestra aplicación tendrá la siguiente estructura, donde las clases contenidas en el paquete
com.codelious.clientejaxb.generados serán generadas automaticamente por la herramienta
wsimport.
2. Incluyendo las dependencias
El archivo
pom.xml de este proyecto incluye las siguientes dependencias.
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.1.1.RELEASE</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.10</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
3. Generando los artefactos JAX-WS
Para generar los artefactos JAX-WS automaticamente debemos conocer la url del WSDL que en nuestro caso es http://localhost:18080/MiWS/services/saludar.wsdl y utilizaremos la herramienta
wsimport que debería estar incluida en la instalacion de java, por tanto en una consola de comandos escribimos...
wsimport -d midirectorio -keep http://localhost:18080/MiWS/services/saludar.wsdl
Con lo anterior se generarán automaticamente varios archivos en el directorio indicado, de los cuales debemos copiar solo los
.java a nuestro paquete
com.codelious.clientejaxb.generados
- ObjectFactory.java
- package-info.java
- Saludar.java
- SaludarService.java
- SaludoRequest.java
- SaludoResponse.java
Una vez copiados los archivos anteriores, debemos asegurarnos de que hagan referencia al paquete correcto de nuestro proyecto, por ejemplo
package com.codelious.clientejaxb.generados; dado que por lo general la herramienta wsimport creará como paquete el directorio que le indicamos y este no siempre es el mismo de nuestra aplicación.
Para mas información acerca de wsimpot puedes ver la
documentacion oficial de oracle
4. Escribiendo el Controlador
Ahora escribamos la clase
SaludoController.java con el metodo saludo() que se encargará de consumir el web service
package com.codelious.clientejaxb.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.ws.client.core.WebServiceTemplate;
import com.codelious.clientejaxb.generados.SaludoRequest;
import com.codelious.clientejaxb.generados.SaludoResponse;
@Controller
public class SaludoController {
@Autowired
@Qualifier("webServiceTemplate")
private WebServiceTemplate webServiceTemplate;
@RequestMapping("/saludo")
public ModelAndView saludo() {
// crear solicitud al ws
SaludoRequest solicitud = new SaludoRequest();
solicitud.setNombre("Mario Espinoza Aguayo");
// obtener la respuesta
SaludoResponse respuesta = (SaludoResponse) webServiceTemplate.marshalSendAndReceive(solicitud);
// obtiene el saludo
String mensaje = respuesta.getSaludo();
return new ModelAndView("saludo", "mensaje", mensaje);
}
}
Como se ve arriba, estamos instanciando un
webServiceTemplate,
SaludoRequest y
SaludoResponse que en conjunto nos ayudan a simplificar las tareas de transformación de xml a objetos java. webServiceTemplate está inyectado por el bean de su mismo nombre desde el archivo
spring-ws.xml que veremos luego...
5. Escribiendo la vista Saludo
La vista
saludo.jsp simplemente desplegará en el navegador el mensaje devuelto por el controlador...
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cliente WS</title>
</head>
<body>
<h1>${mensaje}</h1>
</body>
</html>
6. Escribiendo la página de entrada
La pagina de entrada a la aplicación
index.jsp contiene el link que llama al controlador saludo...
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cliente WS</title>
</head>
<body>
<h1>Bienvenido al ClienteWS</h1>
<p>
Presiona el link para ver el <a href="saludo.html">saludo</a>
</p>
</body>
</html>
7. Configurando la aplicación
Para configurar la aplicación escribiremos varios archivos xml...
por convención Spring buscará el archivo
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- Escanea el classpath para componentes anotados que seran auto-registrados como beans de Spring.
For ejemplo @Controller y @Service. Asegurate de establecer el base-package correcto -->
<context:component-scan
base-package="com.codelious.clientejaxb.controller" />
<!-- Activa varias anotaciones para ser detectadas en las clases bean -->
<context:annotation-config />
<!-- Configura el modelo de programacion annotation-driven de Spring MVC Controller.
Nota que, con Spring 3.0, este tag trabaja en Servlet MVC solamente! -->
<mvc:annotation-driven />
<!-- Contiene configuraciones relacionadas a Spring WS -->
<import resource="spring-ws.xml" />
</beans>
Nuestro archivo
spring-ws.xml contendrá el bean webServiceTemplate que inyectamos anteriormente en nuestro controlador...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services
http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd">
<!-- * El WebServiceTemplate requiere un messageSender y messageFactory
* Para facilitar el envio de plain Java objects, el WebServiceTemplate
requiere un marshaller y unmarshaller.
* La clase WebServiceTemplate usa una URI como el destinatario del mensaje.
Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"
p:marshaller-ref="jaxbMarshaller" p:unmarshaller-ref="jaxbMarshaller"
p:defaultUri="http://localhost:18080/MiWS/services"
p:messageSender-ref="messageSender">
<constructor-arg ref="messageFactory" />
</bean>
<!-- Hay dos implementaciones del WebServiceMessageSender: HttpUrlConnectionMessageSender
y CommonsHttpMessageSender. el CommonsHttpMessageSender provee funcionalidades avanzadas
y faciles de usar (tales como authentication, HTTP connection pooling, y asi sucesivamente).
Esta usa el Jakarta Commons HttpClient.
Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
<bean id="messageSender"
class="org.springframework.ws.transport.http.CommonsHttpMessageSender" />
<!-- Hay dos message factories para SOAP: SaajSoapMessageFactory y AxiomSoapMessageFactory.
Si no se especifica ningun message factory (via la propiedad messageFactory), Spring-WS usara
el SaajSoapMessageFactory por defecto.
Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
<!-- Aqui usamos el Jaxb2 marshaller para marshall y unmarshal nuestros objetos Java -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
p:contextPath="com.codelious.clientejaxb.generados" />
</beans>
El archivo
spring-servlet.xml como siempre es nuestro dispatcher servlet, es decir que es el encargado de despachar solicitudes a controladores y luce asi...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Finalmente nuestro archivo
web.xml es donde definimos nuestro archivo de entrada a la aplicación, y nuestros dispatcher servlet...
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>ClienteWS JAX-WS JAXB</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
8. Probando la aplicación
Ya podemos probar nuestra aplicación en http://localhost:18080/ClienteJAXB/ y ver la página de entrada...
Al hacer clic al link llamaremos al controlador que consume el web service y devuelve el mensaje...
Ya esta!! si quieres el codigo descargalo en github..
https://github.com/codelious/ClienteJAXB