Web services con Spring framework y CXF
Implementar y exponer web services utilizando Spring framework ha sido una tarea recurrente en mi día a día. En este post describiré qué y cómo configurar para tener un web service funcionando con Spring y CXF sobre Tomcat 6.
En este ejemplo tendremos un enfoque code-first, es decir, que definiremos los servicios a exponer en nuestras clases Java, para generar el WSDL a partir de éstas.
Con toda la originialidad del mundo, haremos un Hello world. La intefaz Java del servicio es la siguiente:
package test;
import javax.jws.WebService;
@WebService
public interface SayHello {
String sayHello(String name);
}
Y su implementación:
package test;
import javax.jws.WebService;
@WebService(endpointInterface="test.SayHello")
public class SayHelloImpl implements SayHello {
public String sayHello(String name) {
return "Hello " + name + "!";
}
}
Ya no necesitaremos más código, el resto es configuración. Bajo WEB-INF tenemos un XML de Spring llamado application-config.xml, con el siguiente contenido:
<?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:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <jaxws:endpoint id="sayHello" implementor="test.SayHelloImpl" address="/SayHello"> <jaxws:features> <bean class="org.apache.cxf.feature.LoggingFeature" /> </jaxws:features> </jaxws:endpoint> </beans>
El elemento jaxws:endpoint esconde toda la magia, generando la definición del web service a partir de una clase. También se puede referenciar un bean de spring, poniendo el nombre en el implementor con el formato “#REF_BEAN_NAME”, de la siguiente forma:
<bean id="sayHelloService" class="test.SayHelloImpl" /> <jaxws:endpoint id="sayHello" implementor="#sayHelloService" address="/SayHello"> <jaxws:features> <bean class="org.apache.cxf.feature.LoggingFeature" /> </jaxws:features> </jaxws:endpoint>
WEB-INF/web.xml contiene la configuración para levantar el contexto de Spring y el servlet de CXF
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/application-config.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <display-name>CXF Servlet</display-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
Para el manejo de dependencias utilizaremos Maven, y las dependencias incluídas en el POM del proyecto son las siguientes:
<dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-core</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-simple</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-local</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-common-utilities</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> </dependencies>
Para armar el WAR hacemos “mvn package” en la línea de comandos, posicionados en la raíz del proyecto. Esto generará un archivo target/ws-test.war, el cual copiaremos a la carpeta webapps de Tomcat. Luego de iniciar el tomcat, el WSDL del web service quedará disponible en http://localhost:8080/ws-test/SayHello?wsdl
La estructura final del proyecto es la siguiente:

Estructura del ejemplo
El proyecto de ejemplo se puede bajar de aquí.
Referencias:
http://ralf.schaeftlein.de/2008/05/04/apache-cxf-21-with-spring-2-maven-2-and-eclipse-wtp/
http://cxf.apache.org/
Posts relacionados (generados automáticamente):
- Crear un nuevo proyecto Java con Maven
- Configurar log4j desde beans de Spring Framework
- Catálogos web de artefactos de Maven
- Problemas en Eclipse de proyectos Maven con dependencias a AspectJ
- AOP con Spring framework
- Manejo transaccional de la base de datos con Spring Framework y AOP
- Web services code-first y contract-first (de Lijin’s Localhost)
- Generación del manifest de un JAR utilizando Maven
- Evitar la ejecución de tests o ignorar resultados al utilizar Maven

Hola, gracias por el aporte!
Te hago una pregunta:
Cuando entro a http://localhost:8080/ws-test/SayHello?wsdl, me muestra el wsdl en formato xml:
(
….)
Esta bien que lo vea asi?? o deberia ver un “Hello wsdl!”??
Gracias!
Hola. Si, está perfecto, en esa URL es donde se describen los servicios expuestos. La forma de detallar estos servicios es con este XML llamado WSDL (web service description language). Cuando un cliente desee hacer uso de tus servicios, esa es la URL a la que deberá apuntar para conocer la forma y los detalles para invocarlos.
Muchas gracias por tu comentario.
Saludos,
José