Desplegar web services CXF en Tomcat

De ChuWiki

Si hacemos unos Web Services con CXF, podemos hacer un main() de java y arrancarlos sin más. Pero no siempre queremos esto, a veces podemos querer hacer un war con estos web services para desplegarlos en un contenedor de aplicaciones como Apache Tomcat. Veamos cómo hacerlo.


Creación del proyecto[editar]

Usando maven[editar]

Una forma fácil de crear el proyecto es usar apache maven. Nos basta, con una ventana de comandos de windows, situarnos en el directorio donde queramos crear el proyecto y ejecutar

mvn archetype:generate

En el listado de proyectos que sale, elegimos el 120 org.apache.cxf.archetype:cxf-jaxws-javafirst (tendrás que mirar qué número es según la versión que utilices). Esto nos creará la estructura de directorios y un pequeño Web Service "Hola Mundo", así como todos los ficheros necesarios para tomcat. Con un

mvn package

en el directorio target aparecerá el fichero .war listo para ser desplegado.

Haciéndolo a mano[editar]

Veamos qué ha creado maven para ser capaces de hacerlo nosotros si no queremos usar maven.

En nuestro WEB-INF/lib debemos meter todos los jar que vienen con CXF cuando lo descargamos, las del directorio lib.

En el fichero WEB-INF/web.xml debemos añadir todo esto

<web-app>
   <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>WEB-INF/beans.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>

En el primer grupo de tags xml indicamos dónde está el fichero beans.xml, que es el fichero que usará CXF para saber cuales son las clases que son Web Services.

En el siguiente grupo de tags, la clase ContextLoaderListener se encarga de enterarse cuándo se arranca este war y cargar el fichero anterior e inicializar los Web Services.

En el siguiente grupo de tags, CXFServlet es el servlet que se encarga de recibir las peticiones web de los clientes y reencaminarlas a la clase Web Service adecudada, de forma que ante esas llamadas se ejecute el código de nuestro web service.

Finalmente, en el servlet-mapping indicamos cual es la URL para acceder al servlet anterior. Si el war se llama, por ejemplo, webservices.war, tal cual lo tenemos la URL de acceso al servlet será algo como http://un.dominio.cualquiera/webservices. Si en vez de /* ponemos otra cosa como /mi-servlet/*, entonces el acceso sería http://un.dominio.cualquiera/webservices/mi-servlet

Y en el fichero WEB-INF/beans.xml que aparecía al principio debemos poner lo siguiente

<?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="UnIdCualquiera"
      implementor="com.chuidiang.ejemplos.UnWebService" 
      address="/un-path" />
      
   <jaxws:endpoint id="OtroId"
      implementor="com.chuidiang.ejemplos.OtroWebService" 
      address="/otro-path" />
      
</beans>

La primera parte es fija y lo importante son los <jaxws:endpoint>. Ahí indicamos nuestras clases de web service. El id puede ser cualquiera que queramos, pero deben ser distintos entre sí. El implementor es la clase con las anotaciones @WebService. Y address es el path que hay que añadir en la URL para acceder al web service. En nuestro caso y suponiendo lo que indicamos en el servlet-mapping, sería

* http://un.dominio.cualquiera/webservices/UnWebService
* http://un.dominio.cualquiera/webservices/OtroWebService

Los wsdl estarán accesibles en

* http://un.dominio.cualquiera/webservices/UnWebService?wsdl
* http://un.dominio.cualquiera/webservices/OtroWebService?wsdl