Eclipse + Spring MVC + Maven + Tiles + External MySQL server + JSP
Tiempo total: 96 días con 23:18:10 hrs
En esta publicación explicaré como desarrollar una aplicación con el framework Spring MVC en el IDE Eclipse, utilizando Tiles (plantillas HTML). La aplicación usa MySQL, JSP y Maven… Hacer esta investigación me consumió varias horas, así que espero sea de ayuda.
Eclipse Oxigen
Puedes descargar el IDE en la siguiente dirección:
https://www.eclipse.org/downloads/
El instalador descargado fue eclipse-inst-win64.exe.
Java
Eclipse necesita Java 8 para funcionar, para descargarlo será necesario iniciar sesión en Oracle:
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
En mi caso descargué la versión x64 (dk-8u161-windows-x64.exe). Eclipse solicita la versión 7, pero desde ahí empezamos con el pie izquierdo porque aunque instales la versión 7 no funcionará, al final te terminará solicitando la versión 8.
Instalación de Eclipse
Seleccionamos “Eclipse IDE for Java EE Developers”, esta instalación nos permitirá trabajar con aplicaciones JSP que se ejecutarán en un servidor web (Tomcat en nuestro caso), esta versión instalará todo lo que necesitamos en nuestro entorno de desarrollo (casi todo).
Spring MVC
En Eclipse para poder trabajar con la plantilla de proyecto de Spring, buscamos “Spring STS (Spring Source Tool Suite)” en el menú Help, Eclipse MarketPlace. Entre los resultados, instalamos “Spring Tool (aka Spring IDE and Spring Tool suite) 3.9.3.RELEASE”.
Crear el proyecto Spring MVC
Después de instalar STS y reiniciar eclipse, nos vamos al menú File, New, Other… buscamos la carpeta de Spring y seleccionamos “Spring Legacy Project” en la siguiente ventana seleccionamos la plantilla “Spring MVC Project”. En esta publicación el nombre de mi proyecto será “ejemplo”.
El paquete que contendrá los archivos proyecto será “com.elconspirador.ejemplo”. Deberemos de esperar un par de minutos mientras se descarga lo necesario para empezar a trabajar.
Una vez ha finalizado la creación del proyecto, observaremos la siguiente estructura (para verla cerramos la pestaña de inicio de Eclipse):
Problemas iníciales
Eclipse nos muestra el siguiente error:
Archive for required library: ‘C:/Users/Jose/.m2/repository/org/springframework/spring-webmvc/3.1.1.RELEASE/spring-webmvc-3.1.1.RELEASE.jar’ in project ‘ejemplo’ cannot be read or is not a valid ZIP file
Algo que aprendí en mi investigación, por simplicidad, nunca eliminar la carpeta de dependencias de Maven “.m2”, varios blogs mencionan esto pero solo te provocará entrar en un relajo del cual ninguno te podrá salvar.
Para solucionar el actual problema, simplemente buscamos el archivo ‘spring-webmvc-3.1.1.RELEASE.jar’ en Google, lo descargamos y lo reemplazamos.
Una vez reemplazamos el archivo, reiniciamos eclipse… y encontramos el siguiente error: “RequestMapping cannot be resolved to a type” para solucionarlo debemos de agregar la dependencia “spring-web”.
Las dependencias las agregamos en el archivo pom.xml situado en la raíz de nuestro proyecto, al hacer doble clic nos mostrará un editor grafico, nosotros seleccionamos la pestaña “pom.xml” para poder observar el código del archivo.
En este archivo agregamos la dependencia:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework-version}</version> </dependency>
Después selecciona el proyecto en la parte izquierda y haz clic derecho, busca la opción del menú desplegable “Maven” y haz clic en el ítem “Update Project”.
Los problemas persisten
Como observarás, a pesar de saber cómo hacer la instalación y seguir las instrucciones más lógicas, los problemas siempre estarán presentes. El siguiente error ha aparecido:
Build path specifies execution environment JavaSE-1.6. There are no JREs installed in the workspace that are strictly compatible with this environment.
Para solucionar este error, realice varias cosas, empezando por cambiar la versión de java a utilizar en el archivo pom.xml:
<java-version>1.8</java-version>
Y cambiando la versión JRE de Java haciendo clic derecho en el proyecto, propiedades, Java build Path. En la pestaña “Libraries” he eliminado Jave-SE-1.6 y he agregado la versión que tengo instalada en Add Library, JRE System Library y Workspace default JRE (jre.1.8.0_161).
Luego, instalé Java Runtine Enviroment de la siguiente página (el archivo que instalé fue jre-8u161-windows-x64.exe)
http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html
Ok se que esto es un gran relajo, pero calma! No saldremos a la luz pero si estaremos avanzando unos cuantos pasillos en este tutorial. Lo siguiente que edité fue “Project facets”, está opción la encuentras al hacer clic derecho en la carpeta del proyecto (en Project explorer, parte izquierda de la ventana de Eclipse), y seleccionamos la versión 1.8 de java.
En la ventana de propiedades de nuestro projecto, también nos aseguramos que la opción “Java compiler” tenga seleccionada la versión 1.8 de java.
Para finalizar, el error “RequestMapping cannot be resolved to a type” persistía, así que descargué el archivo .jar del repositorio Maven en internet y lo reemplacé en mi sistema de archivos:
URL descarga:
https://mvnrepository.com/artifact/org.springframework/spring-web/3.1.1.RELEASE
Dirección a reemplazar en mi computadora:
C:\Users\Jose\.m2\repository\org\springframework\spring-web\3.1.1.RELEASE
Último problema
Esto parece más un tutorial de cómo encontrar los problemas más ilógicos en Eclipse IDE, el siguiente problema que he encontrado es:
Error occured processing XML ‘Unable to load schema mappings from location [META-INF/spring.schemas]’. See Error Log for more details
Archivos del error: servlet-context y root-context. Para solucionar esto, en el archivo pom.xml cambiamos la versión de 3.1.1.RELEASE a 3.2.2.RELEASE:
<org.springframework-version>3.2.2.RELEASE</org.springframework-version>
Dependencias de nuestro proyecto
Las dependencias que vamos a usar son las siguientes (las agregamos a nuestro archivo pom.xml):
<!-- Spring JDBC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework-version}</version> </dependency> <!-- MySQL database driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> <!-- tiles --> <dependency> <groupId>org.apache.tiles</groupId> <artifactId>tiles-core</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>org.apache.tiles</groupId> <artifactId>tiles-api</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>org.apache.tiles</groupId> <artifactId>tiles-servlet</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>org.apache.tiles</groupId> <artifactId>tiles-jsp</artifactId> <version>2.1.2</version> </dependency> <!-- validation --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <!-- hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.3.1.Final</version> </dependency>
Javax.validation nos permite utilizar expresiones regulares para validar la información que guardaremos en la DB. Hibernate contiene funciones de validación que serán de utilidad en el proyecto, por ejemplo, validación de correo electrónico.
Base de datos MySQL
MySQL la tengo instalada en un servidor Ubuntu, en una maquina virtual. Utilicé el editor HeidiSQL para crear la base de datos “ejemplo” con la siguiente tabla:
CREATE TABLE usuario ( id BIGINT(20) unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT, correo varchar(254) DEFAULT '', password VARCHAR(100) NOT NULL, rol VARCHAR(50) DEFAULT 'usuario', creacion TIMESTAMP DEFAULT CURRENT_TIMESTAMP )ENGINE=INNODB; ALTER TABLE usuario ADD UNIQUE INDEX usuario_correo (correo); /* elconspirador */ INSERT INTO usuario (correo, password, rol) VALUES ('josedalvik@gmail.com', '09ab5f442a52f2f9e297c7731c4220f5648e6c32a23ec14b7f3b72da762bbcb3', 'admin');
Entidad Usuario
La entidad Usuario almacenará los registros de la tabla Usuario, para ordenar los archivos, colocaré todas las entidades en una carpeta llamada entity:
Project explorer, ejemplo (nombre del proyecto), src, main, java, (com, elconspirador, ejemplo) {es el nombre del paquete} hacemos clic derecho y agregamos la carpeta “entity”.
Ahora, en el paquete que hemos agregado, hacemos clic derecho y agregamos Usuario.java.
Entidad Usuario
package com.elconspirador.ejemplo.entity; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.Email; public class Usuario { private int id; @Email(message="Formato de correo no valido") @Size(min = 1, max = 254, message="Rango permitido de 1 a 254 caracteres") private String correo; @Size(min = 1, max = 100, message="Rango permitido de 1 a 100 caracteres") private String password; @Size(min = 1, max = 50, message="Rango permitido de 1 a 50 caracteres") private String rol; private String creacion; }
Para agregar los getters y setters, en el menú superior seleccionamos “Source” y hacemos clic en “Generate getters and setters”. Las validaciones las agregamos en las variables que creamos convenientes.
Objeto de acceso a los datos DAO
Ahora que tenemos la entidad Usuario, necesitamos una clase que nos permita hacer operaciones en la base de datos, para seguir con el orden agregamos otra carpeta que se llame “dao” y agregamos la clase “UsuarioDao.java”.
package com.elconspirador.ejemplo.dao; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import com.elconspirador.ejemplo.entity.Usuario; public class UsuarioDao { JdbcTemplate model; public void setTemplate(JdbcTemplate model) { this.model = model; } public Usuario login(String correo, String password) { String sql = "SELECT * FROM usuario WHERE correo = ? AND password = ?;"; try { return model.queryForObject(sql, new Object[] { correo, password }, new BeanPropertyRowMapper<Usuario>(Usuario.class)); }catch(Exception e) { return null; } } }
Conexión DAO y MySQL
Hasta ahora observamos como DAO utiliza la entidad para poder hacer operaciones en la base de datos, ¿pero como hace la conexión DAO con MySQL?
La conexión, la relación entre la clase DAO y la base de datos se establece en el archivo ejemplo, src, main, webapp, WEB-INF, spring, root-context.xml
<?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.xsd"> <!-- Root Context: defines shared resources visible to all other web components --> <bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://192.168.56.101:3306/ejemplo" /> <property name="username" value="xxxxxx" /> <property name="password" value="yyyyy" /> </bean> <bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="ds"></property> </bean> <bean id="model_usuario" class="com.elconspirador.ejemplo.dao.UsuarioDao"> <property name="template" ref="jt"></property> </bean> </beans>
De primero observamos cómo se realiza la conexión, después cómo se establece la plantilla JdbcTemplate y por último cómo se relaciona la clase DAO con la plantilla JdbcTemplate.
Ordenando el controlador
Antes de manipular el controlador, agregamos a nuestro paquete Java la carpeta “controller” y agregamos la clase HomeController.java dentro de la misma.
Apache Tiles
Antes de hacer una operación con la base de datos, vamos a utilizar plantillas HTML.
Plantillas HTML: header y footer
Agregamos la carpeta “plantilla” en la carpeta “views”, dentro colocaremos nuestros archivos cabecera y pie de página.
El código para el archivo header.jsp es el siguiente:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <title>Aplicación de prueba</title> <!-- Bootstrap Core CSS --> <link href="${pageContext.request.contextPath}/css/css.css" rel="stylesheet"> <!-- Bootstrap Core CSS --> <link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet"> <!-- MetisMenu CSS --> <link href="${pageContext.request.contextPath}/css/metisMenu.min.css" rel="stylesheet"> <!-- Custom CSS --> <link href="${pageContext.request.contextPath}/css/sb-admin-2.css" rel="stylesheet"> <!-- Custom Fonts --> <link href="${pageContext.request.contextPath}/css/font-awesome.min.css" rel="stylesheet" type="text/css"> <!-- Datatables --> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/dataTables.bootstrap.css" type="text/css"> <link rel="stylesheet" href="${pageContext.request.contextPath}/css/dataTables.responsive.css" type="text/css"> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> <![endif]--> </head> <body>
El código para el archivo footer.jsp es el siguiente:
<!-- jQuery --> <script src="${pageContext.request.contextPath}/js/jquery.min.js" type="text/javascript" ></script> <!-- Bootstrap Core JavaScript --> <script src="${pageContext.request.contextPath}/js/bootstrap.min.js" type="text/javascript" ></script> <!-- Metis Menu Plugin JavaScript --> <script src="${pageContext.request.contextPath}/js/metisMenu.min.js" type="text/javascript" ></script> <!-- Custom Theme JavaScript --> <script src="${pageContext.request.contextPath}/js/sb-admin-2.js" type="text/javascript" ></script> <!-- Datatables --> <script src="${pageContext.request.contextPath}/js/jquery.dataTables.min.js" type="text/javascript" ></script> <script src="${pageContext.request.contextPath}/js/dataTables.bootstrap.min.js" type="text/javascript" ></script> <script src="${pageContext.request.contextPath}/js/dataTables.responsive.js" type="text/javascript" ></script> <!-- js --> <script src="${pageContext.request.contextPath}/js/js.js"></script> </body> </html>
Seguramente hasta ahora has observado tres cosas:
- La variable pageContext.request.contextPath es la URL de nuestra aplicación.
- ${variable} en PHP es el equivalente a utilizar <?=$variable?>
- Si! en este ejemplo utilizaremos la plantilla sb-admin2 de bootstrap.
Donde copiamos los archivos JS y CSS?
Los archivos de estilo, javascript, fuentes e imágenes las agregamos en la carpeta resources:
Explorador del proyecto, ejemplo, src, main, webapp, resources
Para hacer esto posible, debemos de modificar el archivo: Explorador del proyecto, ejemplo, src, main, webapp, WEB-INF, spring, appServlet, servlet-context. La siguiente línea debe quedar así:
<resources mapping="/**" location="/resources/" />
Archivo tiles.xml
A continuación creamos el archivo tiles.xml en Explorador del proyecto, ejemplo, src, main, webapp, WEB-INF. Debe de estar junto al archivo web.xml. El contenido de este archivo debe de ser el siguiente:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN" "http://tiles.apache.org/dtds/tiles-config_2_0.dtd"> <tiles-definitions> <definition name="plantilla " template="/WEB-INF/views/plantilla/layout.jsp"> <put-attribute name="header" value="/WEB-INF/views/plantilla/header.jsp" /> <put-attribute name="body" value="" /> <put-attribute name="footer" value="/WEB-INF/views/plantilla/footer.jsp" /> </definition> <definition name="home" extends="plantilla "> <put-attribute name="body" value="/WEB-INF/views/home.jsp" /> </definition> </tiles-definitions>
Observemos las cosas en orden, en el archivo XML se definen dos objetos: plantilla y home. La definición plantilla es el archivo layout.jsp (que todavía NO hemos creado), a este archivo le envía tres atributos: header, body y footer.
La definición home (utilizado por nuestro controlador HomeController) extiende el objeto “plantilla” y a este objeto le envía el atributo “body” con el valor home.jsp.
Ok, entonces nuestro coeficiente intelectual nos ha hecho entender: plantilla define los atributos por defecto y cada nueva definición podrá cambiar el atributo body.
Agregando tiles.xml a nuestro proyecto
Para registrar la configuración de tiles.xml en nuestro proyecto, editamos el archivo servlet-context, ubicado en: explorador de proyectos, ejemplo, src, main, webapp, WEB-INF, spring, appServlet.
A servlet-context le agregamos el siguiente código XML:
<beans:bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <beans:property name="viewClass"> <beans:value> org.springframework.web.servlet.view.tiles2.TilesView </beans:value> </beans:property> </beans:bean> <beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"> <beans:property name="definitions"> <beans:list> <beans:value>/WEB-INF/tiles.xml</beans:value> </beans:list> </beans:property> </beans:bean>
Servlet-context.xml
Para resumir, este archivo quedará de la siguiente manera:
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://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="/**" location="/resources/" /> <!-- Tiles --> <beans:bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <beans:property name="viewClass"> <beans:value> org.springframework.web.servlet.view.tiles2.TilesView </beans:value> </beans:property> </beans:bean> <beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"> <beans:property name="definitions"> <beans:list> <beans:value>/WEB-INF/tiles.xml</beans:value> </beans:list> </beans:property> </beans:bean> <!-- 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.elconspirador.ejemplo" /> </beans:beans>
Layout.jsp
Su funcionamiento es muy básico, deja que el archivo tiles.xml defina los valores a imprimir:
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%> <tiles:insertAttribute name="header" /> <tiles:insertAttribute name="body" /> <tiles:insertAttribute name="footer" />
Home.jsp
Esta es la vista utilizada por HomeController.java, aquí utilizamos el tag Form de Spring, esto permite enviar entidades a un formulario y mostrar sus valores en los campos HTML:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="true" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <div class="login-panel panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">Inicio de sesión</h3> </div> <div class="panel-body"> <form:form method="POST" action="login" modelAttribute="usuario"> <fieldset> <div class="form-group"> <form:input cssClass="form-control" path="correo" /> <form:errors element="div" path="correo" cssClass="alert alert-danger" /> </div> <div class="form-group"> <form:password cssClass="form-control" path="password" /> <form:errors element="div" path="password" cssClass="alert alert-danger" /> </div> <input type="submit" class="btn btn-lg btn-success btn-block" value="Iniciar sesión" /> </fieldset> <c:choose> <c:when test="${error==1}"> <div class="alert alert-danger"> Completa correctamente el formulario. </div> </c:when> <c:when test="${error==2}"> <div class="alert alert-danger"> Datos de acceso incorrectos. </div> </c:when> <c:when test="${error==3}"> <div class="alert alert-danger"> Ha sucedido un error, por favor intentalo de nuevo. </div> </c:when> </c:choose> </form:form> </div> </div> </div> </div> </div>
La variable error utiliza la instrucción <c:when test=”${condición}”></c:when>, la cual funciona gracias al tag c de Spring. Las clases y estilos CSS utilizadas en esta vista son propias de la plantilla Sb-admin2 de Bootstrap. El tag form de Spring es muy limitado, así que debemos de sacrificar algunas propiedades HTML y CSS para hacerlo funcionar.
HomeController.java, mostrando un simple formulario
Hasta ahora no utilizaremos la conexión MySQL, solo mostraremos un formulario HTML en la aplicación:
package com.elconspirador.ejemplo.controller; import java.util.Locale; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.elconspirador.ejemplo.entity.Usuario; /** * Handles requests for the application home page. */ @Controller public class HomeController { /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model, Usuario usuario) { model.addAttribute("error", 0); model.addAttribute("usuario", usuario); return "home"; } }
En la función home, observamos la entidad Usuario, esto permite inicializar el formulario con sus valores por defecto.
Para ver el ejemplo que tenemos hasta ahora, corremos la aplicación y seleccionamos Tomcat v8.0 en la categoría Apache. Al hacer clic en siguiente, seleccionamos “Download and install”. La ubicación del servidor, para mantener las cosas en orden recomiendo hacerla en el actual workspace utilizado: C:\Users\Jose\eclipse-workspace\Apache
Al finalizar, simplemente abrimos nuestro navegador web y escribimos http://localhost:8080/ejemplo
Eclipse IDE de nuevo nos muestra errores
Al momento de correr la aplicación, nos mostró el siguiente error:
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file HomeController.class; nested exception is org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file – probably due to a new Java class file version that isn’t supported yet
Buscando en la web, encontré que Spring 3.2.2.RELEASE no es compatible con Java 1.8, así que cambié la versión en el archivo pom.xml a Spring 3.2.9.RELEASE:
<org.springframework-version>3.2.9.RELEASE</org.springframework-version>
Esto soluciona el problema.
Nota: al hacer algún cambio en los archivos XML, deberemos detener el servidor, usar la opción clean, y luego lo volvemos a iniciar.
Resultado final de la vista home
Es un formulario de inicio de sesión:
Realizando una consulta en la base de datos
En el formulario de inicio observamos que las variables del formulario son enviadas utilizando el método Post a la página “login”, entonces, en el archivo HomeController.java agregamos la siguiente función:
@RequestMapping(value = "login", method = RequestMethod.POST) public String login(Locale locale, Model model, HttpServletRequest request, @Valid @ModelAttribute("usuario") Usuario usuario, BindingResult bindingResult, HttpServletResponse response) { model.addAttribute("error", 0); if (bindingResult.hasErrors()) { model.addAttribute("error", 1); }else { Usuario login = model_usuario.login(usuario.getCorreo(), tools.sha256(usuario.getPassword())); if(login!=null) { String token = "Nuestra propia implementación de tokens"; request.getSession().setAttribute("token", token); try { response.sendRedirect("login_correcto"); }catch(Exception e) { model.addAttribute("error", 3); } }else { model.addAttribute("error", 2); } } return "home"; }
Básicamente esta función, recibe las variables del formulario en la siguiente variable:
@Valid @ModelAttribute(“usuario”) Usuario usuario
La anotación @Valid indica que los valores deben de cumplir con las validaciones que establecimos en Usuario.java, los resultados de dicha validación se pasan a:
BindingResult bindingResult
Por tal motivo, utilizamos el if para verificar que no tenga errores (o alguna inyección de código), de esta manera, podemos validar su usuario y contraseña para poder iniciar sesión y establecer el token.
Las importaciones extras que necesita HomeController son las siguientes:
import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.validation.BindingResult; import com.elconspirador.ejemplo.dao.UsuarioDao; import com.elconspirador.ejemplo.entity.Usuario; import com.elconspirador.ejemplo.library.Tools;
Las definiciones de variables globales de la clase son las siguientes:
@Autowired
UsuarioDao model_usuario;
Tools tools = new Tools();
Tambien observamos la clase Tools, de acuerdo a la implementación de cada uno, agregaremos las funciones utilizadas en distintas partes de la aplicación.
Tools.java
package com.elconspirador.ejemplo.library; import java.security.MessageDigest; public class Tools { public static String sha256(String base) { try{ MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(base.getBytes("UTF-8")); StringBuffer hexString = new StringBuffer(); for (int i = 0; i < hash.length; i++) { String hex = Integer.toHexString(0xff & hash[i]); if(hex.length() == 1) hexString.append('0'); hexString.append(hex); } return hexString.toString(); } catch(Exception ex){ throw new RuntimeException(ex); } } }
HomeController.java final
Para finalizar, la clase HomeController.java completa es la siguiente:
package com.elconspirador.ejemplo.controller; import java.util.Locale; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.elconspirador.ejemplo.entity.Usuario; import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.validation.BindingResult; import com.elconspirador.ejemplo.dao.UsuarioDao; import com.elconspirador.ejemplo.entity.Usuario; import com.elconspirador.ejemplo.library.Tools; /** * Handles requests for the application home page. */ @Controller public class HomeController { @Autowired UsuarioDao model_usuario; Tools tools = new Tools(); /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model, Usuario usuario) { model.addAttribute("error", 0); model.addAttribute("usuario", usuario); return "home"; } @RequestMapping(value = "login", method = RequestMethod.POST) public String login(Locale locale, Model model, HttpServletRequest request, @Valid @ModelAttribute("usuario") Usuario usuario, BindingResult bindingResult, HttpServletResponse response) { model.addAttribute("error", 0); if (bindingResult.hasErrors()) { model.addAttribute("error", 1); }else { Usuario login = model_usuario.login(usuario.getCorreo(), tools.sha256(usuario.getPassword())); if(login!=null) { String token = "Nuestra propia implementación de tokens"; request.getSession().setAttribute("token", token); try { response.sendRedirect("login_correcto"); }catch(Exception e) { model.addAttribute("error", 3); } }else { model.addAttribute("error", 2); } } return "home"; } }
Validación en acción
Esto sucede al enviar el formulario con los campos vacios:
Datos incorrectos
Al enviar datos incorrectos, muestra un mensaje de error (valida la información en la base de datos correctamente):
Login correcto
Al ingresar los datos correctos, nos redireccionará a la página login_correcto.
Listo! ahora puedes realizar proyectos con Eclipse + Spring MVC + Maven + Tiles + External MySQL server + JSP y algunas otras tecnologías.