26 octubre, 2013

Hola Mundo con Spring MVC

Tipicamente cuando incursionamos con un nuevo framework o lenguaje de programacion queremos rapidamente hacer funcionar algo, y como estoy dedicando una serie de articulos a Spring Framework, no podia faltar uno dedicado al simple y bien ponderado "Hola Mundo"... La idea es mostrar como construir el Skeleton fundamental para que nuestra aplicacion Spring MVC funcione...
Para realizar este ejemplo como la mayoria de los publicados aqui usaré:
  • Eclipse (Juno) como IDE
  • Maven (plugin de eclipse) para incluir facilmente librerias y dependencias
  • Tomcat 7
  • Spring Framework (en este ejemplo la version 3.01)

Configurando el nuevo proyecto

Lo primero es crear un nuevo proyecto, para esto podemos usar clic derecho la ventana de Package Explorer o bien en Archivo->New->Project y seleccionar Maven Project
Luego seleccionado Maven Project le damos Next, para seleccionar el nombre y la ubicacion del proyecto, en esta oportunidad todos los valores quedan por defecto y ademas debemos seleccionar el checkbox "Create a simple project (skip archetype selection)" para saltarnos la selección de arquetipo puesto que lo crearemos nosotros mismos...
Ahora introducimos informacion de configuracion del proyecto como el grupo, artefacto, version y forma de empaquetamiento, en este caso el Group Id es com.codelious.mimvc, el Artifact Id es MiMVC y en Packaging seleccionamos war, la version queda por defecto...
Luego damos clic en Finish y deberiamos tener nuestro proyecto creado con una estructura basica que incluye los directorios src/main/webapp y tambien se ha creado nuestro archivo pom.xml que nos permitira el facil manejo de dependencias con Maven.
Dentro de nuestro directorio webapp debemos crear manualmente algunos directorios y archivos para que se vea finalmente una estructura como la de la imagen abajo...

Incluyendo dependencias Maven

Ahora debemos incluir algunas dependencias y las librerias de Spring Framework en nuestro archivo pom.xml para que Maven las cargue a nuestro proyecto, editemos el contenido del pom.xml para que quede asi:

<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/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.codelious.mimvc</groupId>
 <artifactId>MiMVC</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>
 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>3.0.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>3.0.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>3.0.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
   <version>1.1.1</version>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
 </dependencies>
</project> 

Configurando nuestra aplicación

Luego de añadir las dependencias, debemos codificar nuestro archivo web.xml que es el descriptor de despliegue, y ahi debemos incluir las referencias a nuestro Dispatcher Servlet que es basicamente el despachador de solicitudes a controladores.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" 
 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 id="WebApp_ID" version="3.0">
 
 <display-name>MiMVC</display-name>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

 <servlet>
  <servlet-name>despachador</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>despachador</servlet-name>
  <url-pattern>*.html</url-pattern>
 </servlet-mapping>

</web-app>
Como se puede notar en el web.xml arriba, tenemos un <servlet> y un <servlet-mapping>, el servlet-mapping trabaja direccionando todos los patrones de url que incluyan extension .html a nuestro dispatcher servlet llamado despachador que es de clase org.springframework.web.servlet.DispatcherServlet, por tanto no es coincidencia que hayamos creado un archivo despachador-servlet.xml, ya que spring buscará un archivo con nombre compuesto por el nombre del servlet añadiendo "-servlet.xml" o sea si en el archivo web.xml estamos declarando el dispatcher servlet con <servlet-name>mascotas</servlet-name> entonces se buscará el archivo mascotas-servlet.xml
También tenemos <welcome-file-list> que permite indicar la pagina de entrada a la aplicacion, la que en este caso sera index.jsp

Ahora codificamos el dispatcher servlet llamado despachador-servlet.xml añadiendo bean viewResolver y un component-scan:
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <context:component-scan
        base-package="com.codelious.mimvc.controller" />
         
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
</beans>
El bean context:component-scan resaltado arriba permitirá escanear automáticamente todos los controladores ubicados en el paquete com.codelious.mimvc.controller, tambien es posible declarar  varios beans por separado que invocan directamente a cada controlador.
El bean viewResolver nos permitirá resolver las vistas de nuestra aplicación cuando las invoquemos desde nuestros controladores y en este caso indica la ubicacion de las vistas.

