0% encontró este documento útil (0 votos)
3K vistas

Backend SpringBoot

Este documento proporciona instrucciones para configurar el entorno de desarrollo para proyectos Spring Boot, incluyendo la instalación de Java JDK, IntelliJ IDEA, Maven y Git. Luego explica cómo inicializar proyectos Spring, configurar JPA, cargar datos, escribir controladores, templates, pruebas unitarias y más. El objetivo es crear un sistema de seguridad industrial utilizando las mejores prácticas de Spring Boot.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
3K vistas

Backend SpringBoot

Este documento proporciona instrucciones para configurar el entorno de desarrollo para proyectos Spring Boot, incluyendo la instalación de Java JDK, IntelliJ IDEA, Maven y Git. Luego explica cómo inicializar proyectos Spring, configurar JPA, cargar datos, escribir controladores, templates, pruebas unitarias y más. El objetivo es crear un sistema de seguridad industrial utilizando las mejores prácticas de Spring Boot.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 38

Backend Spring Boot

Mgr. Edson Ariel Terceros Torrico


Noviembre 2021
1 Table of Contents
1. Ambiente de desarrollo...................................................................................................4
1.1 Instalar java jdk.....................................................................................................................4
1.2 Instalar IntelliJ Idea...............................................................................................................5
1.3 Instalar Maven.......................................................................................................................7
1.4 Configuración de Git..............................................................................................................8
1.4.1 Configuración global para Git.................................................................................................8
2 Inicializador de spring......................................................................................................9
2.1 Inicializador start.spring.io....................................................................................................9
2.2 Inicializador de spring IntelliJ Idea.........................................................................................9
3 Enlazar al repositorio online...........................................................................................10
4 JPA.................................................................................................................................11
4.1 Spring Data JPA....................................................................................................................12
5 Inicializar Datos en Spring..............................................................................................12
6 Auditoria........................................................................................................................14
7 Spring Boot Dev Tools....................................................................................................14
8 Configuración IDE para compilar al guardar....................................................................14
9 Data Load.......................................................................................................................15
10 Controladores............................................................................................................15
11 Templates..................................................................................................................15
12 Inyección de dependencia..........................................................................................16
12.1 Simulando Inyección sin Spring............................................................................................16
12.2 Inyección con Spring............................................................................................................18
12.3 Qualifiers.............................................................................................................................18
12.4 @Profile...............................................................................................................................19
13 Ciclo de vida Spring....................................................................................................19
14 Banner.......................................................................................................................20
15 Component Scan........................................................................................................20
15.1 Configuración Java...............................................................................................................20
15.2 Configuración XML...............................................................................................................21
16 Spring Boot Configurations.........................................................................................21
17 Archivos .properties...................................................................................................21
18 Variables de Entorno..................................................................................................22
19 Spring Boot Application properties.............................................................................22
20 YAML.........................................................................................................................23
21 Profile Properties.......................................................................................................23

2
22 Proyecto Sistema de Seguridad Industrial...................................................................23
23 Métodos de Spring Data JPA Query............................................................................24
24 Servicios.....................................................................................................................25
25 JUnit Tests..................................................................................................................25
26 Mockito......................................................................................................................25
Argument Capture.................................................................................................................27
27 Test mockMvc............................................................................................................27
28 Test de Integración.....................................................................................................27
29 Separar los unit test de los test de integración...........................................................28
30 Generalización de Servicios........................................................................................29
31 Definición de templates.............................................................................................30
32 Navegación de Items..................................................................................................30
33 Creación de Items.......................................................................................................32
34 Actualizar Items.........................................................................................................34
35 Eliminar Items............................................................................................................34
36 Subir archivos al servidor...........................................................................................34
37 Mostrar imágenes de la Base de Datos.......................................................................35
38 Manejo de excepciones..............................................................................................36
39 Docker........................................................................................................................37
40 Mysql.........................................................................................................................38
41 MS SQL SERVER..........................................................................................................38
42 Dominio de negocio: Sistema Seguridad Industrial.....................................................39
43 Rubrica Tarea 1..........................................................................................................41
44 Modelo Entidades......................................................................................................42
45 Recursos.....................................................................................................................42

3
1. Ambiente de desarrollo

1.1 Instalar java jdk


Descargue Java jdk para su sistema operativo del siguiente link
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-
2133151.html

Instalación por defecto. Todo siguiente.


https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html

Verificar y de ser necesario añadir Path Var


Ir a panel de control -> Sistema -> avanzado -> Variables de entorno
Añadir la variable
nombre: JAVA_HOME
valor: C:\Program Files\Java\jdk1.8.0_171

Alternativamente ejecutar el comando


setx -m JAVA_HOME "C:\Program Files\Java\jdk1.8.0_171"
Para comprobar reiniciar la terminal y ejecutar
echo %JAVA_HOME%

Adicionar la ruta del directorio "bin" a la variable "PATH" separado por ";"
por ejemplo:
C:\WINDOWS\system32;C:\WINDOWS;"C:\Program Files\Java\jdk1.8.0_171\bin"

4
comprobar ejecutando
java -version
javac -version

1.2 Instalar IntelliJ Idea


Ejecutar instalador y aceptar parámetros por defecto.

Al crear un proyecto java, seleccionar Project SDK con la ruta donde se instaló java jdk.

5
1.3 Instalar Maven
Descargar el archivo compreso binario de https://maven.apache.org/download.cgi

Las instrucciones de instalación están en https://maven.apache.org/install.html


Descomprimir el archivo apache-maven-3.5.3-bin.zip en cualquier directorio. En el curso lo
descomprimiremos en la carpeta c:/maven

Añadir el directorio bin a la variable de entorno PATH


Verificar ejecutando el comando en consola:
mvn -v

La guía de instalación oficial esta en https://maven.apache.org/install.html

1.4 Configuración de Git


Para instalar Git en su computadora, vaya a https://git-scm.com/downloads para descargar el
instalador de Git para su plataforma informática específica.

Luego, siga los pasos de instalación mientras instala Git usando el instalador.
Puede encontrar más detalles sobre la instalación de Git en https://git-
scm.com/book/en/v2/Getting-Started-Installing-Git.
Los usuarios Windows es recomendable elegir la opción de GitShell para manejo de consola.

1.4.1 Configuración global para Git

Abra una ventana o terminal de cmd en su computadora.


Compruebe para asegurarse de que Git esté instalado y disponible en la línea de comandos,
escribiendo lo siguiente en el símbolo del sistema:
git --version

Para configurar su nombre de usuario para ser utilizado por Git, escriba lo siguiente:
git config --global user.name "Tu nombre"
Para configurar su correo electrónico para ser utilizado por Git, escriba lo siguiente:
git config --global user.email [email protected]
Puede verificar su configuración global predeterminada de Git, puede escribir lo siguiente:
git config --list

6
Generar su llave publica:
https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key

Crear un repositorio llamado spring-backend

Añade tu llave publica a la cuenta de gitLab

2 Inicializador de spring
2.1 Inicializador start.spring.io

http://start.spring.io/

2.2 Inicializador de spring IntelliJ Idea

Crear un proyecto con IntelliJ


Usar la opción de Spring Initializer.

group: com.market
artifact: spring-backend
Tipo Maven
Java: 9
SpringBoot: la ultima disponible
Seleccionar Web: Web, SQL: JPA, H2, PostgreSQL, Template: Thymeleaf, Ops: Actuator.
Generar Proyecto

3 Enlazar al repositorio online


Ejecutar el comando:
git status
Si el repositorio no esta inicializado o no existe, inicialízalo con:

7
git init
Hacer commit con el mensaje “Initial setup”

Crear un repositorio en github, totalmente en blanco.

Seguir los pasos provistos en el repositorio creado en github, similar a las siguientes líneas
reemplazando el usuario eterceros por el suyo:

git remote add origin https://github.com/eterceros/spring-backend.git


git push -u origin master

Crear un paquete llamado model para las clases de la capa de modelo.


Crear la clase Position con el atributo name.
Crear la clase Employee con los atributos firstName, lastName ambos tipo String, image de tipo
Byte[] y una colección de Contract contracts.
Crear la clase Contract con los atributos employee tipo Employee, position tipo Position,
initDate, endDate tipo Date.
Crear la clase Category con el atributo name y code tipo String.
Crear la clase SubCategory con el atributo name y code tipo String y category tipo Category.
Crear la clase Item con el atributo name y code tipo String, image de tipo Byte[] y subcategory
tipo SubCategory.

Escribir los métodos getters y setters con la ayuda del ide CTRL + N Alt+Ins.

4 JPA
Añadir la anotación @Entity a cada clase de la capa de modelo.
Crear la clase ModelBase y adicionar a esta la anotación @MappedSuperclass.
Puesto que a momento de persistir en la Base de datos es necesario una llave primaria debe
añadirse una propiedad id de tipo Long con sus getters y setters a la clase ModelBase.
Para que JPA lo identifique como una llave debe añadirse la anotación @Id al campo id y la
anotación @GeneratedValue(strategy = GenerationType.IDENTITY) donde se especifica la
estrategia de generación de llave como automática.
Hacer que todas las clases de tipo modelo extiendan de ModelBase.

Anadir los campos en BaseModel

@CreatedDate
@Temporal(TemporalType.TIMESTAMP)
@Column( nullable = false, updatable = false)
private Date createdOn;

@LastModifiedDate
@Temporal(TemporalType.TIMESTAMP)
@Column(insertable = false)
private Date updatedOn;

8
Añadir el campo requerido version a BaseModel con la anotación @Version
@Version
@Column(nullable = false)
private long version;

Anadir las relaciones JPA en Employee el atributo contracts debe tener la relación:

@OneToMany(mappedBy = "employee", fetch = FetchType.EAGER, cascade = {CascadeType.ALL})

En la clase Contract, employee y position deben tener la relación @OneToOne(optional = false)


En la clase Item, subCategory debe tener la relación @OneToOne(targetEntity = SubCategory.class)
En la clase SubCategory, category debe tener la relación @OneToOne(optional = false).

Es posible ver las tablas creadas en la base de datos por defecto mem:testdb, con el usuario sa
http://localhost:8080/h2-console
para tal efecto adicionar en application.properties la siguiente línea
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb

4.1 Spring Data JPA


Crear un paquete llamado repositories
Para crear un Repositorio para Employee es necesario crear una interfaz EmployeeRepository
que extienda de CrudRepository<Entidad, Class_Id>
public interface EmployeeRepository extends CrudRepository<Employee, Long> {}

De manera similar crear repositorios para cada clase de la capa modelo.


Template para repositorios

#parse("File Header.java")
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import org.springframework.data.repository.CrudRepository;
import com.sales.market.domain.${NAME};
public interface ${NAME}Repository extends CrudRepository<${NAME},Long>{
}

5 Inicializar Datos en Spring


Crear un paquete bootsptrap, dentro de este crear una clase DevBootstrap que implemente
ApplicationListener<ContextRefreshevent> y que tenga la anotación @Component
public class DevBootstrap implements ApplicationListener<ContextRefreshedEvent>

Implemente el método requerido por la interfaz onApplicationEvent.


Implemente un método que crea instancias de los diferentes modelos el cual debe ser invocado
desde la interfaz implementada.

9
private CategoryRepository categoryRepository;
private SubCategoryRepository subCategoryRepository;
private ItemRepository itemRepository;
private EmployeeRepository employeeRepository;
private PositionRepository positionRepository;
private ContractRepository contractRepository;

public DevBootstrap(CategoryRepository categoryRepository, SubCategoryRepository subCategoryRepository,


ItemRepository itemRepository, EmployeeRepository employeeRepository, PositionRepository
positionRepository,
ContractRepository contractRepository) {
this.categoryRepository = categoryRepository;
this.subCategoryRepository = subCategoryRepository;
this.itemRepository = itemRepository;
this.employeeRepository = employeeRepository;
this.positionRepository = positionRepository;
this.contractRepository = contractRepository;
}

@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
initData();
}

private void initData() {


// EPP category
Category eppCategory = new Category();
eppCategory.setCode("REF");
eppCategory.setName("REFRESCO");

categoryRepository.save(eppCategory);

// RES category
Category resourceCategory = new Category();
resourceCategory.setCode("RES");
resourceCategory.setName("RESOURCE");
categoryRepository.save(resourceCategory);

// safety subcategory
SubCategory safetySubCategory = new SubCategory();
safetySubCategory.setCategory(eppCategory);
safetySubCategory.setCode("SAF");
safetySubCategory.setName("SAFETY");

subCategoryRepository.save(safetySubCategory);

// raw material subcategory


SubCategory rawMaterialSubCategory = new SubCategory();
rawMaterialSubCategory.setCategory(resourceCategory);
rawMaterialSubCategory.setCode("RM");
rawMaterialSubCategory.setName("RAW MATERIAL");

subCategoryRepository.save(rawMaterialSubCategory);

10
// Helmet Item
Item helmet = new Item();
helmet.setCode("HEL");
helmet.setName("HELMET");
helmet.setSubCategory(safetySubCategory);

itemRepository.save(helmet);

// ink Item
Item ink = new Item();
ink.setCode("INK");
ink.setName("INK");
ink.setSubCategory(rawMaterialSubCategory);
itemRepository.save(ink);

// John Employee
Employee john = new Employee();
john.setFirstName("John");
john.setLastName("Doe");

// Position
Position position = new Position();
position.setName("OPERATIVE");
positionRepository.save(position);

// contract
Contract contract = new Contract();
contract.setEmployee(john);
contract.setInitDate(new Date(2010, 1, 1));
contract.setPosition(position);

john.getContracts().add(contract);
employeeRepository.save(john);
contractRepository.save(contract);
}

Si no ha inicializado las colecciones definidas en las entidades puede tener errores nullPointer,
en tal caso inicialice las colecciones, siempre con una clase concreta.

6 Auditoria
En la clase ModelBase adicionar la anotación @EntityListeners(AuditingEntityListener.class)
Y crear una clase de configuración PersistenceConfig con las anotaciones:
@Configuration
@EnableJpaAuditing

En la clase ModelBase adicionar la anotación @CreatedDate y @LastModifiedDate a los


atributos createdOn y updatedOn respectivamente

7 Spring Boot Dev Tools


Esta dependencia carga la aplicación con dos class Loader uno para el proyecto y otro para las
librerías. Esto permite que el tiempo de compilación sea más rápido.

11
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

8 Configuración IDE para compilar al guardar


Shift+Command+A (Shift+Ctrl+A en Windows)

Escribir Registry y luego habilitar la opción compiler.automake.allow.when.app.running


En las preferencias del IntelliJ, en la sección Build->Compiler y habilitar: compilar proyectos
automáticamente.

9 Data Load
Crear un archivo llamado data.sql en el paquete resources.

INSERT INTO category (code, name, CREATED_ON, VERSION ) VALUES ('10', 'ND','2018-04-10
14:46:19.282', 0);

10 Controladores
Crear las clases controladoras dentro del paquete controller, para cada modelo. Cada
controlador debe tener la anotación @Controller.
Inyectar el repositorio correspondiente en cada controlador

Implementar métodos tipo GET


@RequestMapping("/employees")
public String getEmployees(Model model) {
model.addAttribute("employees", employeeRepository.findAll());
return "employees";
}

11 Templates
En la carpeta resources, templates crear el template para employee employees.html
Todos los tag html deben estar apropiadamente cerrados por restricciones de thymeleaf.
Adicionar al tag <HTML el atributo:
xmlns:th="http://www.thymeleaf.org"

Añadir un tag h1 en el body


<h1>Employee List</h1>

Crear una tabla en html con 3 elementos thead para mostrar id, first name y last name.
Para llenar los datos de la table crear una fila con un iterador thymeleaf
<table>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>

12
</tr>
<tr th:each="employee:${employees}">
<td th:text="${employee.id}">123</td>
<td th:text="${employee.firstName}">Jhon</td>
<td th:text="${employee.lastName}">Doe</td>
<!--<td>
<table>
<tr th:each="contract:${employee.contracts}">
<td th:text="${contract.id}">123</td>
<td th:text="${contract.initDate}">Jhon</td>
</tr>
</table>
</td>-->
</tr>
</table>

Tarea:
Crear un template para Items donde se vea los datos del ítem, su subcategoría y su categoría.

12 Inyección de dependencia
Crear un proyecto con spring boot initializer, java 8, maven, llamado di-demo. No seleccionar
ninguna característica ya que solo es necesario spring core.
Crear un paquete controller.
Crear una clase llamada MyController en el paquete controller. Adicionar la anotación
@Controller a la clase creada.
Adicionar un método hello que devuelva el Sting “Hello Spring”.
@Controller
public class MyController {
public String hello(){
System.out.println("Hello Spring");
return "Hello Spring";
}
}
En la clase DIDemoApplication asignar la sentencia existente a la variable ctx de tipo Application
Context.
Con el objeto ctx es posible obtener un Bean instanciado por Spring con el método getBean
proveyendo como parámetro el nombre.

ApplicationContext ctx = SpringApplication.run(DiDemoApplication.class, args);


MyController controller= (MyController) ctx.getBean("myController");
controller.hello();

Ejecutar la aplicación y visualizar el mensaje impreso por el controller Bean.

12.1 Inyección con Spring


La inyección por propiedad requiere la anotación @Autowired en el atributo
La inyección por getter requiere la anotación @Autowired en el método setter

13
En la clase DIDemoApplication adicionar las siguientes líneas que permiten a Spring buscar e
inyectar los diferentes tipos de Bean.

System.out.println(ctx.getBean(PropertyBasedController.class).sayHello());
System.out.println(ctx.getBean(GetterBasedController.class).sayHello());
System.out.println(ctx.getBean(ConstructorBasedController.class).sayHello());

Adicionar la anotación @Controller a los controladores y en los controladores adicionar la


anotación @Autowired donde corresponda según es inyección por getter constructor o
propiedad.
Adicionar la anotación @Service al servicio.

12.2 Qualifiers
Algunas veces se tiene mas de una implementación de una interfaz de un servicio que produce
conflicto a Spring debido a que no puede elegir cual implementación es la requerida, por lo cual
se puede hacer uso de los cualificadores.
Crear 2 implementaciones de GreetingService: GetterGreetingServiceImpl y
ConstructorGreetingServiceImpl donde el mensaje será “Hello GetterGreetingServiceImpl” y
“Hello ConstructorGreetingServiceImpl” respectivamente.
Al correr la aplicación habrá conflicto de inyección de dependencias. Con un mensaje similar a:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using
@Qualifier to identify the bean that should be consumed

Usaremos @Qualifier para resolver los problemas. Con la ayuda del IDE ir a los controladores
para ver el código marcado en rojo y aceptar la ayuda del IDE para adicionar el cualificador
apropiado.

Alternativamente si el nombre del property coincide con el bean que deseamos inyectar
también se resuelve el conflicto sin necesidad del @Qualifier.

También se puede marcar los Bean con @Primary para que ese sea el bean inyectado en caso
de conflicto, pero es una mala práctica de programación.

Remover el qualifier del servicio en PropertyBasedController, al ejecutar la aplicación habrá


conflicto. Añadir la anotación @Primary a GreetingServiceImpl y todo debe funcionar
correctamente.

12.3 @Profile
Los profiles se usan para seleccionar los Bean a inyectar de acuerdo al profile activo.
Se activa un profile en el archivo application.properties

spring.profiles.active=es

14
Copiar el Servicio GreetingServiceImpl con el nombre SpanishGreetingServiceImpl y que
devuelva el mensaje: Hello SpanishGreetingServiceImpl. Al existir ahora dos Primary habrá
conflicto, para resolver Adicionar la anotación @Profile(“en”) a GreetingServiceImpl y
@Profile(“es”) a SpanishGreetingServiceImpl

Se puede además especificar un Profile por defecto en caso de no haber configurado el profile
activo.
@Profile({"es","default"})

Correr la aplicación y verificar el resultado en consola.

13 Ciclo de vida Spring


Crear una clase llamada SpringBeanLifeCycleDemo que implemente las interfaces
InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware,
ApplicationContextAware anotarla como componente.
Con la ayuda del IDE implementar las interfaces requeridas e imprimir en cada método el
nombre del método.
Crear un constructor que imprima un texto con el nombre del constructor
Adicionar los métodos postConstruct y preDestroy con las anotaciones del mismo nombre
respectivamente y deben imprimir mensajes con los nombres de sus métodos.

Escribir los métodos beforeInit y afterInit los cuales deben imprimir mensajes con los nombres
de sus métodos.

Crear una clase llamada MyBeanPostProcessor que implemente BeanPostProcessor marcarlo


como componente e implementar los métodos de la interfaz que reciben como parámetro
Object bean, String beanName
En los cuales si corresponde a la instancia de la clase SpringBeanLifeCycleDemo llamaremos a
los métodos apropiados de esta.
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof SpringBeanLifeCycleDemo) {
((SpringBeanLifeCycleDemo) bean).beforeInit();
}
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof SpringBeanLifeCycleDemo) {
((SpringBeanLifeCycleDemo) bean).afterInit();
}
return bean;
}

