Chuleta Java

Descargar como txt, pdf o txt
Descargar como txt, pdf o txt
Está en la página 1de 21

ARRAYLIST

ArrayList<Persona> listaPersonas = new ArrayList<>(Arrays.asList(new


Persona(1,"Juan","Pérez",25),
new Persona(2,"María","Gómez",30),
new Persona(3,"Pedro","González",28)));
ArrayList<Persona> listaPersonas= new ArrayList<>(); //Arrays vacio
public ArrayList<Persona> getAllPersonas();
listaPersonar.size(); //el tamaño del array

############# APP REST EN SPRING BOOT


########################################################################
Una API REST (Representational State Transfer) es un conjunto de convenciones y
principios de arquitectura para diseñar aplicaciones web. Permite que diferentes
tecnologías, sistemas o dispositivos se comuniquen entre sí a través de Internet,
usando HTTP como protocolo de comunicación y JSON (generalmente) como formato para
intercambiar datos.

Imagínate que tienes una aplicación que necesita acceder a información de libros
almacenada en una base de datos. En lugar de acceder directamente a la base de
datos, la aplicación puede hacer solicitudes HTTP (como GET para obtener datos,
POST para crear datos, PUT para actualizar datos y DELETE para eliminar datos) a
una API REST, que luego interactúa con la base de datos y devuelve la información
requerida a la aplicación en un formato que pueda entender y utilizar.

(UTILIZAREMOS UN EJEMPLO LIBRERIA PARA EXPLICAR CADA CAPA)


MODELS O DTO
Almacena objetos que se utilizan para transferir datos entre procesos y/o
capas.Donde se encuentran definidas los atributos de cada objeto molde. Debe ir
también los constructores y los getters y setters.Mas adelante veremos lombok que
soluciona esto.
public class BookDTO {

@NotNull //Esto es una validación simple que veremos más adelante


private Integer id;
private String titulo;
private String autor;
private Boolean reservado;
@BookCodeValidator //Esto es una validación personalizada que veremos
más adelante
private String code;

}
public class ReservationDTO {

private Integer id;


private Integer libroId;
private Integer usuarioId;
private LocalDate fechaReserva;
private LocalDate returnDate;

public class UserDTO {

private Integer id;


private String nombre;

@Email
private String correoElectronico;

LOMBOK (Nos facilita por ejemplo en hace el constructor, o los getters y setters)
//Una vez descargado lombok.jar, lo ejecutamos e instalamos para el eclipse
que estemos utilizando. Si no da errores ya estará implementada.
//En eclipse en el model hay que poner:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {
//Con esto solo nos hace falta definir los atributos.
private Integer id;
private String nombre;

BBDD
Para poder trabajar con persistencia en desarrollo con SpringBoot se deben
considerar los siguientes puntos:

1. Tener un servidor de BDD levantado. En un ambiente de desarrollo, normalmente


usamos estas dos opciones:

a. Instalar el servidor de forma local en vuestros ordenadores (postgreSQL en


nuestro caso)

b. Levantar un contenedor Docker (run) de una imagen de la bdd que se quiere usar
(en este caso Postgres

2. Configurar un server local en PgAdmyn con el fin de visualizar en todo momento


lo que sucede en nuestra BDD.

a. En ambos casos, el puerto debe ser siempre el puerto local en el que escucha mi
ordenador.

b. Hay que tener cuidado de que no exista colisión de puertos en el caso que tenga
varias instancias de BDDS, por ejemplo, el postgres local y el docker. Ejecutar
comando netstat -an

c. Si se diera el caso en el que se tienen varias instancias de servidores


corriendo, es recomendable usar otro puerto local disponible para docker tomando en
cuenta lo siguiente:

Si el puerto 5432 está ocupado y necesitas seleccionar otro puerto para alguna
instancia que corra PostgreSQL, por ejemplo, docker, puedes elegir un puerto que
esté dentro del rango de puertos dinámicos y/o privados, que va desde el 49152
hasta el 65535, según la IANA (Internet Assigned Numbers Authority).

Sin embargo, muchos desarrolladores eligen puertos dentro del rango 5433-5440 para
evitar conflictos con otros servicios y mantener una coherencia que facilite la
identificación del servicio que está utilizando el puerto.

Aquí hay algunos ejemplos de puertos que podrías usar:

i. 5434

ii. 5435
iii. 5436

iv. 5437

v. 5438

vi. 5439

vii. 5440

viii.
d. Si has decidido cambiar el puerto de docker, debes levantar un contenedor
(ejecutar el docker run) asegurándote de hacer un mapeo del puerto local disponible
al puerto 5432 de docker, que es el que usa postgre por defecto.

Ejecutar el siguiente comando, por ejemplo:

docker run --name mypostgres2 -p 5437:5432 -e POSTGRES_PASSWORD=1234 -e


POSTGRES_DB=biblioteca -d postgres

En donde -p 5437:5432 hace el mapeo del puerto local 5437 (en mi ordenador) al
puerto 5432 por defecto que usa la instancia de postgres que estamos ejecutando en
el contenedor docker.

NOTA: Si en el proyector está ya imprementado el docker-compose.yml en -->


resources --> static --> docker:
abrimos el powershell, nos metemos en esta carpeta de docker (cd); y ponemos:
docker-compose up -d. Con esto se nos levantará ya el docker.
Si nos da un fallo porque el puerto está en uso, escribimos: docker ps -a nos
mostrará los procesos de docker que está en uso, y podemos ver que en el puerto
está ejerciciondose otro proceso docker, en mi caso el tomcat. Para pararlo
escribimos: docker stop tomcat-rickmorty
Y metemos docker-compose up -d de nuevo y ya nos debería levantar el proyecto.

3. Configurar propiedades de spring boot.En Resources --> aplicattion.properties

#Datasource configuration para postgres

#Datasource configuration para postgres


spring.sql.init.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/tienda #tienda es el
nombre de la bbdd en postgres
spring.datasource.username=postgres #la contraseña y username se
define al instalarnos postgres
spring.datasource.password=postgres

spring.sql.init.mode=always
spring.jpa.hibernate.ddl-auto=update

4. Configura dependencias Maven (dentro del pom)

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>
<dependency>

<groupId>org.postgresql</groupId>

<artifactId>postgresql</artifactId>

</dependency>

5. Crear paquete .persistence y dentro de ella otro dos paquetes: .entities


y .repositories.En el paquete .entities creamos las clases parecido a los models:
BookEntity,ReservationEntity,UserEntity.
Anotar las clases que usaremos como entidades: Para que spring boot sepa cuáles
clases debe usar como tablas en la BDD, se debe anotar dicha clase con @Entity.

a. Anotar clase con @Entity(name = "Book")

b. Anotar el atributo que sea el id de la tabla:

@Id

@GeneratedValue(strategy = GenerationType.SEQUENCE) //para posgres

//@GeneratedValue(strategy = GenerationType.IDENTITY) //usado para mysql

private Integer id;

Existen más anotaciones para los atributos de las clases (consultar) como por
ejemplo:
//Cuando un campo, muchos de ello pertenezca a un solo, por ejemplo muchos libros
pertenece a un autor, pondremos:
@ManyToOne

@JoinColumn(name = "autor_id")

private AutorEntity autor;

//Y en autor, que un autor puede tener varios libros:


@OneToMany(mappedBy = "autor")

private List<LibroEntity> libros = new ArrayList<>();

6. Crear los repositorios de cada clase: por cada clase se debe crear una interface
que extienda de JPARepository y además se debe anotar dicha interface con
@Repository

Ejemplo:

@Repository
public interface BookRepository extends JpaRepository<BookEntity, Integer>{

7. Hacer el mapeo de las clases que usemos como dtos a entities y viceversa.
Para ello:
-Añadir dependencias y los plugins (en caso de usar lombok) en el pomk:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

Hecho esto actualizamos el pom :click derecho en nuestro proyecto --> Maven -->
Update proyect

Probamos a si se nos levanta, si si pues todo bien;


si no, debemos clean el maven:
click derecho en nuestro proyecto --> Run as -->Maven build -->Goals: clean
validate compile y marcamos skip tests --> run

Hecho esto nos creamos un paquete .mappers (esto sirve para enlazar los dtos y los
entities, para poder usar métodos que nos sirva para actualizar la bbdd) y dentro
nuestras interfaces:BookMapper ....
en la interfaz bookMapper:
@Mapper(componentModel = "spring")
public interface BookMapper {

public BookDTO mapEntityToDTO(BookEntity bookEnt);

public BookEntity mapDtoToEntity(BookDTO bookDto);

//Al tener @OneToMany y @ManyToOne esto cambia:


//En libroMapper: (ManyToOne)
@Mapper(componentModel = "spring")
public interface LibroMapper {

@Mapping(source = "autor", target = "id", qualifiedByName = "mapAutorId")


LibroDTO toDto(LibroEntity libro);

LibroEntity toEntity(LibroDTO libroDTO);


@Named("mapAutorId")
default Long mapAutorId(AutorEntity autor) {
if (autor == null) {
return null;
}
return autor.getId();
}
}

//En AutorMapper: (OneToMany)


@Mapper(componentModel = "spring", uses = {LibroMapper.class})
public interface AutorMapper {

AutorDTO toDto(AutorEntity autor);


AutorEntity toEntity(AutorDTO autorDTO);

8.Ya nos faltaría cambiar los métodos en los services, usando mapeo.

a. Hay varias formas, pero por lo general se usa la librería Structs

SERVICES
En Spring Boot, un servicio es una abstracción que define un conjunto de
operaciones relacionadas con la lógica de negocio. El término "servicio" puede
referirse tanto al concepto como a la implementación concreta en código.

Aquí hay algunas características clave de los servicios en Spring Boot y cómo se
utilizan:

Separación de Responsabilidades:

· Un servicio en Spring Boot generalmente se encarga de la lógica de negocio. Esto


significa que no se preocupa por cómo se presentan los datos al usuario (eso es
responsabilidad de los controladores) o cómo se almacenan los datos (eso es
responsabilidad de los repositorios).

Anotación @Service:

· En Spring, las clases que implementan la lógica de negocio se anotan a menudo con
@Service. Esto le dice a Spring que esta clase es un candidato para la detección
automática al escanear los paquetes de la aplicación y para la inyección de
dependencias.

Transacciones:

· Los servicios son a menudo el lugar donde se manejan las transacciones de base de
datos. Spring proporciona soporte declarativo para transacciones que se pueden
agregar mediante anotaciones como @Transactional.

Inyección de Dependencias:

· Los servicios suelen necesitar acceder a varias dependencias, como objetos de


acceso a datos (DAOs) o repositorios. Spring Boot hace uso de la inyección de
dependencias para proporcionar estas dependencias a los servicios sin que los
servicios tengan que construirlas o buscarlas.

Singularidad:
· A menudo, las instancias de servicios son beans singleton, lo que significa que
hay una única instancia de un servicio en toda la aplicación. Esto es gestionado
por el contenedor de Spring y ayuda a mantener la coherencia y el estado cuando es
necesario.

Reutilización:

· Los servicios pueden ser reutilizados por diferentes partes de la aplicación. Por
ejemplo, un servicio de autenticación podría ser utilizado por diferentes
controladores que manejan el login o la verificación de la identidad del usuario.

Pruebas:

· Los servicios suelen ser diseñados para ser fácilmente testeables. Esto puede
implicar la definición de interfaces claras y el uso de inyección de dependencias
para intercambiar implementaciones reales con dobles de prueba o mocks.

public interface BookService {

List<BookDTO> getAllbooks();

void createBook(BookDTO book);

Boolean IsReserved(Integer bookId) ;

BookDTO getBook(Integer bookId);

String getCode(Integer bookId);

}
@Service //Anotación @Service que siempre se tiene que poner al tener una clase
service.
public class BookServiceImpl implements BookService {

ArrayList<BookDTO> libros = new ArrayList<>();


BookDTO b1 = new BookDTO(1, "LibroT1", "Cervantes", false,"AAA123");
BookDTO b2 = new BookDTO(2, "LibroT2", "María", false, "AAA123");
BookDTO b3 = new BookDTO(3, "LibroT3", "Juana", false, "AAA123");

public BookServiceImpl() {
libros.add(b1);
libros.add(b2);
libros.add(b3);
}

@Override
public ArrayList<BookDTO> getAllbooks() {

return libros;
}

@Override
public void createBook(BookDTO book) {
libros.add(book);

}
@Override
public Boolean IsReserved(Integer id) {
String code = getCode(id);
for (BookDTO b : libros) {

if (b.getCode().equals(code)) {
return b.getReservado();
}
}

return null; // libro no encontrado


}

@Override
public String getCode(Integer bookId) {
for (BookDTO b : libros) {
if (b.getId() == bookId) {
return b.getCode();
}
}

throw new BookNotFoundException("No existe un libro con el id: " +


bookId); // libro no encontrado
}

@Override
public BookDTO getBook(Integer bookId) {

for(BookDTO bo: libros) {


if(bo.getId() == bookId) {
return bo;
}
}

return null;
}

public interface ReservationService {

void reserveBook(Integer bookId, Integer userId);

void cancelReservation(Integer bookId, Integer userId);

ArrayList<ReservationDTO> getAllReservations();

ArrayList<ReservationDTO> getAllReservations(Integer userId);

ArrayList<ReservationDTO> getActiveReservation(Integer userId);

@Service
public class ReservationServiceImpl implements ReservationService {

ArrayList<ReservationDTO> reservas = new ArrayList<>();

BookService bookService;
UserService userService;

Integer cont = 1;

// DI de los beans que usará spring en tiempo de ejecución.


public ReservationServiceImpl(BookService bookService, UserService
userService) {
this.bookService = bookService;
this.userService = userService;
}

@Override
public void reserveBook(Integer bookId, Integer userId) {

BookDTO book = bookService.getBook(bookId);

if (book != null) {
if (book.getReservado()) {
throw new ReservationConflictException("El libro con id: "
+ bookId + " ya se encuentra reservado");
} else {
book.setReservado(true);
ReservationDTO reserva = new ReservationDTO(cont, bookId,
userId, LocalDate.now(), null);
reservas.add(reserva);
cont++;
}
} else {
throw new BookNotFoundException("No extieste el libro con id: " +
bookId);
}
}

@Override
public void cancelReservation(Integer bookId, Integer userId) {
for (ReservationDTO re : reservas) {

if (re.getLibroId() == bookId && re.getUsuarioId() == userId) {


if (re.getReturnDate() != null) {
throw new ReservationConflictException(
"la persona con id: " + userId + " ya ha
devuelto el libro con id" + bookId);
} else {
re.setReturnDate(LocalDate.now());
}

} else {
throw new ReservationConflictException(
"No existe una reserva para el user id:" +
userId + " y el libro con id: " + bookId);

}
}

@Override
public ArrayList<ReservationDTO> getActiveReservation(Integer userId) {
ArrayList<ReservationDTO> activeReservations = new ArrayList<>();

for (ReservationDTO re : reservas) {


if (re.getUsuarioId() == userId) {
if (re.getReturnDate() == null) {
activeReservations.add(re);
}

} else {
throw new ReservationConflictException(
"La persona con el user id:" + userId + " nunca
ha reservado un libro ");
}
}

return activeReservations;
}

@Override
public ArrayList<ReservationDTO> getAllReservations() {

return reservas;
}

@Override
public ArrayList<ReservationDTO> getAllReservations(Integer userId) {
ArrayList<ReservationDTO> reservations = new ArrayList<>();

for (ReservationDTO re : reservas) {


if (re.getUsuarioId() == userId) {
reservations.add(re);
}
}

if (reservations.isEmpty()) {
throw new ReservationConflictException(
"La persona con el user id:" + userId + " nunca ha
reservado un libro ");
}

return reservations;
}

public interface UserService {

UserDTO getUser(Integer id);

Boolean existUser(Integer id);

@Service
public class UserServiceImpl implements UserService{

// private Integer id;


// private String nombre;
//
// @Email
// private String correoElectronico;

List<UserDTO> usuarios = Arrays.asList(


new UserDTO(1, "Angel", "[email protected]"),
new UserDTO(2, "Gynny", "[email protected]"),
new UserDTO(3, "José", "[email protected]"));

@Override
public UserDTO getUser(Integer id) {

return null;
}

@Override
public Boolean existUser(Integer id) {
for(UserDTO u : usuarios) {
if(u.getId() ==id) {
return true;
}
}

return false;
}

EXCEPCIONES PERSONALIZADAS
Almacena clases de excepciones personalizadas para manejar errores y problemas
específicos del negocio.
(Sirve en el mercado cuando te piden que se tenga que devolver una excepción
personalizada y no el rollazo del postman)
Para manejar excepciones siguiendo la especificación RFC 7807, podemos utilizar la
anotación @RestControllerAdvice para crear una clase de manejo de excepciones
personalizada. Esta clase debe extender la clase RestControllerAdvice y utilizar el
método @ExceptionHandler() para registrar los manejadores de excepciones.

//Hay que crear un paquete excepciones donde tendrá nuesta clases de


excepciones(BookNotFoundException y ReservationConflictException):

package edu.cesur.fullstack.exceptions;

public class BookNotFoundException extends RuntimeException {

public BookNotFoundException(String message) {


super(message);

}
}

package edu.cesur.fullstack.exceptions;

public class ReservationConflictException extends RuntimeException {

public ReservationConflictException(String message) {


super(message);

}
}

//Para una excepción personalizada debemos de seguir un estándar:


//Dentro del paquete excepciones, hay que crear un paquete handlers(capturadores),
y dentro de ella una clase global: GlobalHandlerException.Dentro se pondrá:
package edu.cesur.fullstack.exceptions.handlers;

import java.net.URI;
import java.time.Instant;

import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import edu.cesur.fullstack.exceptions.ReservationConflictException;
import edu.cesur.fullstack.exceptions.BookNotFoundException;

@RestControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler( BookNotFoundException.class ) //Aqui hay que poner la


clase de tu excepcion
public ProblemDetail handleBookNotFoundException(BookNotFoundException e) {
//Aqui tambien

ProblemDetail problemDetail =
ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, e.getMessage()); //Aquí se
pondrá el tipo de excepcion, bad_request, not_found......
problemDetail.setTitle("Book Exception Occurred"); //Esto es para
informar "Book" es lo que se cambia
problemDetail.setType(URI.create("http://cesurformacion.com"));
problemDetail.setProperty("errorCategory", "Book"); //"Book" cambiable
problemDetail.setProperty("timeStamp", Instant.now());

return problemDetail;
}

/*Con esto conseguimos que el postman nos salga la excepción personalizada y no un


error muy largo:
"type": "http://cesurformacion.com",
"title": "Book Exception Occurred",
"status": 400,
"detail": "No existe un libro con ese id",
"instance": "/libro/0",
"errorCategory": "Book",
"timeStamp": "2023-10-18T17:38:41.263753300Z"
*/

@ExceptionHandler( ReservationConflictException.class )
public ProblemDetail
handleReservationConflictException(ReservationConflictException e) {

ProblemDetail problemDetail =
ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, e.getMessage());
problemDetail.setTitle("Reservation Exception Occurred");
problemDetail.setType(URI.create("http://cesurformacion.com"));
problemDetail.setProperty("errorCategory", "Reservation");
problemDetail.setProperty("timeStamp", Instant.now());

return problemDetail;
}

@ExceptionHandler( MethodArgumentNotValidException.class )
public ProblemDetail
handleReservationConflictException(MethodArgumentNotValidException e) {

ProblemDetail problemDetail =
ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, e.getLocalizedMessage());
problemDetail.setTitle("Custom Exception Occurred");
problemDetail.setType(URI.create("http://cesurformacion.com"));
problemDetail.setProperty("errorCategory", "Book");
problemDetail.setProperty("timeStamp", Instant.now());

return problemDetail;
}

VALIDACIONES
Almacena iterfaces y clases con validaciones personalizadas.

Antes de hacer una validación en un nuevo proyecto hay que añadir la siguiente
dependencia en el pom.xml:
<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-validation</artifactId>

</dependency>

VALIDACIONES SIMPLES
Se colocan encima de los atributos dentro de los models y también hay
que validarla en los atributos de los métodos que use dicho atributo dentro de los
controllers con @Validated.A continuación se mostrará los diferentes
tipos de anotaciones:
@NotNull: Esta anotación se utiliza para marcar un campo o parámetro
como no nulo.
@NotEmpty: Significa que la cadena no debe ser nula y debe tener una
longitud mayor que cero.
@NotBlank: Similar a @NotEmpty, pero se aplica específicamente a
cadenas.
@Size: Puede especificar valores mínimos y máximos para el tamaño.
@Positive: Se utiliza para asegurarse de que un valor numérico sea
estrictamente mayor que cero.
@Negative: Se utiliza para asegurarse de que un valor numérico sea
estrictamente menor que cero.
@Min @Max: Estas anotaciones se utilizan para definir valores mínimos y
máximos para campos numéricos.
@Pattern: Permite especificar una expresión regular que debe coincidir
con el valor del campo.
@Email: Se utiliza para validar que una cadena es una dirección de
correo electrónico válida.
@AssertTrue y @AssertFalse: Estas anotaciones se utilizan para
verificar si una expresión booleana es verdadera o falsa, respectivamente.
@Future y @Past: Estas anotaciones se utilizan para validar fechas.
@Future garantiza que una fecha esté en el futuro, mientras que @Past garantiza que
esté en el pasado.
@Valid: Esta anotación se utiliza para indicar que se debe realizar una
validación recursiva en un objeto anidado. Es útil cuando se trabaja con objetos
complejos que contienen otros objetos.

Ejemplo:
@NotNull
String nombre;
También hay que validarla en los atributos de los métodos que use
String nombre dentro de los controllers:
public ResponseEntity<?> createPersona(@RequestBody @Validated Persona
persona) //@Validated

VALIDACIONES PERSONALIZADAS
Tenemos que crearnos un paquete validators y dentro primero creamos una
@annotation --> Marcamos Add @Retention --> Runtime --> Add @Target --> Field

package edu.cesur.fullstack.validators;

import static java.lang.annotation.ElementType.FIELD;


import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;

@Retention(RUNTIME)
@Target(FIELD)
@Constraint(validatedBy = BookCodeValid.class)
public @interface BookCodeValidator {
String message() default "Código inválido."
+ " Debe contener exactamente 3 letras seguidas de 3 números.";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

//Clase validadora
package edu.cesur.fullstack.validators;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BookCodeValid implements ConstraintValidator<BookCodeValidator,
String> {//BookCodeValidator será el nombre de la interfaz de anotacion ,String es
donde ponemos el tipo de archivo que queremos validar

//definimos el patrón con java regex


private static final Pattern CODE_PATTERN = Pattern.compile("^[A-Za-z]{3}\\
d{3}$");

@Override
public void initialize(BookCodeValidator constraintAnnotation) {
}

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
log.info("Código null");
return false;
}

Matcher matcher = CODE_PATTERN.matcher(value);


//return matcher.matches();

return Pattern.compile("^[A-Za-z]{3}\\d{3}$").matcher(value).matches();
//directo
}

VALIDACIONES EN GRUPO (cuando en los métodos se quiere validar solo algunos en


concretos, pues creamos grupos de validaciones)
Si queremos que el atributo edad no puede ser null, al crear una persona:
en el model:
@NotNull(groups = OnCreate.class) //OnCreate es una interfaz que hay que
crear en validaciones
private Integer edad;

en el controller:
public ResponseEntity<?> createPersona(@RequestBody
@Validated(OnCreate.class) Persona persona) {

Si queremos que el atributo id no puede ser null, al crear una persona y


tambien al actualizar una persona:
en el model:
@NotNull(groups = {OnCreate.class,OnUpdate.class})
private Integer id;

en el controller: //hay que importar los paquetes de las validaciones.


public ResponseEntity<?> createPersona(@RequestBody
@Validated(OnCreate.class) Persona persona) {
public ResponseEntity<?> updatePersona(@RequestBody
@Validated(OnUpdate.class) Persona persona) {

CONTROLLERS
Los controladores en Spring Boot son componentes fundamentales que actúan como la
capa de presentación en la aplicación. Son responsables de manejar las solicitudes
entrantes del usuario, procesarlas y devolver las respuestas adecuadas. Aquí está
el desglose de su función y cómo se utilizan:
Punto de Entrada:

· Los controladores son la puerta de entrada para las solicitudes HTTP que llegan a
su aplicación. Definen puntos de acceso, también conocidos como endpoints, que los
clientes pueden invocar.

Anotación @RestController:
· En Spring Boot, una clase de controlador se anota con @RestController, indicando
que está lista para manejar las solicitudes web y que su retorno se debe tomar como
el cuerpo de la respuesta (no como una vista).

Mapeo de Solicitudes:

· Dentro de un controlador, se utilizan anotaciones como @GetMapping, @PostMapping,


@PutMapping, @DeleteMapping, etc., para mapear solicitudes HTTP específicas a
métodos individuales en el controlador.

Manejo de Datos:

· Los controladores a menudo utilizan anotaciones como @RequestParam,


@PathVariable, @RequestBody, y @ResponseBody para manejar datos entrantes y
salientes en las solicitudes y respuestas.

Validaciones:

· Los controladores pueden aplicar validaciones a las solicitudes entrantes,


asegurándose de que los datos sean correctos antes de procesarlos. Spring Boot
admite validaciones con anotaciones como @Valid o @Validated.

Inyección de Dependencias:

· Los controladores suelen tener servicios inyectados que contienen la lógica de


negocio necesaria para procesar la solicitud. Esto se logra a través de la
inyección de dependencias con @Autowired o constructores.

Desacoplamiento:

· Los controladores están desacoplados de la lógica de negocio y la persistencia de


datos, lo que facilita la mantenibilidad y las pruebas. Se enfocan únicamente en el
manejo de solicitudes y delegan la lógica de negocio a los servicios.

Pruebas:

· Los controladores se pueden probar de forma aislada utilizando frameworks de


pruebas como JUnit y Mockito, junto con las capacidades de prueba de Spring como
@WebMvcTest.

Respuestas HTTP:

· Los controladores son responsables de configurar detalles de la respuesta HTTP,


como el código de estado, los encabezados y el cuerpo, utilizando ResponseEntity o
directamente a través del cuerpo del método.

//EJEMPLO
package edu.cesur.fullstack.controllers;

import java.net.URI;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import edu.cesur.fullstack.model.BookDTO;
import edu.cesur.fullstack.services.BookService;

@RestController
@RequestMapping("/books") // "/books" es como lo buscaremos en el postman
public class BookRestController {

@Autowired //Inyección de Dependencias


BookService bookService;

@PostMapping() //@PostMapping() sirve para crear datos


public ResponseEntity<?> createBook(@RequestBody @Validated BookDTO book)
{ //ResponseEntity<?> se usa para manejar el codigo de estado //Se usa tambien
@Validated porque en este método se gestiona validaciones

bookService.createBook(book);

//La ubicacion URI siempre la tendremos que poner si queremos crear algo.Será
siempre igual, copiar y pegar.
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(book.getId())
.toUri();

return ResponseEntity.created(location).build();

@GetMapping() //@GetMapping() sirve para una consulta en el postman


public ResponseEntity<?> getAllBooks(){
return ResponseEntity.ok(bookService.getAllbooks());
}

package edu.cesur.fullstack.controllers;

import java.net.URI;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import edu.cesur.fullstack.services.ReservationService;

@RestController
@RequestMapping("/reservations")
public class ReservationRestController {

@Autowired
ReservationService reservationService;

@PostMapping("/{bookId}/{userId}")
public ResponseEntity<?> reserveBook(@PathVariable Integer bookId,
@PathVariable Integer userId){

reservationService.reserveBook(bookId, userId);

URI location = ServletUriComponentsBuilder


.fromCurrentRequest()
.path("/")
.buildAndExpand()
.toUri();

return ResponseEntity.created(location).build();

@GetMapping()
public ResponseEntity<?> getAll(){
return ResponseEntity.ok(reservationService.getAllReservations());
}

@PatchMapping("/books/{bookId}/users/{userId}")
public ResponseEntity<?> cancelReservation(@PathVariable Integer bookId,
@PathVariable Integer userId){

reservationService.cancelReservation(bookId, userId);

return ResponseEntity.noContent().build();

################ PROCESOS EN JAVA


######################################################
CONEXIÓN PADRE-HIJO
//clase padre (aqui se iniciará y será dond el usuario introduzca algo por
pantalla)
package Tarea2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Scanner;

public class Padre_NumAleatorio {

public static void main(String[] args) {


try {
Process hijo = new ProcessBuilder("java", "-jar", "C:\\Prueba\\
numerosaleatorios.jar").start(); //numerosaleatorios.jar será un
archivo donde se enlace con el hijo
//lectura por teclado de la informacion a enviar al proceso hijo
Scanner in = new Scanner(System.in);

//Obtenemos la entrada estandard del proceso hijo (stdin)


BufferedReader br = new BufferedReader(new
InputStreamReader(hijo.getInputStream()));

//Obtenemos la salida standar del proceso hijo (sdout)


PrintStream ps= new PrintStream(hijo.getOutputStream());

String cadena="";

while(!cadena.equalsIgnoreCase("fin")) {

System.out.println("Introduzca una cadena de caracteres:


");
cadena = in.nextLine();

// Se envia la cadena de caracteres proceso hijo


ps.println(cadena);

//Volcado de toda la informacion


ps.flush();

//Lectura de la salida del proceso hijo


System.out.println(br.readLine());

System.out.println("Proceso Finalizado");

} catch (IOException e) {
e.printStackTrace();
}
}
}

//clase hijo (donde recogerá la informacion del padre y se hará todo la lógica y
devolverá informacion para que reciba el padre)
package Tarea2;

import java.util.Scanner;

public class Hijo_NumAleatorio {

public static void main(String[] args) {


Scanner lector = new Scanner(System.in);
String cadena= lector.nextLine();

while(cadena!= null) {
if(!cadena.equalsIgnoreCase("fin")){

//Con el metodo math generamos numeros aleatorios


int aleatorios=(int)(Math.random()*(10))+0;

// Imprimimos el número aleatorio


System.out.println("Proceso hijo: " + aleatorios);

// Leemos la siguiente cadena de texto


cadena=lector.nextLine();
}else{
System.out.println("Proceso padre finalizado");}
}

(IMPORTANTE!!)
Una vez hecha la logica padre e hijo, tenemos que crearnos el archivo .jar que hace
de puente entren los dos.
Para ello: --> File --> export --> Java --> Runnable JAR file --> Launch
configutation: Hijo_NumAleatorios - PracticaProcesos (Aqui elegimos la clase hijo)
--> Export destination: C:\Prueba\numerosaleatorios.jar (elegimos la ubicacion y
nombre del archivo .jar que definimos en la clase padre) --> Finish

######################## REGULAR EXPRESION


###########################################

Coincidencia de Caracteres Literales:


a: Coincide con el carácter 'a' literalmente.

Clases de Caracteres:
[a-z]: Coincide con cualquier letra minúscula.
[A-Z]: Coincide con cualquier letra mayúscula.
[0-9]: Coincide con cualquier dígito.
[a-zA-Z]: Coincide con cualquier letra, tanto minúscula como mayúscula.

Caracteres Especiales:
.: Coincide con cualquier carácter excepto el salto de línea.
\d: Coincide con un dígito (equivalente a [0-9]).
\w: Coincide con un carácter alfanumérico o guion bajo.
\s: Coincide con un espacio en blanco (espacio, tabulación, salto de línea,
etc.).

Cuantificadores:
*: Coincide con cero o más repeticiones del elemento anterior.
+: Coincide con una o más repeticiones del elemento anterior.
?: Coincide con cero o una repetición del elemento anterior.
{n}: Coincide con exactamente n repeticiones del elemento anterior.
{n,}: Coincide con al menos n repeticiones del elemento anterior.
{n, m}: Coincide con entre n y m repeticiones del elemento anterior.

Anclajes:
^: Coincide con el inicio de una cadena.
$: Coincide con el final de una cadena.

Grupos y Alternativas:
(abc): Crea un grupo de caracteres, que coincide con "abc".
a|b: Coincide con "a" o "b".

Escape de Caracteres:
\\: Para escapar caracteres especiales. Por ejemplo, \\. coincide con un
punto literal.
Modificadores:
i: Realiza una coincidencia sin distinción entre mayúsculas y minúsculas.
g: Realiza una coincidencia global, buscando todas las ocurrencias en lugar
de detenerse en la primera.

También podría gustarte