Capítulo 1. Aplicación Base y Configuración del Entorno

1.1. Crear la estructura de directorios del proyecto

Necesitamos crear un directorio donde alojar todos los archivos que vayamos creando, así que comenzaremos creando un Dynamic Web Project llamado 'springapp'. Seleccionaremos la versión 3.1 del módulo web y como el servidor Apache Tomcat como Target runtime, de manera que el proyecto será capaz de encontrar las librerías adecuadas de 'javax.servlet'. Si se desea utilizar Spring Boot, es necesario crear un nuevo proyecto de tipo Spring Starter Project y seleccionar las dependencias Web y JPA. Los siguientes pasos asumirán que no se se está utilizando Spring Boot para poder mostrar explícitamente las dependencias que se utilizan en este proyecto.

Creación del nuevo proyecto

Tras seleccionar el nombre del proyecto, vamos a configurar una estructura de directorios estandar para proyectos Maven). Para ello, hay que crear las siguientes carpetas fuente: 'src/main/java', 'src/main/resources', 'src/test/java', 'src/test/resources'); y también cambar el directorio de contenidos web a 'src/main/webapp'.

Configuración de la estructura de directorios del proyecto

Para convertir el proyecto a tipo Maven y Spring, pinchamos con el botón derecho del ratón sobre el nombre del proyecto y seleccionamos Configure > Convert to Maven Project, y a continuación Spring Tools > Add Spring Project Nature. De momento, sólo disponemos de nuestra simple aplicación para la gestión de inventario.

Definición del nombre del proyecto en Maven

Si apareciera un warning en el proyecto causado por el uso de diferentes versiones de la JDK, ajustarlas conveniente configurando el Build Path del proyecto.

Una vez que el proyecto se ha creado, podemos identificar la siguiente estructura:

  • Los subdirectorios 'src/main/java' y 'src/main/resources' que contendrá todos los recursos utilizados por la aplicación.

  • Los subdirectorios 'src/test/java' y 'src/test/resources' que se utilizarán para los test unitarios.

  • El subdirectorio 'src/main/webapp' que alojará todos los archivos que no sean código fuente Java, como archivos JSP y de configuración.

  • El directorio 'target' donde se generará el archivo WAR que usaremos para almacenar y desplegar rápidamente nuestra aplicación.

  • El fichero 'pom.xml' que contiene las dependencias Maven.

A continuación puedes ver una captura de pantalla que muestra como quedaría la estructura de directorios si has seguido las instrucciones correctamente. (La imagen muestra dicha estructura desde el Spring Tool Suite (STS): no se necesita usar STS para completar este tutorial, pero usándolo podrás hacerlo de manera mucho más sencilla).

La estructura de directorios del proyecto

1.2. Crear 'index.jsp'

Puesto que estamos creando una aplicación web, vamos a crear un punto de entrada a nuestra aplicación en el directorio 'src/main/webapp' mediante un archivo JSP muy simple llamado 'index.jsp' como el que se muestra a continuación:

'springapp/src/main/webapp/index.jsp':

<html>
  <head><title>Example :: Spring Application</title></head>
  <body>
    <h1>Example - Spring Application</h1>
    <p>This is my test.</p>
  </body>
</html>

1.3. Desplegar la aplicación en el servidor

Para compilar, construir y desplegar la aplicación automáticamente sólo es necesario seleccionar 'Run as > Run on Server' sobre el menú contextual que aparece cuando se pincha el botón derecho sobre el nombre del proyecto. A continuación, debemos seleccionar el servidor desde el cuadro de diálogo que ofrece los servidores dados de alta en el entorno. Por ejemplo: Pivotal tc Server, Tomcat, GlassFish, etc.

1.4. Comprobar que la aplicación funciona

Los pasos anteriores abrirán una pestaña en el entorno de desarrollo STS donde se puede ver el contenido de la página 'index.jsp'. De manera alternativa, se puede abrir un navegador y acceder a la página de inicio de la aplicación en la siguiente URL: http://localhost:8080/springapp.

(La imagen muestra la visualización sobre STS: el número de puerto puede variar dependiendo del servidor utilizado).

La página de inicio de la aplicación

Se recomienda detener el servidor para evitar la recarga automática mientras se sigue desarrollando el proyecto.

1.5. Descargar Spring Framework

Utilizaremos Maven para gestionar las dependencias del proyecto con Spring Framework así como para descargar otras librerías adicionales necesarias. Se puede consultar MVNrepository para obtener los datos concretos de las dependencias que incluiremos en el fichero 'pom.xml'. En este fichero, hemos introducido una propiedad llamada 'org.springframework.version' y le hemos dado el valor '5.0.6.RELEASE'. Este valor corresponde con la última versión disponible de Spring Framework en el momento en el que ha escrito el tutorial. La introducción de propiedades con el valor de la versión de cada dependencia facilitará la actualización del proyecto a nuevas versiones.

Propiedades del fichero 'pom.xml'

A continuación, crearemos las siguientes dependencias para el proyecto desde la pestaña 'Dependencies' del fichero 'pom.xml'. Las librerías seran descargadas y añadidas automáticamente al proyecto en el momento en el que guardemos el fichero 'pom.xml'

Group Id Artifact Id Version Scope
org.springframework spring-webmvc ${org.springframework.version} Compile
org.springframework spring-test ${org.springframework.version} Compile
junit junit 4.12 Test

Nótese como la dependencia 'junit' (incluida por defecto en el fichero 'pom.xml') ha sido actualizada a la versión '4.12'. Por otra parte, la dependencia 'servlet-api' ha sido marcada como 'Provided', ya que será proporcionada por el servidor sobre el que se despliegue la aplicación.

Dependencias del fichero 'pom.xml'

1.6. Creación del descriptor de despliegue mediante clases de configuración

El descriptor de despliegue de una aplicación web se encuentra tradicionalmente en el directorio 'src/main/webapp/WEB-INF', y tiene como fichero principal el archivo 'web.xml'. En este tutorial, utilizaremos una aproximación más actual basada en el uso de anotaciones y clases de configuración.

En primer lugar, vamos a definir un DispatcherServlet cuya misión será controlar hacia dónde serán enrutadas todas nuestras solicitudes. Para ello creamos el paquete 'com.companyname.springapp' dentro de 'src/main/java' y añadimos la siguiente clase, que se lanzará automáticamente a través de la funcionalidad javax.servlet.ServletContainerInitializer del API de Servlet 3 (para más información podéis consultar esta guía rápida sobre configuración web en Spring).

'springapp/src/main/java/com/companyname/springapp/SpringappWebApplicationInitilizer.java':

package com.companyname.springapp;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.companyname.springapp.business.SpringappBusinessConfig;
import com.companyname.springapp.web.SpringappWebConfig;


public class SpringappWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { SpringappBusinessConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { SpringappWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

}

Como se puede observar, esta clase depende de la creación de dos clases de configuración en los paquetes 'com.companyname.springapp.business' y 'com.companyname.springapp.web'. La primera clase definirá la configuración del contexto general de la aplicación y la segunda el contexto de la capa web, es decir, las definiciones de los beans usados por el DispatcherServlet.

'springapp/src/main/java/com/companyname/springapp/business/SpringappBusinessConfig.java':

package com.companyname.springapp.business;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class SpringappBusinessConfig {

}

'springapp/src/main/java/com/companyname/springapp/web/SpringappWebConfig.java':

package com.companyname.springapp.web;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan
@EnableWebMvc
public class SpringappWebConfig {

}

1.7. Crear el Controlador

Vamos a crear una clase anotada con la etiqueta @Controller (a la que llamaremos HelloController.java) y que estará definida dentro del paquete 'com.companyname.springapp.web.controllers' del directorio 'src/main/java'

'springapp/src/main/java/com/companyname/springapp/web/controllers/HelloController.java':

package com.companyname.springapp.web.controllers;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {

    protected final Log logger = LogFactory.getLog(getClass());

    @RequestMapping(value="/hello.htm")
    public ModelAndView handleRequest() {
        logger.info("Returning hello view");
        return new ModelAndView("hello.jsp");
    }
}

De momento, esta implementación del controlador mediante la anotación @Controller, es muy básica. Más adelante la iremos expandiendo. En Spring Web MVC, los componentes @Controller manejan las solicitudes gracias al mapeo de métodos con múltiples de firmas posibles (para más información sobre la variedad de parámetros de entrada y de posibles valores de retorno consultad este enlace de la documentación oficial). En este caso, el método anotado @RequestMapping devuelve un objeto ModelAndView, cuya vista hace referencia al fichero 'hello.jsp' que vamos a crear a continuación. El objeto devuelto es resuelto a través del ViewResolver. Puesto que no hemos definido explicítamente un ViewResolver, vamos a obtener uno por defecto de Spring que simplemente redigirá a una dirección URL que coincida con el nombre de la vista especificada. Más tarde modificaremos este comportamiento. Además, hemos especificado un logger de manera que podemos verificar que pasamos por el manejador en cada momento. Usando STS, estos mensajes de log deben mostrarse en la pestaña 'Console'.

1.8. Escribir un test para el Controlador

Los tests son una parte vital del desarrollo del software. El mejor momento para escribir los tests es durante el desarrollo, no después, de manera que aunque nuestro controlador no contiene lógica demasiado compleja vamos a escribir un test para probarlo. Esto nos permitirá hacer cambios en el futuro con total seguridad. Vamos a crear (si no existiera) un nuevo directorio de tipo 'Source Folder' llamado 'src/test/java'. Aquí es donde alojaremos todos nuestros tests, en una estructura de paquetes que será idéntica a la estructura de paquetes que tenemos en 'src/main/java'.

Creamos una clase de test llamada 'HelloControllerTests' dentro del paquete 'com.companyname.springapp.web.controllers'.

'springapp/src/test/java/com/companyname/springapp/web/controllers/HelloControllerTests.java':

package com.companyname.springapp.web.controllers;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.servlet.ModelAndView;

import com.companyname.springapp.business.SpringappBusinessConfig;
import com.companyname.springapp.web.SpringappWebConfig;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SpringappBusinessConfig.class, SpringappWebConfig.class})
@WebAppConfiguration
public class HelloControllerTests {

    @Autowired
    private HelloController controller;

    @Test
    public void testHandleRequestView() {	
        ModelAndView modelAndView = controller.handleRequest();		
        assertEquals("hello.jsp", modelAndView.getViewName());
    }
}

Para ejecutar el test (y todos los tests que escribamos en el futuro), basta con que seleccionemos 'Run as > JUnit Test' sobre el menú contextual que aparece cuando se pincha el botón derecho sobre la clase de test. Si el test se ejecuta de forma satisfactoria podrás ver una barra verde que lo indica.

1.9. Crear la Vista

Ahora es el momento de crear nuestra primera vista. Como hemos mencionado antes, estamos redirigiendo hacia una página JSP llamada 'hello.jsp'. Para empezar, crearemos este fichero en el directorio 'src/main/webapp'.

'springapp/src/main/webapp/hello.jsp':

<html>
  <head><title>Hello :: Spring Application</title></head>
  <body>
    <h1>Hello - Spring Application</h1>
    <p>Greetings.</p>
  </body>
</html>

1.10. Compilar, desplegar y probar la aplicación

Para ejecutar la aplicación de nuevo, seleccionamos de nuevo 'Run as > Run on Server' sobre el menú contextual que aparece cuando se pincha el botón derecho sobre el nombre proyecto. (En algunos casos, es necasario reiniciar el servidor para asegurar que la aplicación se actualiza correctamente).

Probemos esta nueva versión de la aplicación. Desde el navegador que ofrece STS, o desde cualquier otro navegador, abrir la URL http://localhost:8080/springapp/hello.htm.

La aplicación actualizada

1.11. Resumen

Echemos un vistazo rápido a las partes de nuestra aplicacioón que hemos creado hasta ahora.

  1. Una página de inicio, 'index.jsp', la página de bienvenida de nuestra aplicación. Fue usada para comprobar que nuestra configuración era correcta. Más tarde la cambiaremos para proveer un enlance a nuestra aplicación.

  2. Un controlador frontal, DispatcherServlet, con las correspondientes clases de configuración: SpringappWebApplicationInitializer, SpringappBusinessConfig, SpringappWebConfig.

  3. Un controlador de página, HelloController, con funcionalidad limitada – simplemente devuelve un objeto ModelAndView. Actualmente tenemos un modelo vacío, más tarde proveeremos un modelo completo.

  4. Una unidad de test para la página del controlador, HelloControllerTests, para verificar que el nombre de la vista es el que esperamos.

  5. Una vista, 'hello.jsp', que de nuevo es extremadamente sencilla. Las buenas noticias son que el conjunto de la aplicación funciona y que estamos listos para añadir más funcionalidad.

A continuación puedes ver una captura de pantalla que muestra el aspecto que debería tener la estructura de directorios del proyecto después de seguir todas las instrucciones anteriores.

La estructura de directorios del proyecto al final de la parte 1