Web Service con Maven + Axis2 + Spring framework

En este post voy a explicar cómo crear un servicio web con Maven, Axis2 y Spring framework. La idea es tener el mínimo número de ficheros y configuración para que el servicio web funcione.

Lo primero que vamos a necesitar es un proyecto Maven, al que he llamado "servicioWeb", de tipo aplicación web con la siguiente estructura:
servicioWeb
 |-src
   |-main
     |-resources
     |-java
     |-webapp
       |-web.xml
       |-WEB-INF
         |-services
 |-pom.xml

El servicio web podrá desplegarse como un fichero WAR en un contenedor Tomcat o ejecutarlo con un servidor embebido Jetty. Lo primero es darle contenido al fichero pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.tutorialexception</groupId>
    <artifactId>servicioWeb</artifactId>
    <packaging>war</packaging>
    <version>0.1</version>
    <name>Ejemplo de servicioWeb</name>
    <url>http://tutorialexception.blogspot.com</url>

    <build>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <warName>${pom.artifactId}</warName>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>3.0.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>3.0.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-kernel</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-codegen</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>java.net</id>
            <url>https://maven-repository.dev.java.net/nonav/repository</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>
Aquí simplemente hemos configurado el plugin de jetty para poder ejecutar el servicio web de forma embebida y los plugins mave-compiler-plugin (para indicar que trabajamos con J2SE 1.5) y maven-war-plugin (para especificar el nombre del WAR generado). Además especificamos las dependencias y el repositorio en el que se encuentran algunas de las mismas.

Lo siguiente es crear nuestra interfaz que defina el servicio web y su implementación. Aunque no es necesario crear la interfaz, es una práctica recomendable. Veamos el contenido de la misma.
package org.tutorialexception.ws;

public interface SaludaService {
    
    public String saluda(String nombre);

}
Ahora vamos con la implementación, en la que haremos uso de dos atributos que serán inyectados con Spring en el bean de implementación:
package org.tutorialexception.ws;

public class SaludaServiceImpl implements SaludaService {
    
    private String prefijoSaludo;
    private String sufijoSaludo;

    public SaludaServiceImpl(String prefijoSaludo, String sufijoSaludo) {
        super();
        this.prefijoSaludo = prefijoSaludo;
        this.sufijoSaludo = sufijoSaludo;
    }

    public String saluda(String nombre) {
        return prefijoSaludo + nombre + sufijoSaludo;         
    }

}
Ambas propiedades (prefijoSaludo y sufijoSaludo) serán inyectadas por Spring. Aquí podríamos perfectamente cambiar dichas propiedades por objeto de negocio que proporcionara a la implementación del servicio web acceso a la capa de negocio y a sus operaciones.

Ahora veamos el fichero de configuración de Spring que guardaremos en 'src/main/resources':
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    
    <bean id="saludaService" class="org.tutorialexception.ws.SaludaServiceImpl">
        <constructor-arg value="¡Hola "/>
        <constructor-arg value="!, ¿como va todo?"/>
    </bean>
    
</beans>
Como vemos inyectamos las propiedades a través del constructor. Esto se ha echo así por comodidad, puesto que si creamos métodos setter para dichas propiedades, Axis2 pondría dichos métodos como operaciones del servicio web.

Lo siguiente es ver el contenido del fichero web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
    <display-name>Ejemplo de Servicio Web</display-name>
  
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/applicationContext.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <servlet>
        <servlet-name>AxisServlet</servlet-name>
        <servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>AxisServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>

</web-app>
En este fichero configuramos dos cosas:
  • El contexto de Spring, de forma que al arrancar la aplicación web se cargará el fichero applicationContext.xml
  • El servlet de Axis que se hará cargo de las peticiones

Por último, necesitamos configurar Axis2 para especificar el servicio y que delegue la carga de objetos en Spring. Esto se hace creando una carpeta con el nombre del servicio dentro de 'src/main/webapp/WEB-INF/services' y dentro de ella otra subcarpeta 'META-INF' en la que guardaremos el fichero de configuración 'services.xml' (la ruta completa sería 'src/main/webapp/WEB-INF/services/SaludaService/META-INF'). El contenido de 'services.xml' para nuestro ejemplo será:
<?xml version="1.0" encoding="UTF-8"?>
<serviceGroup>
    <service name="SaludaService">
        <description>Ejemplo de Servicio Web</description>
        <parameter name="ServiceObjectSupplier" locked="false">org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier</parameter>
        <parameter name="SpringBeanName" locked="false">saludaService</parameter>        
        <operation name="saluda">
            <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
        </operation>
    </service>
</serviceGroup>
A destacar son los dos parámetros (ServiceObjectSupplier y SpringBeanName) que indican el proveedor de objetos y el nombre del objeto respectivamente. El elemento operation indica la operación y el método que se va a utilizar (RPC).

Ahora si nos vamos al directorio raíz del proyecto y ejecutamos:
mvn clean package jetty:run
Tendremos desplegado nuestro servicio web en http://localhost:8080/servicioWeb/services/SaludaService?wsdl. Podemos probarlo fácilmente con SoapUI que es un proyecto open source, con una versión gratuita) y que permite probar servicios web de una forma sencilla indicando únicamente el WSDL del servicio web.

Una vez instalado y abierto el programa, seleccionamos "File -> New soapUI Project":
En la siguiente pantalla, damos un nombre al proyecto y en el campo "Initial WSDL/WADL" introducimos la dirección del WSDL de nuestro proyecto (http://localhost:8080/servicioWeb/services/SaludaService?wsdl)
Al pulsar en "OK", soapUI generará peticiones para nuestras operaciones y para los binding disponibles. En nuestro caso sólo tenemos una operación pero dos binding (Soap 1.1 y Soap 1.2).
Si hacemos doble click en cualquiera de los dos request, nos aparecerá una pantalla de petición. En el cuadro de la izquierda se representa nuestra petición, que modificaremos de acuerdo a nuestros parámetros. En nuestro caso el campo nombre:
Si pulsamos en el botón de enviar (flecha verde) se enviará la petición obteniendo el resultado en el cuadro de la derecha.

Como vemos resulta muy sencillo implementar un servicio web con estas tecnologías. Espero que os sirva de ayuda. En próximos posts aumentaremos el ejemplo añadiéndole seguridad con Rampart.

Descarga el proyecto completo aquí

4 comentarios:

Alejandro dijo...

Muy claro tu ejemplo, gracias por el aporte!

elisamuel dijo...

Super!!
Muchas gracias esta facil y rapido de entender.
Disculpa Voy hacer un Web Service usando axis2 hibernate y spring
podrias orientarme en la estructura y lo q debo hacer.
De antemano muchas gracias
Saludos

Fede dijo...

Buenas elisamuel, para tu caso simplemente tendrías que añadir hibernate al ejemplo anterior. Puedes buscar ejemplos de Hibernate + Spring y simplemente adaptarlos a este ejemplo. Piensa en SaludaServiceImpl como el objeto de negocio y que tendría acceso a la capa de datos a través de objetos DAO.

Espero haberte ayudado, saludos!

will824 dijo...

Muchas muchas gracias por este sencillo tutorial, que va al grano y permite utilizar lo mínimo para tener un webservice disponible en Maven+Spring.

Saludos!

Publicar un comentario