Spring boot example from zero to hero!

If you need further information about the topic, follow this link.

Here's how you can make the database schema.

Build the model with the VO classes

      
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "EMPLEADOS")
public class EmpleadoVO {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	public int idEmpleado;
	public String nombre;
	public String nif;
	public LocalDate fechaContrato;
	@OneToMany(mappedBy = "empleado")
	public List<EmpleadoSupermercadoVO> supermercados;
}
      
      
        
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "SUPERMERCADOS")
public class SupermercadoVO {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	public int idSupermercado;
	public String denominacion;
	public String direccion;
	@OneToMany(mappedBy = "supermercado", cascade = CascadeType.REMOVE, orphanRemoval = true)
	public List<EmpleadoSupermercadoVO> empleados;
}
      
      
        
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "EMPLEADOSUPERMERCADO")
public class EmpleadoSupermercadoVO {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	public int idEmpleadoSupermercado;
	@ManyToOne
	public EmpleadoVO empleado;
	@ManyToOne
	public SupermercadoVO supermercado;
	public LocalDate fechaInicio;
	public LocalDate fechaFin;
}
      
      

Create the service and his implementation

        
      
public interface EmpleadoServicio {

	List<EmpleadoVO> findByFechaContratoBetweenOrderByFechaContratoDesc(
	LocalDate inicio, LocalDate fin);

	<S extends EmpleadoVO> S save(S entity);
}

@Service
public class EmpleadoServicioImpl implements EmpleadoServicio {

	@Autowired
	EmpleadoRepository er;
	
	@Override
	public List<EmpleadoVO> findByFechaContratoBetweenOrderByFechaContratoDesc
	(LocalDate inicio, LocalDate fin) {
		return er.findByFechaContratoBetweenOrderByFechaContratoDesc(inicio, fin);
	}

	@Override
	public <S extends EmpleadoVO> S save(S entity) {
		return er.save(entity);
	}

	@Override
	public <S extends EmpleadoVO> Iterable<S> saveAll(Iterable<S> entities) {
		return er.saveAll(entities);
	}

	@Override
	public Optional<EmpleadoVO> findById(Integer id) {
		return er.findById(id);
	}

	@Override
	public boolean existsById(Integer id) {
		return er.existsById(id);
	}

	@Override
	public Iterable<EmpleadoVO> findAll() {
		return er.findAll();
	}

	@Override
	public Iterable<EmpleadoVO> findAllById(Iterable<Integer> ids) {
		return er.findAllById(ids);
	}

	@Override
	public long count() {
		return er.count();
	}

	@Override
	public void deleteById(Integer id) {
		er.deleteById(id);
	}

	@Override
	public void delete(EmpleadoVO entity) {
		er.delete(entity);
	}

	@Override
	public void deleteAllById(Iterable<? extends Integer> ids) {
		er.deleteAllById(ids);
	}

	@Override
	public void deleteAll(Iterable<? extends EmpleadoVO> entities) {
		er.deleteAll(entities);
	}

	@Override
	public void deleteAll() {
		er.deleteAll();
	}

}
      
      

Create the repository and the controller


import com.dawes.modelo.ClienteVO;
@Repository
public interface ClienteRepository extends CrudRepository<ClienteVO, Integer> {

}

@Repository
public interface AlquilerRepository extends CrudRepository<AlquilerVO, Integer> {
	// Alquileres de un coche entre fechas
	List<AlquilerVO> findByCocheAndFechacomienzoBetween(CocheVO coche, 
	LocalDate inicio, LocalDate fin);
}


      
      

@Controller
@RequestMapping("/asignaciones")
public class EmpleadoSupermercadoController {

	@Autowired
	EmpleadoServicio es;
	@Autowired
	EmpleadoSupermercadoServicio ess;
	
	@RequestMapping("/empleado")
	public String asignacionesEmpleado (@RequestParam int idEmpleado, Model modelo){
		EmpleadoVO empleado = es.findById(idEmpleado).get();
		modelo.addAttribute("empleado", empleado);
		modelo.addAttribute("asignaciones", ess.findByEmpleado(empleado));
		return "asignacionEmpleado";
	}
	
}

@RequestMapping("/coche")
@RestController
public class CocheWS {
	@Autowired
	CocheServicio cos;
	@Autowired
	AlquilerServicio as;
	@Autowired
	ClienteServicio cls;

	@PostMapping("/inserta")
	public ResponseEntity<?> insertCoche(@RequestBody CocheDTO coche) {
		try {
			cos.save(new CocheVO(0, coche.getMatricula(), coche.getMarca(), coche.getFechacompra(),
					new ArrayList<AlquilerVO>()));

			return new ResponseEntity<String>("Inserción correcta", HttpStatus.OK);
		} catch (Exception e) {
			if (e.getCause() instanceof ConstraintViolationException)
				return new ResponseEntity<String>("Clave única duplicada: 
				" + e.getMessage(), HttpStatus.BAD_REQUEST);

			if (e.getCause() instanceof DataException)
				return new ResponseEntity(
				"Error: Tienes algún problema con los tipos de datos",
						HttpStatus.BAD_REQUEST);
			if (e.getCause() instanceof PropertyValueException)
				return new ResponseEntity("Error: el campo matrícula no puede ser nulo",
				HttpStatus.BAD_REQUEST);
			return new ResponseEntity(
			"Error!\n Revisa parámetros! idcliente o idcoche incorrecta o inexistente ",
					HttpStatus.BAD_REQUEST);

		}
	}

	@PostMapping("/insertaAlquiler")
	public ResponseEntity<?> insertAlquiler(@RequestBody AlquilerDTO alquiler) {
		try {
			as.save(new AlquilerVO(0, alquiler.getFechacomienzo(), alquiler.getFechafin(),
					cos.findById(alquiler.getIdcoche()).get(), cls.findById(
					alquiler.getIdcliente()).get()));

			return new ResponseEntity<String>("Inserción alquiler correcta", HttpStatus.OK);
		} catch (NoSuchElementException e) {
			if (cos.findById(alquiler.getIdcoche()).isEmpty()) {
				return new ResponseEntity<String>("El coche no existe: " + e.getMessage(),
				HttpStatus.NOT_FOUND);
			} else {
				return new ResponseEntity<String>("El cliente no existe: " + e.getMessage(), 
				HttpStatus.NOT_FOUND);
			}
		}
	}

	@GetMapping("/listadoEntreFechas")
	public ResponseEntity<?> findBetweenFechas(@RequestParam int idcoche,
	LocalDate inicio,
	LocalDate fin) {
		try {
			List<AlquilerDTO> alquileres = new ArrayList<AlquilerDTO>();

			as.findByCocheAndFechacomienzoBetween(cos.findById(idcoche).get(), inicio, fin).forEach
			(x -> alquileres
					.add(new AlquilerDTO(x.getFechacomienzo(),
					x.getFechafin(), x.getCliente().getIdcliente())));
			if (alquileres.isEmpty())
				return new ResponseEntity(HttpStatus.NO_CONTENT);
			return new ResponseEntity<List<AlquilerDTO>>(alquileres, HttpStatus.OK);
		} catch (Exception e) {
			return new ResponseEntity("Error en la consulta, revisa parámetros", 
			HttpStatus.BAD_REQUEST);
		}
	}
}
      
      

spring.datasource.url=jdbc:mysql://localhost/mayo23
spring.datasource.username=root
spring.datasource.password=temporal
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.defer-datasource-initialization=true
spring.jpa.hibernate.ddl-auto=create

DELETE FROM pasajeros;
INSERT INTO pasajeros(dni,nombre) VALUES('32889395Q','Adrián');
INSERT INTO pasajeros(dni,nombre) VALUES('33889385A','Mati');
DELETE FROM vuelos;
INSERT INTO vuelos(identificacion,fecha_salida, hora_salida, hora_llegada,descripcion)
VALUES('FY234','2023-10-06','2023-10-06 14:00:00','2023-10-06 15:00:00','OVD-MAD');
INSERT INTO vuelos(identificacion,fecha_salida, hora_salida, hora_llegada,descripcion)
VALUES('KI934','2023-10-09','2023-10-06 15:00:00','2023-10-06 19:00:00','MAD-STD');
DELETE FROM pasajerovuelo;
INSERT INTO pasajerovuelo(pasajero_id_pasajero,vuelo_id_vuelo, numero_maletas_10, 
numero_maletas_20,embarque_prioritario, tarjeta_embarque) VALUES(1,1,2,2,true,'10A');
INSERT INTO pasajerovuelo(pasajero_id_pasajero,vuelo_id_vuelo, numero_maletas_10,
numero_maletas_20,embarque_prioritario, tarjeta_embarque) VALUES(1,2,1,2,false,'9F');
      
      

Create the templates


<!DOCTYPE html>
<html xmlns:th="thymeleaf.org">
<head>
<meta charset="utf-8">
<link rel="stylesheet" th:href="@{/style.css}">
<title>MVC</title>
</head>
<body>

	<table>
		<tr class="nohover">
			<th  colspan="4">Empleados</th>
		</tr>
		<tr class="nohover"> 
			<th>Nombre</th>
			<th>DNI</th>
			<th>Fecha Contratación</th>
			<th>Información Adicional</th>
		</tr>
		<tr th:each="empleado : ${empleados}">
			
				<td th:text="${empleado.nombre}"></td>
				<td th:text="${empleado.nif}"></td>
				<td th:text="${empleado.fechaContrato}"></td>
				<td><a th:href="@{/asignaciones/empleado
				(idEmpleado=${empleado.idEmpleado})}">
				Detalles</a></td>
			
		</tr>
	</table>
	
	<button onclick="history.back()">Volver</button>

</body>
</html>



			<tr th:each="vuelo : ${vuelos}">
				<form method="post" action="/vuelos/actualizarVuelo">
				<td>
					<input type="text" name="identificacion" th:value="${vuelo.vuelo.identificacion}">
				</td>
				<td>
					<input type="text" name="descripcion" th:value="${vuelo.vuelo.descripcion}">
				</td>
				<td>
					<input type="number" name="numero_maletas_10" th:value="${vuelo.numero_maletas_10}">
				</td>
				<td>
					<input type="number" name="numero_maletas_20" th:value="${vuelo.numero_maletas_20}">
				</td>
				<input type="hidden" name="vueloId" th:value="${vuelo.vuelo.idVuelo}">
				<td>
					<button type="submit">Guardar</button>
				</td>
				</form>
			</tr>




<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.1.0</version>
		<relativePath/> 
	</parent>
	<groupId>com.dawes</groupId>
	<artifactId>adrian_mayo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>adrian_mayo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</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-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
	<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.32</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
		<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
	</plugins>
	</build>

</project>