Spring Framework ... Spring MVC

¿Qué es Spring Framework?

Es un marco de trabajo que se apoya en algunos estándares Java EE para el desarrollo de aplicaciones y contenedor de inversión de control. Nos permite, entre otras cosas, crear aplicaciones web, servicios REST, persistencia de bases de datos relacionales y no relacionales, etc. En este post hablaremos de Spring MVC, el cual es un marco de trabajo que nos permite crear aplicaciones web con la arquitectura MVC.

Arquitectura Modelo-Vista-Controlador (Model-View-Control)

Esta arquitectura se compone de tres principales conceptos:

  • A. Modelo: Objetos Java.
  • B. Vista: Plantilla que genera la HTML.
  • C. Controlador: Controlador que atiende las peticiones HTTP que llegan al servidor desde el navegador; si resuelve la petición, devuelve una respuesta, en este caso la página HTML.

Supongamos que un cliente quiere saber el estado actual de sus movimientos bancarios.

  1. El cliente hace una solicitud al servidor.
  2. El servidor atiende esa solicitud, verifica si puede atenderla y en caso afirmativo prepara un objeto.
  3. Ese objeto contiene los datos solicitados y con eso el controlador genera una vista (HTML) que verá el cliente en su pantalla.

¿Por qué usar Spring MVC en vez de otras tecnologías (EJB)?
Eso es cuestión de enfoques y necesidades del desarrollador (o jefes del desarrollador).

¿Qué necesito saber para aprender Spring MVC?
Comprender la lógica de la programación (principalmente la orientada a objetos). Entender qué son los patrones de diseño (IoC= Inversión de Control) y comprender como funciona el protocolo HTTP y los métodos GET y POST. Y un sinfín de cosas más.

¿Qué herramientas necesito para comenzar?
Por el momento dos cosas:

  1. Un editor de textos
  2. Descargar e instalar Gradle

Comencemos. Crearemos un proyecto llamado Test. Con la siguiente estructura de directorios:

Test/src/main/java
Test/src/main/resources

Carpeta src/main/java

src/main/java/com/codemonkey/Application.java
src/main/java/com/codemonkey/model/Usuario.java
src/main/java/com/codemonkey/controller/ControllerUsuario.java

Carpeta src/main/resources

src/main/resources/templates
src/main/resources/static
src/main/resources/application.properties
src/main/resources/banners.txt

Para descargar e instalar Gradle podemos usar SKDMAN!
$ sdk install gradle

Una vez instalado crearemos un archivo *.gradle. Este archivo contendrá las dependencias necesarias para crear nuestro ejemplo (disculpen si no lo describo detalladamente).

build.gradle

/**
*
*
*@description Ejemplo  
*@version 1.1.0
*
*
*
* 1. Construir proyecto: gradle build
* 2. Ver tareas disponibles: gradle task
* 3. Ejecutar: gradle run ó gradle bootRun
*/

buildscript {

        ext {
                springBootVersion = '1.5.6.RELEASE'
        }

        repositories {
                mavenCentral()
                maven {
                        url "https://plugins.gradle.org/m2/"
                }
        }
        dependencies {
                classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        }
}

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
apply plugin: 'project-report'
apply plugin: 'org.springframework.boot'

version = '1.0.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
mainClassName = "com.codemonkey.Application"
description ="""
Ejemplo de proyecto hecho con Gradle build
 
"""

jar {

        baseName='principal'

        manifest{
                attributes 'Main-Class': 'com.codemonkey.Application'
        }
}

repositories {
        mavenCentral()
}

dependencies {
        compile('org.springframework.boot:spring-boot-starter')
        compile group: 'org.projectlombok', name: 'lombok', version: '1.16.16'
        testCompile('org.springframework.boot:spring-boot-starter-test')
        compile('org.springframework.boot:spring-boot-starter-mustache')
        compile('org.springframework.boot:spring-boot-starter-web')
       
}

configurations.all {
    resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
}

//Ver dependencias
project.configurations.compile.resolvedConfiguration.resolvedArtifacts.each {
 println '   [Dependencias] '
 println 'artifact: '+it.name // << the artifact name
 println 'referencia: '+it.file // << the file reference
 println '**************************'
}

Ejemplo. Crearemos un servicio REST sencillo con las clases Usuario y Area.

  1. Clase principal: Application.java
  2. Clase Usuario.java
  3. Clase Area.java
  4. Controlador ControllerUsuario.java

Application.java

package com.codemonkey;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

        public static void main(String[] args) {
                SpringApplication.run(Application.class, args);
        }
   
}

Usuario.java

package com.codemonkey.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;
import lombok.Getter;
 
@Data
@AllArgsConstructor
public class Usuario{
  @Getter @Setter private int id;
  @Getter @Setter private String nombre_usuario;
  @Getter @Setter private String password;
  @Getter @Setter private boolean logeado;
  @Getter @Setter private Area area;
}

Area.java

package com.codemonkey.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;
import lombok.Getter;
 
@Data
@AllArgsConstructor
public class Area {
        @Getter @Setter private int id;
        @Getter @Setter private String responsable_area;
        @Getter @Setter private int piso;
}

Como pueden notar nos ayudamos de Lombok para generar los getter y setter de ambas clases.

ControllerUsuario.java

package com.codemonkey.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Date;

import com.codemonkey.model.Usuario;
import com.codemonkey.model.Area;

@RestController
@RequestMapping("/nodo")
public class ControllerUsuario {

    //http://127.0.0.1:8080/nodo/usuarios
    @RequestMapping("/usuarios")
    public List<Usuario> getUsuarios(){
        List<Usuario> listaUsuario = new ArrayList<Usuario>();
        listaUsuario.add(new Usuario(1, "Sr. Negativo", "1234", true, new Area(1, "sistemas",10)));
        listaUsuario.add(new Usuario(2, "OscarRyz", "ryz123", false, new Area(2, "informatica",12)));
        listaUsuario.add(new Usuario(3, "Benek", "secreta", true, new Area(3, "manager",9)));
        return listaUsuario;
    }

}

Construimos el proyecto:

$ gradle build

Ejecutamos:

$ gradle bootRun

Abrimos cualquier navegador en la siguiente dirección:
http://127.0.0.1:8080/nodo/usuarios

Cabecera de la respuesta

Content-Type application/json;charset=UTF-8
Date Sun, 13 Aug 2017 02:19:22 GMT
Transfer-Encoding chunked

Cabeceras de la petición

Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Host 127.0.0.1:8080
Upgrade-Insecure-Requests 1
User-Agent Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0

Datos obtenidos:

[{"id":1,"nombre_usuario":"Sr. Negativo","password":"1234","logeado":true,"area":{"id":1,"responsable_area":"sistemas","piso":10}
},
{"id":2,"nombre_usuario":"OscarRyz","password":"ryz123","logeado":false,"area":{"id":2,"responsable_area":"informatica","piso":12}
},
{"id":3,"nombre_usuario":"Benek","password":"secreta","logeado":true,"area":{"id":3,"responsable_area":"manager","piso":9}}
]

Nota: Firefox muestra mejor esos datos.