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:

<br />
package test;</p>
<p>import javax.jws.WebService;</p>
<p>@WebService<br />
public interface SayHello {</p>
<p>	  String sayHello(String name);<br />
}<br />

Y su implementación:

<br />
package test;</p>
<p>import javax.jws.WebService;</p>
<p>@WebService(endpointInterface=&amp;quot;test.SayHello&amp;quot;<br />
)<br />
public class SayHelloImpl implements SayHello {</p>
<p>	public String sayHello(String name) {<br />
		return &amp;quot;Hello &amp;quot; + name + &amp;quot;!&amp;quot;;<br />
	}</p>
<p>}<br />

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:

<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br />
	xmlns:jaxws=&quot;http://cxf.apache.org/jaxws&quot;<br />
	xsi:schemaLocation=&quot;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&quot;&gt;</p>
<p>	&lt;import resource=&quot;classpath:META-INF/cxf/cxf.xml&quot; /&gt;<br />
	&lt;import resource=&quot;classpath:META-INF/cxf/cxf-extension-soap.xml&quot; /&gt;<br />
	&lt;import resource=&quot;classpath:META-INF/cxf/cxf-<br />
servlet.xml&quot; /&gt;</p>
<p>	&lt;jaxws:endpoint id=&quot;sayHello&quot; implementor=&quot;test.SayHelloImpl&quot; address=&quot;/SayHello&quot;&gt;<br />
		&lt;jaxws:features&gt;<br />
			&lt;bean class=&quot;org.apache.cxf.feature.LoggingFeature&quot; /&gt;<br />
		&lt;/jaxws:features&gt;<br />
	&lt;/jaxws:endpoint&gt;</p>
<p>&lt;/beans&gt;<br />

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:

<br />
&lt;bean id=&quot;sayHelloService&quot; class=&quot;test.SayHelloImpl&quot; /&gt;</p>
<p>&lt;jaxws:endpoint id=&quot;sayHello&quot; implementor=&quot;#sayHelloService&quot; address=&quot;/SayHello&quot;&gt;<br />
	&lt;jaxws:features&gt;<br />
		&lt;bean class=&quot;org.apache.cxf.feature.LoggingFeature&quot; /&gt;<br />
	&lt;/jaxws:features&gt;<br />
&lt;/jaxws:endpoint&gt;<br />

WEB-INF/web.xml contiene la configuración para levantar el contexto de Spring y el servlet de CXF

<br />
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;!DOCTYPE web-app PUBLIC<br />
 &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;<br />
 &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &gt;</p>
<p>&lt;web-app&gt;<br />
	&lt;context-param&gt;<br />
		&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;<br />
		&lt;param-value&gt;WEB-INF/application-config.xml&lt;/param-value&gt;<br />
	&lt;/context-param&gt;</p>
<p>	&lt;listener&gt;<br />
		&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;<br />
	&lt;/listener&gt;</p>
<p>	&lt;servlet&gt;<br />
		&lt;servlet-name&gt;CXFServlet&lt;/servlet-name&gt;<br />
		&lt;display-name&gt;CXF Servlet&lt;/display-name&gt;<br />
		&lt;servlet-class&gt;org.apache.cxf.transport.servlet.CXFServlet&lt;/servlet-class&gt;<br />
		&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />
	&lt;/servlet&gt;</p>
<p>	&lt;servlet-mapping&gt;<br />
		&lt;servlet-name&gt;CXFServlet&lt;/servlet-name&gt;<br />
		&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />
	&lt;/servlet-mapping&gt;<br />
&lt;/web-app&gt;<br />

Para el manejo de dependencias utilizaremos Maven, y las dependencias incluídas en el POM del proyecto son las siguientes:

<br />
&lt;dependencies&gt;<br />
	&lt;dependency&gt;<br />
		&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;<br />
		&lt;artifactId&gt;cxf-rt-core&lt;/artifactId&gt;<br />
		&lt;version&gt;2.1&lt;/version&gt;<br />
	&lt;/dependency&gt;<br />
	&lt;dependency&gt;<br />
		&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;<br />
		&lt;artifactId&gt;cxf-rt-frontend-simple&lt;/artifactId&gt;<br />
		&lt;version&gt;2.1&lt;/version&gt;<br />
	&lt;/dependency&gt;<br />
	&lt;dependency&gt;<br />
		&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;<br />
		&lt;artifactId&gt;cxf-rt-frontend-jaxws&lt;/artifactId&gt;<br />
		&lt;version&gt;2.1&lt;/version&gt;<br />
	&lt;/dependency&gt;<br />
	&lt;dependency&gt;<br />
		&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;<br />
		&lt;artifactId&gt;cxf-rt-transports-local&lt;/artifactId&gt;<br />
		&lt;version&gt;2.1&lt;/version&gt;<br />
	&lt;/dependency&gt;<br />
	&lt;dependency&gt;<br />
		&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;<br />
		&lt;artifactId&gt;cxf-rt-transports-http&lt;/artifactId&gt;<br />
		&lt;version&gt;2.1&lt;/version&gt;<br />
	&lt;/dependency&gt;<br />
	&lt;dependency&gt;<br />
		&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;<br />
		&lt;artifactId&gt;cxf-common-utilities&lt;/artifactId&gt;<br />
		&lt;version&gt;2.1&lt;/version&gt;<br />
	&lt;/dependency&gt;<br />
	&lt;dependency&gt;<br />
		&lt;groupId&gt;junit&lt;/groupId&gt;<br />
		&lt;artifactId&gt;junit&lt;/artifactId&gt;<br />
		&lt;version&gt;4.4&lt;/version&gt;<br />
		&lt;scope&gt;test&lt;/scope&gt;<br />
	&lt;/dependency&gt;<br />
&lt;/dependencies&gt;<br />

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

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/

Bookmark the permalink.

10 respuestas a Web services con Spring framework y CXF

  1. Diego says:

    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!

    • jarrarte says:

      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é

  2. Sr. José: LA verdad es que habia visto muchos ejemplos de un web service con cxf, además integrado con spring, pero ninguno me habia funcionando porque no me mostraban la estructura del proyecto, y además no daban una total configuracion de las dependencias.

    excelente ejemplo.

    Creo que cuando se hacen este tipo de ejemplos se debe mostrar cosas elementales, como la estructura del proyecto asi que bien por ello.

    • Agustín, muchas gracias por tu comentario!

      Este blog surge justamente por eso que comentas, intentando armar ejemplos y explicar conceptos que no están demasiado claros en la documentación o en otras páginas de la web. Al principio fue un registro para uso personal, pero me alegro mucho que sirva a otra gente también.

      Saludos!

  3. JoseBT says:

    Estimado José,

    Excelente articulo!! al igual que Agustin tampoco había dado con algo que funcionara.
    Ahora quesiera pedir de su ayuda… Necesito implementar este Web Services con Mysql, pero he buscado y probado y no logro conseguir nada. Si tiene algún ajemplo o consejo de como hacerlo.

    Saludos y Gracias!!!

  4. Sergio Hernandez says:

    Hola, me gustaria que implementaras el cliente que consuma este web service…no tengo ni idea de como hacerlo, si puedes hacerlo dentro de un servlet te lo agradeceria mucho..

    Gracias¡¡¡¡

  5. Tavo says:

    Excelente ejemplo. Una duda, ¿existe alguna manera de cargar los «endpoint» solo con annotation?. Me quiero evitar estar declarando cada endpoint en el archivo xml, y crear un factory que me levante todos los que sean servicios web. Actualmente lo hago de esa forma con XFire, pero quiero cambiarme a CXF y solo me queda ese objetivo por lograr. He revisado JaxWsServerFactoryBean pero no lo he podido lograr. Ojala si tienes ejemplos concretos de como hacerlo ideal, pero con alguna idea podria empezar. Se agradece!. Saludos.

  6. Leonardo says:

    Tengo un problema al probar el servicio, descarge los archivo lo eche a correr y me muestra el xml en «localhost:8080/ws-test/SayHello?wsdl» . Pero cuando lo intento probar desde soapUi me arroga el siguiente error.
    Error loading [http://localhost:8080/ws-test/SayHello?wsdl]: org.apache.xmlbeans.XmlException: org.apache.xmlbeans.XmlException: error: Unexpected element: TAG_END

  7. Francisco says:

    Excelente, gracias Jose por tu ejemplo.
    Funciona impecable.
    Saludos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *