Tutorial de Spring MVC

En este Tutorial de Spring MVC, aprenderemos cómo desarrollar una aplicación web utilizando Spring MVC y Spring Tool Suite. El framework Spring MVC se utiliza ampliamente para desarrollar aplicaciones web en Java.

Spring MVC

Al igual que Struts Framework, Spring MVC también se basa en las tecnologías Java EE de Servlet y JSP e implementa el patrón de diseño ModeloVistaControlador.

Tutorial de Spring MVC

Hemos visto anteriormente cómo funciona la Inyección de Dependencias de Spring y en este tutorial aprenderemos a crear una aplicación web simple utilizando el framework Spring MVC. Podemos utilizar Eclipse o IntelliJ IDE para el desarrollo de proyectos Spring, pero SpringSource proporciona Spring Tool Suite (STS), que es un IDE basado en Eclipse y viene con VMware vFabric tc Server incorporado, construido sobre el contenedor Apache Tomcat y optimizado para aplicaciones basadas en Spring. Utilizaré STS para el tutorial de Spring MVC y otros tutoriales futuros, ya que facilita la vida del desarrollador al proporcionar las siguientes características:

  • Soporte para crear aplicaciones esqueleto de Spring (MVC, Rest, Batch, etc.), útil para iniciar el proyecto desde cero. Pronto veremos en este tutorial de Spring MVC lo fácil que es crear un proyecto de Spring MVC.
  • Ofrece características útiles como la creación de archivos de configuración de Spring, análisis de archivos de configuración y clases para proporcionar información útil sobre ellos.
  • Validación automática de aplicaciones de Spring.
  • Soporte de refactorización para realizar fácilmente cambios en el proyecto; los cambios se reflejan también en los archivos de configuración.
  • Asistencia de código no solo para clases, sino también para archivos de configuración. Me gusta mucho esta función porque la mayoría de las veces necesitamos saber qué podemos usar y sus detalles.
  • El mejor soporte para la Programación Orientada a Aspectos (AOP) a través de la integración de AspectJ.

Mirando todas las características que ofrece STS, me convencí y decidí usarlo para mi aplicación de Spring, y hasta ahora estoy muy contento con ello. Solo descarga STS desde la Página Oficial de Descargas de STS e instálalo. Estoy utilizando STS 3.4.0.RELEASE, que se basa en Eclipse 4.3.1 release. Si no quieres usar STS y prefieres obtener sus funciones en tu Eclipse existente, entonces necesitas instalar su complemento desde el Eclipse Marketplace. Utiliza la siguiente imagen como referencia y asegúrate de elegir la versión correcta de STS para la instalación. El siguiente complemento es bueno para Eclipse Kepler. Si no deseas utilizar el servidor de SpringSource, puedes implementar la aplicación en cualquier otro contenedor Java EE, como Tomcat, JBoss, etc. Para este tutorial, usaré el servidor que viene con STS, pero he probado la aplicación exportándola como archivo WAR en un servidor Tomcat independiente y funciona bien. Ahora que nuestro entorno de servidor y IDE está listo, procedamos a crear nuestro primer proyecto Spring MVC. Los siguientes pasos son válidos tanto para STS como para Eclipse con complementos de STS.

Creando una aplicación Spring MVC en STS o Eclipse

Paso 1: Cree un Nuevo Proyecto Spring desde el menú. Paso 2: En la ventana del nuevo proyecto, dé el nombre como “SpringMVCExample” y elija la plantilla como “Proyecto Spring MVC”. Si está utilizando esta plantilla por primera vez, STS la descargará del sitio web de SpringSource. Si lo desea, puede agregar el proyecto a cualquier conjunto de trabajo. Paso 3: Cuando se haya descargado la plantilla, en la siguiente pantalla debe proporcionar el nombre del paquete de nivel superior. Este paquete se utilizará como el paquete base para los componentes de Spring. Paso 4: Una vez que el proyecto haya sido creado por la plantilla de Spring MVC, se verá como en la imagen de abajo. No se preocupe si no ve la clase User.java, ni los archivos login.jsp y user.jsp, los agregué más tarde. Si su proyecto no se ha compilado y ve algunos errores, ejecute Maven/Actualizar Proyecto. Asegúrese de marcar las opciones “Actualizar forzadamente Instantáneas/Liberaciones”, consulte la imagen a continuación. En general, el proyecto se ve como cualquier otra aplicación web basada en Maven con algunos archivos de configuración de Spring. Ahora es el momento de analizar las diferentes partes de los proyectos y extenderlo un poco.

Dependencias de Spring MVC

Nuestro archivo pom.xml generado se ve así debajo.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>SpringMVCExample</artifactId>
	<name>SpringMVCExample</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>4.0.0.RELEASE</org.springframework-version>
		<org.aspectj-version>1.7.4</org.aspectj-version>
		<org.slf4j-version>1.7.5</org.slf4j-version>
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>        
	</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

artifactId será el servlet-contexto para la aplicación web, así que puedes cambiarlo si deseas algo diferente. Hay algunas propiedades definidas para las versiones de Spring Framework, AspectJ y SLF4j; noté que no reflejaban las últimas versiones, así que las he cambiado a la versión estable más reciente hasta la fecha de hoy. Las dependencias del proyecto en las que estoy interesado son:

  • spring-context: Dependencia principal de Spring Core. Observa la exclusión de commons logging en favor de SLF4J.
  • spring-webmvc: Artefacto de Spring para soporte de MVC
  • aspectjrt: Referencia de la API de AspectJ
  • SLF4J y Log4j: Para fines de registro, Spring es muy fácil de configurar para log4j o API de Registro de Java gracias a la integración con SLF4J.
  • javax.inject – API JSR330 para inyección de dependencias

Hay algunas otras dependencias añadidas, como Servlet, JSP, JSTL y la API JUnit, pero para la aplicación inicial, podemos pasar por alto estas.

Tutorial de Spring MVC – Configuración de Log4j

El archivo log4j.xml generado se ve así.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="https://jakarta.apache.org/log4j/">

	<!-- Appenders -->
	<appender name="console" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p: %c - %m%n" />
		</layout>
	</appender>
	
	<!-- Application Loggers -->
	<logger name="com.journaldev.spring">
		<level value="info" />
	</logger>
	
	<!-- 3rdparty Loggers -->
	<logger name="org.springframework.core">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.beans">
		<level value="info" />
	</logger>
	
	<logger name="org.springframework.context">
		<level value="info" />
	</logger>

	<logger name="org.springframework.web">
		<level value="info" />
	</logger>

	<!-- Root Logger -->
	<root>
		<priority value="warn" />
		<appender-ref ref="console" />
	</root>
	
</log4j:configuration>

Observe que está imprimiendo todo en la consola, podemos agregar fácilmente dispositivos de salida para redirigir los registros a archivos.

Tutorial de Spring MVC – Configuración del Descriptor de Implementación

Vamos a ver nuestro web.xml y analizarlo.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

ContextLoaderListener vincula el ciclo de vida del ApplicationContext al ciclo de vida del ServletContext y automatiza la creación del ApplicationContext. El ApplicationContext es el lugar para los beans de Spring y podemos proporcionar su configuración a través del parámetro de contexto contextConfigLocation. El archivo root-context.xml proporciona los detalles de configuración para WebApplicationContext. DispatcherServlet es la clase controladora para la aplicación Spring MVC y todas las solicitudes del cliente son manejadas por este servlet. La configuración se carga desde el archivo servlet-context.xml.

Tutorial de Spring MVC – Archivos de Configuración

Archivo root-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components -->
		
</beans>

Aquí podemos definir beans compartidos, por ahora no hay nada en él. Código de servlet-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="https://www.springframework.org/schema/beans"
	xmlns:context="https://www.springframework.org/schema/context"
	xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="com.journaldev.spring" />	
	
</beans:beans>

