Aplicación básica en Spring

Desarrollo de una aplicación básica en Spring

En la web faltan ejemplos de aplicaciones de verdad, especialmente en castellano, así que vamos a solucionar eso: el sistema Edu-Manage es un sistema que permite administrar un instituto de idiomas, desde la gestión de cursos, horarios de clases, inscripción de estudiantes, pago de cuotas, hasta el honorario de los profesores.

Esquema básico

Vamos a empezar por lo básico. Hoy en día empezar una aplicación en Spring es extremadamente fácil gracias al producto Spring Initializr. Así que vamos a hacer eso.

El Spring Initializr es una forma automatizada de generar el esqueleto del proyecto: el archivo POM para almacenar las dependencias, la estructura de carpetas, archivos de propiedades, etc, todo lo necesario para empezar.

Para Edu-Manage vamos a seleccionar las siguientes dependencias:

  • Spring Web – Para desarrollar aplicaciones web
  • Spring HATEOAS – para hacer una interfaz RESTful
  • Spring Session – para mantener el estado de una sesión en el sistema
  • Spring Data JPA – para facilitar la creación de la capa de persistencia con Hibernate
  • Flyway Migration – para facilitar la migración del esquema de la base de datos
  • PostgreSQL driver – para conectarnos a la base de datos
  • Spring security – para manejo de usuarios, grupos y permisos
  • Validation – para permitir validar formularios mediante reglas a escribir directamente en la definición de las clases del modelo de datos.

Luego de generar el proyecto, lo descomprimimos en una carpeta y empezamos a trabajar.

Sobre esto, vamos a hacer algunas modificaciones:

  • Agregamos el proyecto jjwt de io.jsonwebtoken, para trabajar con las Java Web Tokens (JWT), y facilitar la autenticación de una interfaz REST.
  • Log4j2 – para hacer Logging dentro de nuestra aplicación.
  • Hibernate envers – para hacer auditoría de cambios a las entidades.
  • Al agregar log4j2, tenemos que evitar que Spring Boot use la implementación por defecto del subsistema de Logging, basado en slf4j. Se puede usar, y de hecho, muchos lo usan, pero log4j2 es mucho más flexible.
  • Para trabajar con archivos JSP, necesitamos tener las bibliotecas de Taglibs, así que las agregamos como dependencias.

Por lo tanto, en las dependencias generadas en el POM, aplicamos los cambios mencionados:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</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</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-log4j2</artifactId>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-envers</artifactId>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>c</artifactId>
			<version>1.1.2</version>
			<type>tld</type>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>fmt</artifactId>
			<version>1.1.2</version>
			<type>tld</type>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
		</dependency>

A continuación, el POM completo:

<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>ar.com.strellis</groupId>
	<artifactId>edu-manage</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>edumanage</name>
	<description>Sistema para administración de cursos</description>
	<packaging>war</packaging>
	<properties>
		<java.version>1.8</java.version>
		<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
	</properties>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.4.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity5</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-hateoas</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</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-cache</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-junit-jupiter</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-envers</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.tiles</groupId>
			<artifactId>tiles-jsp</artifactId>
			<version>3.0.5</version>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>c</artifactId>
			<version>1.1.2</version>
			<type>tld</type>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>fmt</artifactId>
			<version>1.1.2</version>
			<type>tld</type>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>
		<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>
	</dependencies>

	<build>
		<finalName>${project.artifactId}</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.hibernate.orm.tooling</groupId>
				<artifactId>hibernate-enhance-maven-plugin</artifactId>
				<version>${hibernate.version}</version>
				<executions>
					<execution>
						<configuration>
							<failOnError>true</failOnError>
							<enableLazyInitialization>true</enableLazyInitialization>
						</configuration>
						<goals>
							<goal>enhance</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>properties-maven-plugin</artifactId>
				<version>1.0.0</version>
				<executions>
					<execution>
						<phase>initialize</phase>
						<goals>
							<goal>read-project-properties</goal>
						</goals>
						<configuration>
							<files>
								<file>src/main/resources/application.properties</file>
							</files>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.flywaydb</groupId>
				<artifactId>flyway-maven-plugin</artifactId>
				<executions>
					<execution>
						<phase>compile</phase>
						<goals>
							<goal>migrate</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<url>${spring.datasource.url}</url>
					<user>${spring.datasource.username}</user>
					<password>${spring.datasource.password}</password>
					<baselineOnMigrate>true</baselineOnMigrate>
				</configuration>
			</plugin>
		</plugins>
		<pluginManagement>
			<plugins>
				<!--This plugin's configuration is used to store Eclipse m2e settings 
					only. It has no influence on the Maven build itself. -->
				<plugin>
					<groupId>org.eclipse.m2e</groupId>
					<artifactId>lifecycle-mapping</artifactId>
					<version>1.0.0</version>
					<configuration>
						<lifecycleMappingMetadata>
							<pluginExecutions>
								<pluginExecution>
									<pluginExecutionFilter>
										<groupId>org.flywaydb</groupId>
										<artifactId>
											flyway-maven-plugin
										</artifactId>
										<versionRange>
											[4.0.3,)
										</versionRange>
										<goals>
											<goal>migrate</goal>
										</goals>
									</pluginExecutionFilter>
									<action>
										<ignore></ignore>
									</action>
								</pluginExecution>
							</pluginExecutions>
						</lifecycleMappingMetadata>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
</project>

El proyecto se puede descargar de GitHub.