Introducción a Spring Boot: Aplicación Web con Spring Data JPA

logo springEn el tutorial Persistencia en BD con Spring: Integrando JPA, c3p0, Hibernate y EHCache, vimos de forma práctica los pasos a seguir para configurar una aplicación Maven que integre Spring con JPA, utilizando Hibernate como implementación. No es difícil, pero resulta tedioso tener que replicar esta configuración cada vez que empecemos un proyecto nuevo y la configuración puede complicarse si por ejemplo vamos a desarrollar un proyecto web completo y necesitamos también utilizar otros módulos de Spring tales como MVC, Data, Security, etc. Esto lleva a que en la práctica numerosos programadores y empresas recurran a la creación de plantillas genéricas, por ejemplo en la forma de arquetipos Maven, que eviten tener que invertir tiempo en la creación y configuración de los nuevos proyectos desde cero (aunque esto conlleva el problema adicional de tener que mantener actualizadas dichas plantillas). Otra opción es utilizar plantillas de terceros disponibles en GitHub como por ejemplo las indexadas en yeoman, o irnos directamente a frameworks basados en Spring como JHipster aunque aquí ya entramos en el terreno de los generadores de código.

Teniendo en cuanta esta problemática, allá por 2014 se publicó la primera versión estable de Spring Boot, un módulo que pretende solucionar estos problemas y acelerar el desarrollo de aplicaciones basadas en Spring gracias a una gestión automatizada de la infraestructura software que necesitamos en nuestra aplicación. En concreto: “Spring Boot proporciona una manera rápida de construir aplicaciones. Inspecciona el classpath y los beans que tengas configurado, hace asunciones razonables sobre lo que te falta y lo añade. Con Spring Boot puedes centrarte más en la lógica de negocio y menos en la infraestructura”.

Master Pyhton, Java, Scala or Ruby

Hay que tener presente que Spring Boot no es un framework al uso ni un generador de código, se centra en la configuración e integración de las dependencias que solemos necesitar de forma genérica para que sin ningún esfuerzo empecemos directamente a desarrollar nuestra aplicación. Incluso configura de forma embebida un servidor Tomcat o Jetty si así lo deseamos. Y lo mejor de todo es que no supone una limitación ya que podemos seguir realizando cualquier configuración de igual forma que si no tuviéramos Spring Boot.

En este tutorial daremos los primeros pasos para empezar a utilizar Spring Boot en nuestros proyectos. En concreto, crearemos una aplicación web con una simple pantalla que muestre un listado de datos obtenido desde una tabla de una base de datos MySQL. Se asume que el lector tiene conocimientos, a nivel muy básico, de Maven, Spring Data JPA y Spring MVC.

Creando un proyecto con Spring Boot para Spring Data JPA

Vamos a crear y configurar un proyecto Maven con Spring Boot análogo al de los tutoriales de Spring Data JPA. Como es habitual, empezamos configurando el pom.xml con las dependencias que necesitamos, y aquí viene la primera ventaja de adoptar Spring Boot: no definiremos como dependencias directamente los módulos de Spring necesarios (web, orm, security) sino una suerte de “metadependencias” (starters) de Spring Boot que incluyen todo lo necesario. Para ello añadimos lo siguiente al pom.xml:

  1. Utilizar Spring Boot como módulo padre de nuestro proyecto. Usaremos Spring Boot 1 para Spring 4 y Spring Boot 2 para Spring 5.
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>1.5.10.RELEASE</version>
    		<relativePath />
    	</parent>
    
    

    Nota: si no queremos o podemos utilizar Spring Boot como proyecto padre, consultar la configuración alternativa.

  2. Añadir todos los metamódulos (starters) de Spring Boot que encapsulen las funcionalidades que necesitemos. Los starters disponibles se pueden consultar directamente en GitHub en este enlace. En nuestro caso, para utilizar Spring Data JPA con Hibernate necesitaremos el siguiente:
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
  3. Adicionalmente también necesitamos el driver JDBC.
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    
  4. Opcionalmente se puede utilizar el plugin de Maven de Spring Boot que proporciona algunos “goals” interesantes para ejecutar y empaquetar nuestras aplicaciones.
    <build>
    	<plugins>
    		<plugin>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-maven-plugin</artifactId>
    		</plugin>
    	</plugins>
    </build>
    

Spring Boot utiliza Logback, pero acostumbro a utilizar Log4j en mis proyectos. Para hacer este cambio, es necesario incluir el starter spring-boot-starter-log4j y excluir spring-boot-starter-logging de los otros starters de los que sea dependencia

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
    </exclusion>
  </exclusions>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-log4j</artifactId>
  <version>1.3.8.RELEASE</version>
</dependency>

El pom final queda así

<?xml version="1.0" encoding="UTF-8"?>
<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.danielme.demo</groupId>
	<artifactId>spring-boot</artifactId>
	<version>1.0</version>
	<packaging>jar</packaging>

	<name>spring-boot-demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<relativePath />
	</parent>