Así es como se ve el archivo de configuración estándar de Spring, simplemente imagina escribir todo esto por tu cuenta y comenzarás a gustarte la herramienta STS. El elemento annotation-driven se utiliza para informar al servlet del Controlador que se utilizarán anotaciones para las configuraciones de bean. El elemento resources define la ubicación donde podemos poner archivos estáticos como imágenes, páginas HTML, etc., que no queremos que se gestionen a través del framework de Spring. InternalResourceViewResolver es el resolutor de vistas, podemos proporcionar la ubicación de las páginas de vista a través de las propiedades de prefijo y sufijo. Por lo tanto, todas nuestras páginas JSP deben estar en el directorio /WEB-INF/views/. El elemento context:component-scan se utiliza para proporcionar la ubicación del paquete base para escanear clases de Controlador. Recuerda el valor del paquete de nivel superior dado en el momento de la creación del proyecto, es el mismo valor que se está utilizando aquí.

Clase Controlador de Spring MVC

La clase HomeController se crea automáticamente con el método home(), aunque la he extendido un poco añadiendo los métodos loginPage() y login().

package com.journaldev.spring;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);
		
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
		
		String formattedDate = dateFormat.format(date);
		
		model.addAttribute("serverTime", formattedDate );
		
		return "home";
	}
	
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String loginPage(Locale locale, Model model) {
		return "login";
	}
	
	@RequestMapping(value = "/home", method = RequestMethod.POST)
	public String login(@Validated User user, Model model) {
		model.addAttribute("userName", user.getUserName());
		return "user";
	}
}

@Controller se utiliza como anotación para indicar que es una clase controladora web. @RequestMapping se usa con clases y métodos para redirigir la solicitud del cliente a un método controlador específico. Observa que los métodos controladores devuelven un String, que debe ser el nombre de la página de vista a utilizar como respuesta. Como puedes ver, tenemos tres métodos que devuelven cadenas diferentes, por lo que necesitamos crear páginas JSP con el mismo nombre. Observa que el método login() se llamará con el método HTTP POST, por lo que esperamos recibir datos de formulario aquí. Para esto, tenemos la clase modelo User, marcada para validación con la anotación @Validated. Cada método contiene Model como argumento y podemos establecer atributos para usar más tarde en las páginas de respuesta JSP.

Clases de Modelo de Spring MVC

Las clases de modelo se utilizan para almacenar variables de formulario, nuestro modelo User se ve así:

package com.journaldev.spring;

public class User {

	private String userName;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}
	
}

A simple java bean with the variable name and its getter and setter methods.

Tutorial de Spring MVC – Páginas de Vista

Tenemos tres páginas JSP como se muestra a continuación. Código de home.jsp:

<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
</head>
<body>
<h1>
	Hello world!  
</h1>

<P>  The time on the server is ${serverTime}. </P>
</body>
</html>

Observa el uso de Expresión de Lenguaje JSP para obtener los valores de atributo. Código de login.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login Page</title>
</head>
<body>
<form action="home" method="post">
<input type="text" name="userName"><br>
<input type="submit" value="Login">
</form>
</body>
</html>

A simple JSP page for the user to provide the userName as input. Notice that form variable name is same as User class variable name. Also, form action is “home” and method is “post”. It’s clear that HomeController login() method will handle this request. user.jsp code:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>User Home Page</title>
</head>
<body>
<h3>Hi ${userName}</h3>
</body>
</html>

Página de inicio simple para el usuario donde se muestra el nombre de usuario, observa que estamos configurando este atributo en el método de inicio de sesión.

Ejemplo de Aplicación de Spring MVC

Nuestra aplicación está lista para ejecutarse, simplemente ejecútela en el servidor VMware tc o en el contenedor de servlets de su elección. Obtendrá las siguientes páginas como respuesta. Eso es todo para el Tutorial de Spring MVC. Puede ver lo fácil que es crear una aplicación Spring MVC utilizando los complementos de STS. El tamaño del código es muy pequeño y la mayor parte de la configuración la maneja Spring MVC para que podamos centrarnos en la lógica empresarial. Descargue el proyecto de ejemplo de Spring MVC desde el siguiente enlace y juegue con él.

Descargar Proyecto Spring MVC

Source:
https://www.digitalocean.com/community/tutorials/spring-mvc-tutorial