15
14 Banner
Para reemplazar el banner por defecto se debe crear un archivo llamado banner.txt en la
carpeta resources. Puedes crear tu banner en http://patorjk.com/software/taag/

15 Component Scan
La clase con la anotación @SpringBootApplication determina el directorio o paquete que
contiene los componentes de Spring, en caso de haber componentes fuera del alcance de esta
debe adicionarse la anotación @ComponentScan(basePackages= {“paquete”, “otropaquete”})

15.1 Configuración Java


Crear una clase plana POJO llamada Forecast que tenga un método llamado weather que
devuelve un String que dice “It will rain tomorrow”.

Adicionar la línea
System.out.println(ctx.getBean(Forecast.class).weather());
En DiDemoApplication

Crear una clase llamada BeanConfiguration en el paquete config que tenga la anotación
@Configuration y definir un método que instancie un objeto tipo Forecast, para permitirle ser
un Bean de Spring y poder ser inyectado desde otros componentes.

@Configuration
public class BeanConfiguration {
@Bean
public Forecast forecast(){
return new Forecast();
}
}

Modificar la clase ConstructorBasedController adicionando la propiedad


private Forecast forecast;
y hacer los cambios para que la inyección sea por constructor. En el método sayHello
concatenar la salida con forecast.weather();
Correr la aplicación y verificar que la inyección funciona.

15.2 Configuración XML


Comentar @Configuration y @Bean de BeanConfiguration
En el paquete resources crear un archivo llamado beanconfig. New File-> XMLConfiguration
File->SpringConfig mediante el IDE.
Con ayuda del IDE introducir en el archivo xml un tag <bean>
<bean name="forecast" class="com.market.didemo.Forecast"/>

16
Adicionar la anotación @ImportResource en la clase de la aplicación

@ImportResource("classpath:beanconfig.xml")
public class DiDemoApplication {

16 Spring Boot Configurations


Correr el comando para ver las opciones del plugin de spring boot

mvn spring-boot:help -Ddetail=true

Correr el comando para ver que dependencias se cargaron y cuales no

mvn spring-boot:run -Drun.arguments=--debug

IntelliJ tiene esta última opción en la configuración para correr el proyecto.

17 Archivos .properties
Mover el paquete services a su localización original.
Eliminar de DiDemoApplication las sentencias que imprimen.
Crear un archivo llamado database.properties
Introducir las líneas:

database.user=root
database.password=saltRootPwd
database.url=10.0.0.115

Crear una clase de configuración PropertyConfig y crear el método estático


propertySourcesPlaceholderConfigurer que devuelva PropertySourcesPlaceholderConfigurer en
su implementación debe crearse la instancia requerida a devolver
Adicionar la anotación @Bean al método para que pueda ser instanciado por Spring.
Adicionar la siguiente anotación a la clase para que el archivo de recursos sea reconocido.

@PropertySource("classpath:database.properties")

Crear un componente llamado FakeDataSource, con las propiedades user, pwd y url, anotar con
@Value(“${propertyKey}”)
En DiDemoApplication inyectar el bean por medio del contexto e imprimir el usuario

18 Variables de Entorno
IntelliJ provee la facilidad de especificar las variables de entorno. En windows son environment
variables y en osx están en bash_profile. En el Toolbar donde está el botón Run se puede editar
la configuración y esto permitirá adicionar las variables de entorno entre otras funcionalidades.

17
Adicionar la varible de entorno DATABASE_USER=EnvironmentUserValue
Es posible inyectar el entorno.
Adicionar la propiedad Environment env; anotada con @Autowired en FakeDataSource.
Mediante env.getProperty(“nombreVariable”) se puede obtener el valor de las variables de
entorno.
Crear una nueva variable de entorno llamada ENV_USER=EnvUser.
Crear un método con la anotación @PostConstruct y asignar el valor de la nueva variable de
entorno a user.
Correr la aplicación para verificar.

Crear un archivo de propiedades llamado jms.properties:


jms.user=JMSRoot
jms.password=saltJMSRootPwd
jms.url=10.0.0.120

Copiar la clase FakeDataSource con el nombre FakeJMS y cambiar las claves de las propiedades
de acuerdo al archivo de jms.properties.
En la clase PropertyConfig adicionar el nuevo recurso en la anotación correspondiente.
De manera similar a la impresión del database user imprimir el usuario de FakeJMS.

19 Spring Boot Application properties


En FakeDataSource eliminar el autowiring de environment y el método postconstruct.
En PropertyConfig eliminar la anotación PropertySource y el método para crear el bean de los
properties.
Copiar las propiedades definidas en database.properties y jms.properties a
application.properties y correr la aplicación.

20 YAML
Un archivo ejemplo es el siguiente:
name: Valeria

names:
- Gabriela
- Viviana
- Mariela
pound_sign: "#"

book:
author: Joe Buck
publisher: random house

truth: yes # Yes, true, TRUE

false: no #No, false, FALSE

string_value: "'This is surrounded by: single quotes'"

18
include_new_lines: |
line 1
line 2
line 3

ignore_new_lines: >
this is
just one long
string

Copiar las propiedades correspondientes a jms del archivo application.properties a


application.yml con el formato correspondiente. Ejecutar la aplicación y verificar los resultados.

21 Profile Properties
Cuando un profile está activo ese busca primero el archivo properties-<profile>.properties.
Copiar application.properties con el nombre application-es.properties y escribir los valores en
español. Fijar el profile a “es”
En YML se genera nuevos profiles en el mismo archivo con un separador:
---
spring:
profiles: es
jms:
user: root JMS ES

22 Proyecto Sistema de Market


Adicionar al proyecto la dependencia DevTools-Core para habilitar reinicio automatico cuando
cambie una clase del proyecto.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

Crear un controlador IndexController con el método getIndexPage que devuelve el String


"index". Anotar el método con
@RequestMapping({"", "/", "/index"})

crear un archivo llamado index.html en la carpeta templates. Modificar el texto de <title> a My


personal protection equipment. Adicionar en el body:
<h1 style="text-align: center">SII Index</h1>

23 Métodos de Spring Data JPA Query


En la interfaz CategoryRepository, crear el signature:
Optional<List<Category>> findByCode(String code);

19
De similar manera para subcategory.
Crear una plantilla para category:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Category</title>
</head>
<body>
<h1>Category</h1>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Code</th>
</tr>
<tr>
<td th:text="${category.id}">123</td>
<td th:text="${category.name}">Category Name</td>
</tr>
</table>

</body>
</html>

Crear un controlador para Category

@Controller
@RequestMapping("/categories")
public class CategoryController {
private CategoryRepository categoryRepository;

public CategoryController(CategoryRepository categoryRepository) {


this.categoryRepository = categoryRepository;
}

@RequestMapping
public String getCategories(@RequestParam(value = "code", required = false) String code, Model model) {
model.addAttribute("categories", StringUtils.isEmpty(code) ? categoryRepository.findAll() :
categoryRepository.findByCode(code).get());
return "categories";
}

@RequestMapping("/{id}")
public String getCategoriesById(@PathVariable("id") @NotNull Long id, Model model) {
model.addAttribute("category", categoryRepository.findById(id).get());
return "category";
}
}

24 Servicios
Crear el paquete services dentro de este crear la interfaz CategoryService que implementa

20
Set<Category> getCategories();

Con la ayuda del IDE generar su implementación y luego agregar la anotación @Service a la
implementación. Introducir una propiedad de tipo CategoryRepository y hacer la inyección
correspondiente. La implementación del método de interfaz es:

@Override
public Set<Category> getCategories() {
Set<Category> categories= new HashSet<>();
categoryRepository.findAll().iterator().forEachRemaining(categories::add);
return categories;
}

Los controladores deben invocar a los servicios y no a los repositorios directamente.


Los servicios es donde se encuentra nuestra lógica del negocio y estos pueden invocar otros
servicios y la capa de repositorio.
Por tanto cambiar los controladores, servicios y repositorios para que la aplicación refleje esto.

25 JUnit Tests
Asegurarse o adicionar la dependencia en el archivo pom spring-boot-starter-test.
Con la ayuda del IDE Alt+enter (alternativamente Alt+ins en la clase Category) crear test para
comprobar si es posible obtener el codigo de una categoría mediante su método getter.

26 Mockito
Crear un test para el servicio CategoryServiceImpl con ayuda del plugin testMe del IDE.
Adicionar las siguientes propiedades a la clase:
private static final String OTRA_CAT = "OTRACAT";

private List<Category> categorySet;

En el método setup adicionar la configuración inicial

categorySet = new ArrayList<>();


Category category = new Category();
category.setName(OTRA_CAT);
categorySet.add(category);

when(categoryRepository.findAll()).thenReturn(categorySet);

Opcionalmente de puede adicionar la anotación @RunWith(MockitoJUnitRunner.class) para


indicar que el test corre con Mockito en lugar de usar la sentencia del método setup:
MockitoAnnotations.initMocks(this);
Opcionalmente si no se adiciona @RunWith(MockitoJUnitRunner.class) y @InjectMocks debe
inicializarce en before:

21
MockitoAnnotations.initMocks(this);
categoryService= new CategoryServiceImpl(categoryRepository);

Verificar el número de veces que el método del mock se llama: “test de caja blanca”
verify(categoryRepository,times(1)).findAll();

CategoryController y el resto de los controlladores deberían en este punto hacer llamadas para
búsqueda no mediante el repositorio sino más bien mediante sus services correspondientes.

Realizar un test para CategoryController de similar manera, notar que necesitara introducir
mock para el servicio y model. Ademas una propiedad tipo lista categoryList que almacenera
posteriormente la respuesta Stub.
Necesitará además indicar al mock de service que hacer cuando sea invocado el método find:
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
categoryList = new ArrayList<>();
categoryList.add(new Category());
when(categoryService.find(any())).thenReturn(categoryList);
}

el método test debería invocar a getCategories del controller, verificar que la respuesta sea
“categories”, verificar que se haya llamado 1 vez al método del servicio y al método
addAttribute de model
@Test
public void testGetCategories() throws Exception {
String result = categoryController.getCategories(null, model);
String expectedView = "categories";
assertEquals(expectedView, result);
assertEquals(expectedView, expectedView);
verify(categoryService,times(1)).find(any());
verify(model,times(1)).addAttribute(eq(expectedView), eq(categoryList));
}

Argument Capture
En el método before adicionar una categoría al set de categories.
Un ejemplo de argument capture es:

@Test
public void testGetCategories() throws Exception {
ArgumentCaptor<List<Category>> argumentCaptor=
ArgumentCaptor.forClass((Class<List<Category>>)categoryList.getClass());
String result = categoryController.getCategories(null, model);
String expectedView = "categories";
assertEquals(expectedView, result);
assertEquals(expectedView, expectedView);
verify(categoryService,times(1)).find(any());
verify(model,times(1)).addAttribute(eq(expectedView), eq(categoryList));

verify(model,times(1)).addAttribute(eq("categories"), argumentCaptor.capture());
List<Category> capturedCategories = argumentCaptor.getValue();

22
assertEquals(capturedCategories.size(),1);
}

27 Test mockMvc
Hace un mock de Mvc, por ejemplo:

@RunWith(MockitoJUnitRunner.class)
public class IndexControllerTest {

@Mock
CategoryService categoryService;

@Mock
Model model;

@InjectMocks
IndexController controller;

@Test
public void testMockMVC() throws Exception {
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();

mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("index"));
}
}

28 Test de Integración
Los nombres de test de este tipo terminan en IT.
Crear una carpeta de nombre integration. Crear un Test llamado CategoryRepositoryIT. Anotar
con @DataJpaTest y @RunWith(SpringRunner.class), inyectar un CategoryRepository con
@Autowired y crear un método de test llamado tesFindAllCategoriesIT que invoca al método
findAll del repositorio inyectado realizando un assert para verificar el número de categoies. Mas
detalles en el siguiente fragmento de codigo

@Before
public void before() {
initialCount = categoryRepository.findAll().size();
categoryA = new Category();
categoryA.setCreatedOn(new Date());
categoryRepository.save(categoryA);
categoryB = new Category();
categoryB.setCreatedOn(new Date());
categoryRepository.save(categoryB);
}

@Test
public void tesFindAllCategoriesIT() {
Set<Category> categories = new HashSet<>();

23
categoryRepository.findAll().iterator().forEachRemaining(categories::add);
assertEquals(initialCount + 2, categories.size());
}

29 Separar los unit test de los test de integración


Para tal fin es necesario habilitar que los test IT corran en el goal verify de pom como se ve a
continuación. mvn:test correra los test unitarios y mvn:verify correra primero los unit test y
luego los test de integración.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<includes>
<include>**/*IT.java</include>
</includes>
<additionalClasspathElements>
<additionalClasspathElement>${basedir}/target/classes</additionalClasspathElement>
</additionalClasspathElements>
<parallel>none</parallel>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>

30 Generalización de Servicios
En este punto es importante notar que podemos aprovechar las características de java generics
para generalizar mediante abstracción el comportamiento común. A continuación, se muestra
la propuesta de generalización:

public interface GenericService<T> {


List<T> findAll();

T findById(Long id);
}

@Service
public abstract class GenericServiceImpl<T> implements GenericService<T> {

@Override
public List<T> findAll() {

24
List<T> results = new ArrayList<>();
getRepository().findAll().forEach(results::add);
return results;
}

@Override
public T findById(Long id) {
return getRepository().findById(id).get();
}

protected abstract CrudRepository<T,Long> getRepository();


}

Modificando de acuerdo a la propuesta por ejemplo ahora tenemos:


public interface EmployeeService extends GenericService<Employee> {
}

@Service
public class EmployeeServiceImpl extends GenericServiceImpl<Employee> implements EmployeeService {
private EmployeeRepository employeeRepository;

public EmployeeServiceImpl(EmployeeRepository EmployeeRepository) {


this.employeeRepository = EmployeeRepository;
}

@Override
protected CrudRepository<Employee, Long> getRepository() {
return employeeRepository;
}
}

31 Definición de templates
Template para interfaz Service, llámenla SSIService:

/**
* @author: Edson A. Terceros T.
*/

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end


#parse("File Header.java")

import com.sales.market.domain.${NAME};

public interface ${NAME}Service extends GenericService<${NAME}> {


}

Propuesta de file template para la implementación de servicios, llámenla SSIServiceImpl:

25
/**
* @author: Edson A. Terceros T.
*/

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end


#parse("File Header.java")

import com.sales.market.domain.${NAME};
import com.sales.market.repositories.${NAME}Repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Service;

@Service
public class ${NAME}ServiceImpl extends GenericServiceImpl<${NAME}> implements ${NAME}Service {

private ${NAME}Repository repository;

public ${NAME}ServiceImpl(${NAME}Repository repository) {


this.repository = repository;
}

@Override
protected CrudRepository<${NAME}, Long> getRepository() {
return repository;
}
}

32 Navegación de Items
En GenericServiceImpl modificar el siguiente método asi:
@Override
public T findById(Long id) {

Optional<T> optional = getRepository().findById(id);


if (!optional.isPresent()) {
String typeName = (((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]).getTypeName();
typeName = typeName.substring(typeName.lastIndexOf(".") + 1);
throw new RuntimeException(
typeName + " NotFound");
}
return optional.get();
}

Definir un template para controladores:

/**
* @author: Edson A. Terceros T.
*/

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end


#parse("File Header.java")
#set($LOWER_NAME = $NAME.substring(0,1).toLowerCase() + $NAME.substring(1))

26
import com.sales.market.services.${NAME}Service;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.validation.constraints.NotNull;

@Controller
@RequestMapping("/${LOWER_NAME}s")
public class ${NAME}Controller {
private ${NAME}Service service;

public ${NAME}Controller(${NAME}Service service) {


this.service = service;
}

@RequestMapping
public String get${NAME}s(Model model) {
model.addAttribute("${LOWER_NAME}s", service.findAll());
return "${LOWER_NAME}s";
}

@RequestMapping("/{id}")
public String get${NAME}sById(@PathVariable("id") @NotNull Long id, Model model) {
model.addAttribute("${LOWER_NAME}", service.findById(id));
return "${LOWER_NAME}";
}
}

Crear ItemController usando el template.

Crear items.html asi:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Items</title>
</head>
<body>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Code</th>
<th>View</th>
</tr>
<tr th:each="item:${items}">
<td th:text="${item.id}">123</td>
<td th:text="${item.name}">Jhon</td>
<td th:text="${item.code}">Doe</td>
<td><a href="#" th:href="@{'/items/'+${item.id}}">View</a></td>

27
</tr>
</table>

</body>
</html>

Observe que se ha definido un link para navegación <td><a href="#" th:href="@{'/items/'+$


{item.id}}">View</a></td>

Crear un nuevo template llamado item.html para visualizar un ítem especifico


El body puede ser similar a
<body>
<h1 th:text="'Item '+ ${item.name}">Item Name</h1>
<table>
<tr>
<th>ID</th>
<th>Code</th>
<th>Name</th>
<th>Sub Category</th>
</tr>
<!--/*@thymesVar id="item" type=" com.sales.market.model.Item"*/-->
<tr>
<td th:text="${item.id}">123</td>
<td th:text="${item.code}">ItemCode</td>
<td th:text="${item.name}">ItemName</td>
<td th:text="${item.subCategory.name}">Jhon</td>
</tr>
</table>
</body>

33 Creación de Items
Crear un template llamado itemForm. Para acceder a los atributos usar th:field=”*{propiedad}”
usar un elemento select para mostrar las diferentes sub categorías cada <option> se itera con
th:each=”subCategoryItem : ${subCategories}” además proveer el valor relacionado al id y
como texto mostrar el nombre.
<form th:object="${item}" th:action="@{/items}" METHOD="post">
<div>
<label>Name</label>
<input type="text" th:field="*{name}"></input>
</div>
<div>
<label>Code</label>
<input type="text" th:field="*{code}"></input>
</div>
<div>
<label>SubCategory</label>
<select th:field="*{subCategory}">
<option th:each="type : ${subCategories}"
th:value="${type.id}"
th:text="${type.name}"></option>
</select>
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>

28
</div>
</form>

Este formulario debe ser accesible desde una ruta en el controller de ítem, para lo cual será
necesario inyectar además SubCategoryService, proveer una instancia nueva de Item en model
y las sub categrias leidas por el servicio correspondiente.
Devolver el nombre del template con el formulario para item
@RequestMapping("/new")
public String newItem(Model model, Item item) {
Item newItem = new Item();
newItem.setSubCategory(new SubCategory());
model.addAttribute("item", newItem);
model.addAttribute("subCategories", subCategoryService.getSubCategories());
return "itemForm";
}

El template hace una llamada post a la ruta ítems, por lo cual necesitamos una ruta en el
controller de ítem para crear y actualizar ítems. Una vez procesado, debe hacerse un redirect
a /ítems/{id}. Implementar el método save en el service.

@PostMapping
public String saveItem(Model model, Item item) {
Item itemPersisted = service.save(item);
model.addAttribute("item", itemPersisted);
return "redirect:/items/"+itemPersisted.getId();
}

Para soportar el método save Es necesario modificar GenericService


T save(T model);

y GenericServiceImpl

@Override
public T save(T model) {
return getRepository().save(model);
}

Ademas modificar el mapeo unidireccional de la Clase item de subcategory


@OneToOne(targetEntity = SubCategory.class)

34 Actualizar Items
Para actualizar ítems se necesita adicionar en el listado
<td><a href="#" th:href="@{'/items/update/'+${item.id}}">Edit</a></td>

y la ruta correspondiente en el controller:

@RequestMapping("/update/{id}")
public String updateItem(Model model, @PathVariable String id) {

29
model.addAttribute("item", service.findById(Long.valueOf(id)));
model.addAttribute("subCategories", subCategoryService.findAll());
return "itemForm";
}

La actualización se maneja con la misma lógica de save.

35 Eliminar Items
Para eliminar ítems se necesita adicionar en el listado
<td><a href="#" th:href="@{'/items/delete/'+${item.id}}">Delete</a></td>
y la ruta correspondiente en el controller
@RequestMapping(value = "/delete/{id}")
public String deleteItem(Model model, @PathVariable String id) {
itemService.deleteItem(Long.valueOf(id));
return "redirect:/items/";
}

36 Subir archivos al servidor


Modificar el template de item adicionando
<div>
<label>Image</label>
<a href="#" th:href="@{'/items/'+${item.id}+'/image'}">Image</a>
</div>

la acción del template nos permite nagevar a items/{itemId}/image. Adicionar la ruta


correspondiente en el controlador.

@RequestMapping(value = "/{id}/image")
public String showUploadItemImageForm(Model model, @PathVariable String id) {
Item itemPersisted = itemService.findById(Long.valueOf(id));
model.addAttribute("item",itemPersisted);
return "uploadItemImageForm";
}

adicionar un template para hacer upload de la imagen llamado uploadItemImageForm


<form action="http:\\localhost" method="post" enctype="multipart/form-data"
th:action="@{'/items/' + ${item.id} + '/image'}">
<label class="control-label">Select File</label>
<input id="imagefile" name="imagefile" type="file" class="file"/>
<button type="submit">Submit</button>
</form>

este formulario hace una llamada post al controller para almacenar la imagen, para tal motivo
es necesario adicionar una nueva propiedad en Item de tipo byte array
@Lob
private Byte[] image;

en el controller adicionar la ruta:

30
@PostMapping("/items/{id}/image")
public String potImage(Model model, @PathVariable String id, @RequestParam("imagefile") MultipartFile file) {
service.saveImage(Long.valueOf(id), file);

model.addAttribute("item", service.findById(Long.valueOf(id)));
model.addAttribute("subCategories", subCategoryService.getSubCategories());
return "redirect:/items/update/{id}";
}

El servicio encargado de almacenar la imagen en la base de datos seria como sigue

@Override
public void saveImage(Long id, MultipartFile file) {
Item itemPersisted = findById(id);
try {
Byte[] bytes = new Byte[file.getBytes().length];
int i = 0;
for (Byte aByte : file.getBytes()) {
bytes[i++] = aByte;
}
itemPersisted.setImage(bytes);
getRepository().save(itemPersisted);
} catch (IOException e) {
logger.error("Error reading file", e);
e.printStackTrace();
}
}

37 Mostrar imágenes de la Base de Datos


Para mostrar imágenes de la BD se necesita una ruta en controlador que devuelva contenido
tipo image en el response. A continuación un ejemplo:

@GetMapping("/{id}/readimage")
public void renderImageFromDB(@PathVariable String id, HttpServletResponse response) throws IOException {
Item itemPersisted = service.findById(Long.valueOf(id));

if (itemPersisted.getImage() != null) {
byte[] byteArray = new byte[itemPersisted.getImage().length];
int i = 0;

for (Byte wrappedByte : itemPersisted.getImage()) {


byteArray[i++] = wrappedByte;
}
response.setContentType("image/jpeg");
InputStream is = new ByteArrayInputStream(byteArray);
IOUtils.copy(is, response.getOutputStream());
}
}

en el template del formulario de item adicionar

31
<div>
<label>Image</label>
<div>
<img th:src="@{'/items/' + ${item.id} + '/readimage'}"
width="200" height="200"/>
</div>
<a href="#" th:href="@{'/items/'+${item.id}+'/image'}">change Image</a>
</div>
que permite llamar al endpoint para renderizar imágenes.

38 Manejo de excepciones
En el paquete exceptions crear la excepción
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException{
public NotFoundException() {
super();
}
public NotFoundException(String message) {
super(message);
}
public NotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
véase que el estado esta establecido por la anotación @ResponseStatus
En el método findById de generic service arrojar la nueva excepción si el item no fue
encontrado.
throw new NotFoundException(typeName + " id:" + id + " Not Found");

Probar los resultados verificando el http Status code que se devuelve.

Para mostrar el error en una vista especifica, crear el template error

<h1 th:text="${exception.message}">error code</h1>

En el controlador de ítem definir el handler


@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler(NotFoundException.class)
public ModelAndView handleNotFound(Exception e){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject("exception",e);
return modelAndView;
}

A nivel de aplicación se puede definir un handler de excepciones. Crear una clase llamada
ControllerExceptionHandler anotada con @ControllerAdvice que devuelva ModelAndView con
datos de la excepción y la vista a la que redirige.

32
@ControllerAdvice
public class ControllerExceptionHandler {

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(NumberFormatException.class)
public ModelAndView handleNumberFormat(Exception e){
ModelAndView modelAndView= new ModelAndView();
modelAndView.setViewName("applicationerror");
modelAndView.addObject("exception", e);
return modelAndView;
}
}
crear la pagina applicationerror y probar ver un ítem introduciendo un id de ítem invalido.

39 Docker
Instalar Docker community edition edge. Usuarios Windows necesitan virtual box instalado.
Ejecutar el comando
docker version
docker run hello-world

Verificar la salida de consola.


El repositorio publico de docker esta en https://hub.docker.com/ donde podrá buscar imágenes
de contenedores disponibles
Por ejemplo, buscar MySql.
Para crear una instancia de mysql:

docker run --name ssi-mysql -e MYSQL_ROOT_PASSWORD=root -v /Users/edson/volumes:/var/lib/mysql -p


3306:3306 -d mysql

Otros comandos docker


docker kill $(docker ps -q) elimina procesos de contenedores
docker rm $(docker ps -a -q) elimina contenedores

40 Mysql
En el archivo application.yml en resources escribir la configuración de mysql

spring:
datasource:
url: jdbc:mysql://localhost:3306/mysql
username: root
password: root
jpa:
hibernate:
ddl-auto: create
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: mysql
show-sql: true

33
Adicionar la dependencia maven

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

41 MS SQL SERVER
Ejecutar los siguientes comandos.
docker pull microsoft/mssql-server-linux:2017-latest

Previamente crear la carpeta donde estará el volumen /var/opt/mssql


docker create -v /var/opt/mssql --name mssql microsoft/mssql-server-linux /bin/true
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=P@55w0rd' -p 1433:1433 --volumes-from mssql -d
--name sql-server microsoft/mssql-server-linux

En el archivo pom.xml adicionar la dependencia:

<!-- https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc -->


<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.4.0.jre8</version>
</dependency>

Modificar la configuración de la BD asi:


spring:
datasource:
url: jdbc:sqlserver://localhost
username: sa
password: P@55w0rd
platform: mssql
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
jpa:
hibernate:
ddl-auto: create-drop
database: SQL_SERVER
show-sql: true

Descargar el jar desde https://docs.microsoft.com/en-us/sql/connect/jdbc/download-


microsoft-jdbc-driver-for-sql-server
Instalar el driver desde la ubicación de la carpeta que contiene el jar descompreso.

mvn install:install-file -Dfile=./mssql-jdbc-6.4.0.jre8.jar -DgroupId=com.microsoft.sqlserver -DartifactId=mssql-


jdbc -Dversion=6.4.0.jre8 -Dpackaging=jar

PostgreSQL

34
docker run --name postgres -e POSTGRES_PASSWORD=postgres -d -p 5432:5432 postgres:9.6.10-alpine

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.3-1100-jdbc41</version>
</dependency>

spring:
datasource:
username: postgres
password: postgres
url: jdbc:postgresql://localhost:5432/ssi
jpa:
database: POSTGRESQL
generate-ddl: true
hibernate.ddl-auto: update
show-sql: true

https://www.getpostman.com/collections/cb9764af6c5d5bcaa0c9

42 Recursos
Muchos ejemplos de Spring 5
https://github.com/eugenp/tutorials

Spring Framework reference


https://docs.spring.io/spring/docs/current/spring-framework-reference/

Spring Boot Reference


https://docs.spring.io/spring-boot/docs/current/reference/html/

Repositorio del proyecto


https://github.com/eterceros/spring-backend

Git: master o main branch


https://www.zdnet.com/article/github-to-replace-master-with-alternative-term-to-avoid-
slavery-references/

Git: ¿Donde están los archivos de configuracion?


https://www.theserverside.com/blog/Coffee-Talk-Java-News-Stories-and-Opinions/Where-
system-global-and-local-Windows-Git-config-files-are-saved

Git cheat sheet

35
https://www.atlassian.com/dam/jcr:8132028b-024f-4b6b-953e-e68fcce0c5fa/atlassian-git-
cheatsheet.pdf

Git crear mas de un ssh key


https://www.youtube.com/watch?v=N2hMGEeYR7c

Git entendiendo mas como funciona ssh key en Git


https://www.youtube.com/watch?v=z7jVOenqFYk

Libros de Git
https://git-scm.com/book/es/v2

Documentacion oficial de GIT


https://git-scm.com/doc

Hibernate documentación oficial


https://docs.jboss.org/hibernate/orm/6.0/userguide/html_single/Hibernate_User_Guide.html

Video como llevar desde una Base de Datos a Entidades

Ejemplos de tipos de Herencia JPA


https://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/
Ejemplos Spring Boot. Herencia JPA
https://github.com/netgloo/spring-boot-samples

Spring Boot H2
https://www.baeldung.com/spring-boot-h2-database

REST con Spring


https://www.baeldung.com/rest-with-spring-series

REST Mejores prácticas para el diseño de un REST API


https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/

REST API Verbos versos Sujetos


https://www.youtube.com/watch?v=2Mz3V-
faNFo&list=PLjXUjSTUHs0QaXI9xrioHpvsJ9Hs_r0_0&index=1

VIM cheatsheet
https://vim.rtorr.com/

REST Conversión de DTO


https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application

36
DSL online mapeo de entidades
http://www.jhipster.tech/jdl-studio/

Optimistic lock exception handling


https://www.mkyong.com/jpa/jpa-optimistic-lock-exception-in-java-development/

JPA locking
https://www.baeldung.com/jpa-optimistic-locking

https://www.baeldung.com/jpa-pessimistic-locking

Java: BigDecimal and BigInteger


https://www.baeldung.com/java-bigdecimal-biginteger

Futuros completables
https://www.baeldung.com/java-completablefuture

WebClient de Spring 5
https://www.baeldung.com/spring-5-webclient

Rest Template
https://www.baeldung.com/rest-template

Mockito
https://www.baeldung.com/mockito-series
https://www.baeldung.com/mockito-annotations

Inyeccion de arrays
https://www.baeldung.com/spring-inject-arrays-lists

Estrategias de herencia JPA


https://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/

Criteria Query
https://www.baeldung.com/hibernate-criteria-queries

Date Time Queries


https://www.objectdb.com/java/jpa/query/jpql/date
https://www.baeldung.com/spring-data-jpa-query-by-date

Spring Boot y Angular


https://www.baeldung.com/spring-boot-angular-web

37
Spring Security OAuth 2 Guides
https://www.baeldung.com/spring-security-oauth

Spring Security Method authorization


https://www.baeldung.com/spring-security-check-user-role
https://www.baeldung.com/spring-enablewebsecurity-vs-enableglobalmethodsecurity

Spring REST API + OAuth2 + Angular


https://www.baeldung.com/rest-api-spring-oauth2-angular

Java AWS
https://aws.amazon.com/es/blogs/opensource/java-apis-aws-lambda/
https://www.baeldung.com/java-aws-lambda
https://docs.aws.amazon.com/lambda/latest/dg/welcome.html

Ejemplo MVCMock
https://memorynotfound.com/unit-test-spring-mvc-rest-service-junit-mockito/

Java, Spring y A WS Lambda, SQS, S3


https://aws.amazon.com/es/blogs/opensource/java-apis-aws-lambda/
https://www.baeldung.com/java-aws-lambda
https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html

Validation
https://www.baeldung.com/spring-custom-validation-message-source

38

También podría gustarte