l
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>

		<mysql.version>5.1.33</mysql.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j</artifactId>
			<version>1.3.8.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>


	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

Con el comando mvn dependency:list podemos comprobar todas las librerías que tenemos en nuestro proyecto.

Ahora tenemos que definir los parámetros de configuración de nuestra aplicación. Spring Boot los lee por defecto del fichero /src/main/resources/application.properties o /src/main/resources/application.yaml y en este listado encontramos los más habituales aunque no se incluyen los de todas las librerías con las Spring Boot se integra de forma automática.

Para nuestro ejemplo necesitamos como mínimo la url de conexión a la base de datos y las credenciales. Adicionalmente establecemos también el modo DDL de Hibernate, que por defecto es none, a update para que se sincronicen nuestras entidades JPA con las tablas de la base de datos (¡No usar esto en producción!).

spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=demo
spring.datasource.password=demo
spring.jpa.hibernate.ddl-auto=update

Vamos a añadir una entidad de JPA y su repositorio de JPA.

package com.danielme.springboot.entities;

import java.util.Calendar;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@EntityListeners({ AuditingEntityListener.class })
@MappedSuperclass
public class AuditableEntity {
	@CreatedDate
	@Temporal(TemporalType.TIMESTAMP)
	private Calendar createdDate;

	@LastModifiedDate
	@Temporal(TemporalType.TIMESTAMP)
	private Calendar lastModifiedDate;

	@CreatedBy
	private String createBy;

	@LastModifiedBy
	private String lastModifiedBy;

	getter y setters...

package com.danielme.springboot.entities;

import java.util.Calendar;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "countries")
public class Country extends AuditableEntity
{
	 @Id
	 @GeneratedValue(strategy = GenerationType.IDENTITY)
	 private Long id;
	 
	 @Column(nullable = false, unique=true)
	 private String name;
	 
	 @Column(nullable = false)
	 private Integer population;
	 
	 @Column(updatable = false, nullable = false)
	 @Temporal(TemporalType.TIMESTAMP)
	 private Calendar creation;
	 
	 public Country()
	 {
		super();
	 }

	public Country(String name, Integer population)
	{
		super();
		this.name = name;
		this.population = population;
	}
	
	 @PrePersist
	 public void onPersist()
	 {
		 creation = Calendar.getInstance();
	 }
...getters y setters

package com.danielme.springboot.repositories;

import org.springframework.data.jpa.repository.JpaRepository;

import com.danielme.springboot.entities.Country;

public interface CountryRepository extends JpaRepository<Country, Long>{

}

Antes de continuar construyendo nuestra aplicación web, vamos a ver cómo ejecutar el proyecto utilizando una clase con una un método main. Para hacer que Spring Boot configure Spring anotamos esta la clase con @SpringBootApplication que aplica las funcionalidades proporcionadas por @Configuration, @EnableAutoConfiguration, @ComponentScan y @EnableWebMvc (esta última si tenemos Spring MVC en el classpath). En el método main lanzamos la aplicación de forma estática con el método run. Para ejecutar código en el arranque pero después de la iniciación de Spring, implementamos la interfaz CommandLineRunner.

package com.danielme.springboot;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.danielme.springboot.repositories.CountryRepository;

@SpringBootApplication
public class DemoApp implements CommandLineRunner {

	private static final Logger logger = Logger.getLogger(DemoApp.class);
	
	@Autowired
	CountryRepository countryRepository;
	
	public static void main(String[] args) {
		SpringApplication.run(DemoApp.class, args);
	}

	@Override
	public void run(String... arg0) throws Exception {
		logger.info(countryRepository.count());		
	}	

}

Ahora ejecutamos el método main como cualquier proyecto Maven y comprobamos el log.

También podemos utilizar el plugin de Maven para empaquetar toda la aplicación en un jar ejecutable sin tener que realizar ninguna acción adicional utilizando el siguiente comando.

mvn package spring-boot:repackage

Pool de conexiones

Por defecto el starter que estamos utilizando emplea como implementación de DataSource la de Tomcat( org.apache.tomcat.jdbc.pool.DataSource), pero para producción es recomendable utilizar un pool de conexiones más potente como HikariCP, totalmente compatible con Spring Boot. Para usarlo incluimos su dependencia en el pom, por ejemplo:

<dependency>
  <groupId>com.zaxxer</groupId>
  <artifactId>HikariCP</artifactId>
</dependency>

Y lo habilitamos añadiendo la siguiente línea al application.properties.

spring.datasource.type: com.zaxxer.hikari.HikariDataSource

Los parámetros de Hikari a configurar se definen en este mismo fichero con el prefijo spring.datasource.hikari, por ejemplo:

spring.datasource.hikari.maximum-pool-size: 10

Aplicación web

Convirtamos nuestro ejemplo en una aplicación web con Spring MVC que muestre el listado de países que tengamos en la base de datos siguiendo los siguientes pasos.