Codificando la pagina de entrada

Como mencionamos en el archivo de configuracion web.xml declaramos una pagina de entrada a la aplicacion, para esto agreguemos el siguiente codigo a index.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>MiMVC</title>
</head>
<body>
 <h1>Bienvenido a MiMVC</h1>
 <p>
  Presiona el link para ver el <a href="saludar.html">saludo</a>
 </p>
</body>
</html>

Creando el controlador

Vamos a crear un contralador llamado "Saludo" que recibira nuestra solicitud desde la pagina de entrada index.jsp y luego nos direccionará a la vista de saludo, para esto debemos crear en src/main/java el paquete com.codelious.mimvc.controller donde crearemos la clase SaludoController.java y le agregaremos el siguiente codigo:
package com.codelious.mimvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class SaludoController {

 @RequestMapping("/saludar")
 public ModelAndView saludar(){
  
  String mensaje = "Hola Mundo Maravilloso";
  return new ModelAndView("saludo", "mensaje", mensaje);
  
 }
}
En el codigo hemos creado un metodo saludar() que devuelve ModelAndView y es el metodo que procesará nuestra solicitud y nos direccionará a la vista deseada, luego hemos puesto un par de anotaciones de Spring, la primera es @Controller e indica que la clase es un controlador, la segunda es @RequestMapping("/saludar") que permite mapear la solicitud desde la url. El metodo saludar() nos retornará un objeto ModelAndView al cual le indicamos la vista que en nuestro caso sera saludo.jsp, luego incluimos un mensaje que estará disponible en nuestra vista para accederlo mediante tags jstl.

Creando la vista

Para nuestra vista crearemos en WEB-INF/jsp el archivo saludo.jsp en el cual agregaremos nuestro codigo:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>MiMVC</title>
</head>
<body>
 <h1>${mensaje}</h1>
</body>
</html>

Probando la aplicacion

Hecho todo lo anterior deberiamos tener una estructura similar a la siguiente:
y entonces ya podemos probar nuestra aplicación en un navegador web, para eso podemos dar clic derecho sobre la raiz de nuestro proyecto y seleccionar Run As->Run on Server y verlo en la direccion http://localhost:18080/MiMVC/ (reemplazar el puerto 18080 por el que uses)
Si damos clic al link saludo estaremos haciendo la llamada al controlador y este nos devolvera la pagina saludo.jsp
Y esto sería todo, ya tenemos nuestro hola mundo MVC en Spring Framework. Si quieres descargar el proyecto completo puedes hacerlo en github: https://github.com/codelious/MiMVC

20 octubre, 2013

Spring Framework y Vistas XSLT

XSLT es un lenguaje de transformación para XML y es popular como una tecnología de vistas con aplicaciones web. XSLT puede ser una buena elección como una tecnología de vista si tu aplicación naturalmente negocia con XML, o si tu modelo puede ser fácilmente convertido a XML. Este post muestra como producir un documento XML como modelo de datos y tenerlo transformado con XSLT en una aplicación Spring Web MVC.

Este ejemplo es una aplicación trivial de Spring que crea una lista de palabras en el Controlador y las agrega al mapa de modelo. El mapa es retornado junto con el nombre de vista de nuestra vista XSLT. La vista XSLT pondrá la lista de palabras en un documento simple XML listo para la transformación.

La estructura de la aplicacion

Nuestra aplicacion es una aplicacion Simple de Maven y deberá tener una estructura similar a esto:


Usando Maven

Como yo estoy usando Maven para el manejo de las dependencias de la aplicacion, mi archivo pom.xml se ve asi:
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.codelious.mixslt</groupId>
  <artifactId>MiXSLT</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <dependencies>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>3.0.1.RELEASE</version>
   </dependency>
   <dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
   </dependency>
   <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
   </dependency>
   <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
   </dependency>
  </dependencies>
</project>

Los archivos de configuracion y dispatcher sevlet

El archivo web.xml tiene el siguiente aspecto:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" 
 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 id="WebApp_ID" version="3.0">
 
 <display-name>MiXSLT</display-name>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>

 <servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>*.htm</url-pattern>
 </servlet-mapping>

</web-app>
y El archivo spring-servlet.xml que es nuestro despachador de solicitudes sigue asi:
<?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:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 <bean id="viewResolver"
  class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
  <property name="order">
   <value>1</value>
  </property>
  <property name="basename" value="views" />
 </bean>
 
 <bean id="xsltViewResolver"
  class="org.springframework.web.servlet.view.xslt.XsltViewResolver">
  <property name="order">
   <value>2</value>
  </property>
  <property name="viewClass"
   value="org.springframework.web.servlet.view.xslt.XsltView" />
  <property name="sourceKey" value="obj" />
  <property name="suffix" value=".xsl" />
  <property name="prefix" value="/WEB-INF/xsl/" />
 </bean>

 <bean id="simpleUrlMapping"
  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
   <value>
    /home.htm=homeController
   </value>
  </property>
 </bean>

 <bean id="homeController" class="com.codelious.mixslt.controller.HomeController" /> 
</beans>

Definicion de Beans

Como se ve arriba, la configuracion es estandar para una aplicacion simple de Spring. El archivo de configuracion de dispatcher servlet contiene una referencia a un ViewResolver, URL mappings y un Bean de controlador que encapsula nuestra logica de generacion de palabras:
<bean id="homeController" class="com.codelious.mixslt.controller.HomeController" />

Codigo del Controlador MVC

La logica del controlador es encapsulada en una subclase de AbstractController, con el metodo handler que se define como sigue...
package com.codelious.mixslt.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class HomeController extends AbstractController {

    protected ModelAndView handleRequestInternal(HttpServletRequest request,
        HttpServletResponse response) throws Exception {
  
        Map mapa = new HashMap();
        List listaPalabras = new ArrayList();
  
        listaPalabras.add("Hola");
        listaPalabras.add("Universo");
  
        mapa.put("listaPalabras", listaPalabras);
  
        return new ModelAndView("home", mapa);
    }

}
Hasta aqui no tenemos nada especifico de XSLT. Los datos del modelo han sido creados en la misma forma en que hariamos otra aplicacion Spring MVC. Dependiendo de la configuracion de la aplicacion, esta lista de palabras podria ser renderizada por JSP/JSTL teniendolas agregadas como atributos en la solicitud (request attributes), o podrian ser manipuladas por Velocity agregando el objeto al VelocityContext. Para tener XSLT renderizalos, y por supuesto tienen que ser convertidos en un documento XML de alguna manera. Existen paquetes de software que automaticamente 'DOMifican' los objetos, pero con Spring, tienes completa flexibilidad para crear el DOM desde tu modelo en cualquier forma que quieras. Esto evita el juego exesivo con la transformacion de XML, lo cual es peligroso cuando usamos herramientas para manejar procesos de DOMificacion

Convertir los datos del modelo a XML

Para crear un documento DOM desde nuestra lista de palabras o cualquier otro dato del modelo, debemos extender de la clase org.springframework.web.servlet.view.xslt.AbstractXsltView. Haciendo esto, debemos tambien implementar el metodo abstracto createXsltSource(..). El primer parametro pasado a este metodo es nuestro mapa del modelo. Aqui esta la clase HomePage en nuestra aplicacion:
package com.codelious.mixslt.controller;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;

import org.springframework.web.servlet.view.xslt.AbstractXsltView;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

public class HomePage extends AbstractXsltView {

    protected Source createXsltSource(Map modelo, String nombreRaiz,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {

        Document documento = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        Element raiz = documento.createElement(nombreRaiz);

        List palabras = (List) modelo.get("listaPalabras");
        for (Iterator it = palabras.iterator(); it.hasNext();) {
            String palabraSiguiente = (String) it.next();
            Element nodoPalabra = documento.createElement("palabra");
            Text nodoTexto = documento.createTextNode(palabraSiguiente);
            nodoPalabra.appendChild(nodoTexto);
            raiz.appendChild(nodoPalabra);
        }
        return new DOMSource(raiz);
    }
}

Una serie de parametros nombre/valor pueden ser definidos opcionalmente por tu subclase la cual sera agregado al objeto de transformacion. Los nombres de parametro deben coincidir con los definidos en la plantilla XSLT declarados con <xsl:param name="miParametro">valorDefecto</xsl:param><bean id="homeController" class="xslt.HomeController" />. Para especificar los parametros, sobreescribe el metodo getParameters() de la clase AbstractXsltView y retorna un Map de nombre/valor. Si tus parametros necesitan derivar informacion desde la solicitud actual, tu puedes sobreescribir el metodo getParameters(HttpServletRequest request) en su lugar.

Definiendo las propiedades de la vista

El archivo views.properties (o definicion xml equivalente si estas usando un view resolver basado en XML) luce como este para la unica vista de la aplicacion que es 'Mis Primeras Palabras':
home.(class)=com.codelious.mixslt.controller.HomePage 
home.stylesheetLocation=/WEB-INF/xsl/home.xsl
home.root=palabras
Aqui, puedes ver como la vista esta enlazada con la clase HomePage recien escrita la cual maneja el modelo domificacion en la primera propiedad '.class'. La propiedad 'stylesheetLocation' apunta al archivo XSLT el cual manipulara para nosotros la transformacion XML dentro de HTML y la propiedad final '.root' es el nombre que sera usado como la raiz del documento XML. Este obtiene acceso a la clase HomePage de arriba en el segundo parametro para los metodos createXsltSource(..).

Transformacion del documento

Finalmente, tenemos el codigo XSLT usado para transformar el documento de arriba. Como muestra en el archivo 'views.properties', la hoja de estilos es llamada 'home.xslt' y esta ubicada en el directorio 'WEB-INF/xsl'.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" omit-xml-declaration="yes" />

    <xsl:template match="/">
        <html>
            <head>
                <title>Hola!</title>
            </head>
            <body>
                <h1>Mis Primeras Palabras</h1>
                <xsl:apply-templates />
            </body>
        </html>
    </xsl:template>

    <xsl:template match="palabra">
        <xsl:value-of select="." />
    </xsl:template>
</xsl:stylesheet>

El archivo index.jsp solamente es la pagina de entrada a la aplicacion y en ella hemos puesto un link a nuestro controlador http://localhost:18080/MiXSLT/home.htm
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>MiXSLT</title>
    </head>
    <body>
        <h1>Bienvenido a mi XSLT</h1>
        Prueba la vista XSL en <a href="http://localhost:18080/MiXSLT/home.htm">
                      http://localhost:18080/MiXSLT/home.htm</a>
    </body>
</html>

Solo nos queda probar nuestra aplicacion en un navegador usando la pagina de entrada o bien directamente escribiendo la url http://localhost:18080/MiXSLT/home.htm y deberia verse algo asi:
Puedes descargarte el codigo en github https://github.com/codelious/Spring_XSL_views

12 octubre, 2013

Contract-First en Spring-WS, Definiendo el contrato

Problema

De acuerdo al enfoque de WS basado en Contract-First, el primer paso de desarrollar un WS es definer el contrato del servicio. ¿Cómo debes hacer eso?

Solucion

Un contrato de WS consiste en dos partes: El contrato de datos y el contrato de servicios. Ambos son definidos con tecnologías XML en una plataforma y lenguaje de forma independiente.

Contrato de datos: Describe la complejidad de los tipos de datos y mensajes de solicitudes y respuestasde del WS. Un contrato de datos es típicamente definido con XSD, pero también puedes usar DTD, RELAX NG, o Schematron.
Contrato de servicios: Describe las operaciones del WS. Un WS puede tener multiples operaciones. Un contrato de servicio es definido con WSDL

Cuando usamos un framework de desarrollo de WS como Spring-WS, el contrato de servicio puede usualmente ser generado automáticamente, pero tú debes crear el contrato de datos por ti mismo.
Para crear el contrato de datos para tu WS, debes comenzar creando el archivo XSD. Dado que hay muchas herramientas XML poderosas disponibles en la comunidad, esto no debería ser muy pesado. Como siempre, muchos desarrolladores prefieren comenzar creando algún mensaje ejemploXML y luego generar el XSD desde este xml. Por supuesto, tu necesitas optimizar manualmente el XSD generado, como también puede que no requiera enteramente ajustarlo, y a veces, tu puedes desear agregar mas restricciones a este.

¿Como funciona?

Creando mensajes XML de ejemplo

Para el servicio del clima, puedes representar la temperatura de una ciudad y fecha particular como en el siguiente mensaje XML:
<TemperaturaInfo ciudad="Santiago" fecha="2013-10-12">
    <min>5</min>
    <max>26</max>
    <promedio>15.5</promedio>
</TemperaturaInfo>
Entonces puedes definir el contrato de datos para el servicio del clima. Supongamos que quieres definir una operación que permita a los clientes consultar las temperaturas de una ciudad en particular, para multiples fechas. Cada solicitud consiste de un elemento de ciudad y multiples elementos de fecha. Debes especificar también el nombre de espacio para esta solicitud para evitar conflictos de nombre con otros documentos XML. Guardemos este mensaje XML como solicitud.xml
<GetTemperaturasRequest 
xmlns="http://spring.codelious.com/clima/schemas"> 
    <ciudad>Santiago</ciudad> 
    <fecha>2013-10-01</fecha> 
    <fecha>2013-10-08</fecha> 
    <fecha>2013-10-15</fecha> 
</GetTemperaturasRequest> 
La respuesta consiste de multiples elementos TemperaturaInfo, donde cada uno representa la temperatura de una ciudad y fecha particular, de acuerdo con las fechas solicitadas. Guardemos el mensaje XML como respuesta.xml
<GetTemperaturasResponse 
xmlns="http://spring.codelious.com/clima/schemas"> 
    <TemperaturaInfo ciudad="Santiago" fecha="2013-10-01"> 
        <min>5.0</min> 
        <max>10.0</max> 
        <promedio>8.0</promedio> 
    </TemperaturaInfo> 
    <TemperaturaInfo ciudad="Santiago" fecha="2013-10-08"> 
        <min>4.0</min> 
        <max>13.0</max> 
        <promedio>7.0</promedio> 
    </TemperaturaInfo> 
    <TemperaturaInfo ciudad="Santiago" fecha="2013-10-15"> 
        <min>10.0</min> 
        <max>18.0</max> 
        <promedio>15.0</promedio> 
    </TemperaturaInfo> 
</GetTemperaturasResponse>

Generando un archivo XSD desde los mensajes XML de ejemplo

Ahora, tu puedes generar el archivo XSD desde los mensajes XML de ejemplos anteriores. Muchas herramientas XML populares y tambien IDEs de Java EE pueden generar un XSD desde un par de archivos XML. Aqui usaremos Apache XMLBeans (http://xmlbeans.apache.org) para generar nuestro archivo XSD.
Apache XMLBeans provee una herramienta llamada inst2xsd que genera archivos XSD desde archivos XML. Este soporta varios tipos de diseños para generar archivos XSD. El mas simple se llama Russian doll design, el cual genera elementos locales y tipos locales para el archivo XSD objetivo. Debido a que no hay un tipo de enumeracion usado en tus mensajes XML, debes tambien deshabilitar la caracteristica de generacion de enumeracion. Puedes ejecutar el siguiente comando para generar el XSD para tu contrato de datos:
inst2xsd -design rd -enumerations never solicitud.xml respuesta.xml
El archivo XSD generado tendra el nombre por defecto schema0.xsd, localizado en el mismo directorio. Renombremoslo a temperatura.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" 
           elementFormDefault="qualified" 
           targetNamespace="http://spring.codelious.com/clima/schemas" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="GetTemperaturasRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="ciudad"/>
        <xs:element type="xs:date" name="fecha" 
           maxOccurs="unbounded" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="GetTemperaturasResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="TemperaturaInfo" 
           maxOccurs="unbounded" minOccurs="0">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:float" name="min"/>
              <xs:element type="xs:float" name="max"/>
              <xs:element type="xs:float" name="promedio"/>
            </xs:sequence>
            <xs:attribute type="xs:string" name="ciudad" use="optional"/>
            <xs:attribute type="xs:date" name="fecha" use="optional"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Optimizando el XSD generado

Como puedes ver, el archivo XSD generado permite a los clientes consultar temperaturas de fechas ilimitadas. Si tu quieres agregar una restriccion sobre el maximo y minimo de consultas de fechas, puedes modificar los atributos maxOccurs y minOccurs.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" 
           elementFormDefault="qualified" 
           targetNamespace="http://spring.codelious.com/clima/schemas" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="GetTemperaturasRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="ciudad"/>
        <xs:element type="xs:date" name="fecha" 
            maxOccurs="5" minOccurs="1"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="GetTemperaturasResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="TemperaturaInfo" 
            maxOccurs="5" minOccurs="1">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:float" name="min"/>
              <xs:element type="xs:float" name="max"/>
              <xs:element type="xs:float" name="promedio"/>
            </xs:sequence>
            <xs:attribute type="xs:string" name="ciudad" use="optional"/>
            <xs:attribute type="xs:date" name="fecha" use="optional"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Previsualizando el archivo WSDL generado

Como aprenderemos despues, Spring-WS puede automaticamente generar el contrato de servicio para ti, basado en el contrato de datos y algunas convensiones que puedes sobreescribir. Aqui, puedes previsualizar el archivo WSDL generado para entender mejor el contrato de servicio. Para simplificar, las partes menos importantes son omitidas.
<?xml version="1.0" encoding="UTF-8" ?> 
<wsdl:definitions ... 
    targetNamespace="http://spring.codelious.com/clima/schemas"> 
    <wsdl:types> 
        <!-- Copiado desde el archivo XSD --> 
        ... 
    </wsdl:types> 
    <wsdl:message name="GetTemperaturasResponse"> 
        <wsdl:part element="schema:GetTemperaturasResponse" 
            name="GetTemperaturasResponse"> 
        </wsdl:part> 
    </wsdl:message> 
    <wsdl:message name="GetTemperaturasRequest"> 
        <wsdl:part element="schema:GetTemperaturasRequest" 
            name="GetTemperaturasRequest"> 
        </wsdl:part> 
    </wsdl:message> 
    <wsdl:portType name="Clima"> 
        <wsdl:operation name="GetTemperaturas"> 
            <wsdl:input message="schema:GetTemperaturasRequest" 
                name="GetTemperaturasRequest"> 
            </wsdl:input> 
            <wsdl:output message="schema:GetTemperaturasResponse" 
                name="GetTemperaturasResponse"> 
            </wsdl:output> 
        </wsdl:operation> 
    </wsdl:portType> 
    ... 
    <wsdl:service name="ClimaService"> 
        <wsdl:port binding="schema:ClimaBinding" name="ClimaPort"> 
            <soap:address 
                location="http://localhost:8080/clima/services" /> 
        </wsdl:port> 
    </wsdl:service> 
</wsdl:definitions> 
En el portType Clima, una operacion GetTemperaturas es definida cuyo nombre es derivado desde el prefijo de la entrada y salida de mensajes (ejemplo., <GetTemperaturasRequest> y <GetTemperaturasResponse>). Las definiciones de estos dos elementos son incluidas en la parte <wsdl:types>, asi como definidos en el contrato de datos.
Para saber como implementar un Web Services usando Spring-WS y un Contrato generado de la forma explicada aqui, puedes ver el post Spring Web Services Contract First.