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/