  1. Añadimos el starter spring-boot-starter-web. Vamos a utilizar JSP para renderizar la vista de forma dinámica, pero si hiciéramos uso de alguno de los motores de plantillas compatibles con Spring Boot (Thymelef, FreeMarker, Mustache, Velocity, Groovy Templates) tendríamos que incluir el starter correspondiente y en este caso ya no es necesario el spring-boot-starter-web.
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  2. Al utilizarse JSP, necesitamos la dependencia para el lenguaje jstl.
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
    </dependency>
    
  3. Spring Boot utiliza un servidor Tomcat o Jetty embebido para desplegar la aplicación. Para utilizar Tomcat añadimos las siguientes dependencias (en la práctica esto no es necesario si utilizamos spring-boot-starter-web).
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>
    		
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
      <scope>provided</scope>
    </dependency>
    
  4. Las herramientas de desarrollo de Spring Boot permiten, entre otras funcionalidades, la recarga automática de la aplicación web en el Tomcat al detectarse cambios en los ficheros incluidos en el classpath.
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
    </dependency>
    
  5. El valor del packaging debe ser war.

    <packaging>war</packaging>

  6. En el application.properties definimos el prefijo y sufijo que utilizará el ViewResolver de Spring MVC para encontrar los ficheros .jsp que renderizarán las respuestas de las peticiones web.
    spring.mvc.view.prefix= /WEB-INF/jsp/
    spring.mvc.view.suffix= .jsp
    

Con estos sencillos pasos ya hemos convertido nuestra aplicación de ejemplo en una aplicación web. Vamos a desarrollar un controlador que atienda la raíz de la aplicación web para obtener los países de la base de datos utilizando el repositorio de Spring Data que ya tenemos. La lista de países se añade al Model de Spring MVC y un script JSP será el responsable de renderizar el html final que se enviará al navegador del usuario.

package com.danielme.springboot.controllerstomcat;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.danielme.springboot.repositories.CountryRepository;

@Controller
public class CountryController {

	@Autowired
	CountryRepository countryRepository;

	@RequestMapping("/")
	public String list(Model model) {
		model.addAttribute("countriesList", countryRepository.findAll());
		return "countriesList";
	}
}

Ubicamos countriesList en el directorio /src/main/WEB-INF/jsp.

<%@ page contentType="text/html; charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" type="image/png" href="/favicon.png">
<title>Spring Boot</title>
</head>
<body>
	
<h1>Countries</h1>
	
<hr>
	<c:choose>
		<c:when test="${not empty countriesList}">
			
                     <ul>
		       <c:forEach var="item" items="${countriesList}">
					
                          <li>${item.name}:<fmt:formatNumber value="${item.population}" /></li>

			</c:forEach>
		      </ul>

		</c:when>
		<c:otherwise>
			<b>NO DATA</b>
		</c:otherwise>
	</c:choose>

pr
</body>
</html>

Los ficheros con recursos estáticos tales como imágenes, css, javascript, etc, se ubican por defecto en el directorio /src/main/resources/static, Son accesibles a partir de la url raíz de la aplicación, por ejemplo /src/main/resources/static/js/script.js estará en http://localhost:8080/js/script.js.

Arrancamos la aplicación del mismo modo que vimos anteriormente y podremos acceder a nuestra pantalla a través de la url http://localhost:8080. El puerto se puede cambiar con la propiedad server.port en el application.properties.

Spring initializr

La creación inicial del proyecto se puede realizar de forma gráfica mediante esta herramienta vía web, o bien mediante un asistente en Eclipse gracias a la extensión gratuita Spring Tool Suite. Para usar este último nos vamos a “File>New->Other” y seleccionamos el asistente Spring Boot->Spring Starter Project.

El asistente consta de tres pantallas. En la segunda de ellas tenemos acceso a un catálogo categorizado con todos los starters.

Los proyectos creados con esta herramienta incluyen un “wrapper” para Maven o Gradle, según la opción elegida, por lo que no es necesario tener instalado como prerrequisito Maven (o Gradle) para poder construir el proyecto. Disponemos de dos scripts, uno para Windows (cmd) y otro para Linux (bash), que invocaremos con los mismos parámetros que usaríamos si llamáramos directamente al ejecutable de Maven (mvn).

Código de ejemplo

El proyecto completo se encuentra disponible en GitHub. Para más información sobre cómo utilizar GitHub, consultar este artículo.

También se encuentran en GitHub los ejemplos oficiales de Spring Boot

.

Otros tutoriales relacionados con Spring

Spring JDBC Template: simplificando el uso de SQL

Persistencia en BD con Spring Data JPA

Persistencia en BD con Spring: Integrando JPA, c3p0, Hibernate y EHCache

Testing Spring con JUnit 4

Ficheros .properties en Spring IoC

Cursos aplicaciones móviles

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

w

Conectando a %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

A %d blogueros les gusta esto: