Evitar valores negativos o mayores a 100 en Spring Boot y Java [SOLUCIONADO]

Validación de Rangos en Spring Boot para Asegurar Valores Positivos y Dentro de Límites

Cuando trabajamos con aplicaciones desarrolladas en Spring Boot, uno de los puntos críticos es garantizar que los datos que ingresan al sistema sean consistentes y válidos. En particular, si estamos tratando con campos numéricos, es esencial limitar los valores a un determinado rango. Esto no solo protege la integridad de nuestra aplicación sino que también asegura su funcionamiento óptimo y la calidad de los datos.

Aquí te mostraremos cómo implementar restricciones para el ingreso de datos, concretamente, cómo gestionar y validar datos para no admitir números que sean negativos o que excedan el valor de 100 en Spring Boot. Esta capacidad es clave para aplicaciones que requieren la entrada precisa de información dentro de umbrales definidos, como sistemas de puntuación, aplicaciones financieras, gestión de inventarios, entre otros.

#### Uso de Anotaciones para Validar Datos en Spring Boot

Spring Boot ofrece una variedad de anotaciones y clases listas para usar que nos permiten añadir estas restricciones a nuestros modelos de datos con relativa facilidad. Por ejemplo, podemos usar anotaciones de validación incluidas en `javax.validation.constraints`.

Vamos a definir una clase simple llamada `Puntuacion`, la cual tiene un único atributo que no deberá ser menor que 0 ni mayor que 100. Utilizaremos la anotación `@Min` y `@Max` del API de validación de Java Bean.

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;

public class Puntuacion {

    @Min(0)
    @Max(100)
    private int valor;

    // Getters y Setters
}

Las anotaciones `@Min` y `@Max` hacen que Spring Boot lance una excepción si los valores establecidos no cumplen con los requisitos mínimos y máximos definidos.

#### Manejo de Errores de Validación

Si una solicitud falla en la validación, debemos asegurarnos de manejar adecuadamente los errores y proporcionar respuestas útiles al cliente o a la interfaz de usuario. Podemos hacer uso de un manejador de excepciones a nivel de controlador con `@ExceptionHandler`.

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

@RestControllerAdvice
public class ManejadorDeErroresGlobal {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> manejarValidacion(MethodArgumentNotValidException ex) {
        String mensajeError = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        return new ResponseEntity<>(mensajeError, HttpStatus.BAD_REQUEST);
    }
}

En este caso, si existe un error de validación, el código proporcionará una respuesta de estado `400 BAD REQUEST` junto con el mensaje de error predeterminado.

#### Integración de la Validación en los Endpoints

Una vez definidas las anotaciones en nuestro modelo y establecido el manejo de las excepciones, debemos asegurarnos de que la validación ocurra cuando se recibe la información. Para ello, integraremos las anotaciones `@Valid` en nuestros controladores, concretamente en los métodos que manejan las peticiones.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;

@RestController
@RequestMapping("/puntuaciones")
public class PuntuacionController {

    // Supongamos que tenemos un servicio inyectado para manejar las operaciones
    @Autowired
    private PuntuacionServicio puntuacionServicio;

    @PostMapping
    public ResponseEntity<Puntuacion> agregarPuntuacion(@Valid @RequestBody Puntuacion puntuacion) {
        Puntuacion nuevaPuntuacion = puntuacionServicio.guardar(puntuacion);
        return ResponseEntity.ok(nuevaPuntuacion);
    }
}

El uso de `@Valid` asegura que la `Puntuacion` pasada al método `agregarPuntuacion` será validada antes de proceder. Si hay errores, se lanzará una excepción y se manejarán de acuerdo a lo configurado en nuestro `ManejadorDeErroresGlobal`.

#### Ampliación de la Validación Personalizada

En algunos escenarios, las restricciones básicas no son suficientes y necesitamos ampliar nuestra validación. Para ello, Spring Boot nos proporciona la capacidad de crear validadores personalizados. Implementamos una validación personalizada definiendo una anotación y su respectivo validador de clase.

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = ValorRangoValidador.class)
@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValorRango {

    String message() default "El valor debe estar entre 0 y 100";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class ValorRangoValidador implements ConstraintValidator<ValorRango, Integer> {

    @Override
    public void initialize(ValorRango rango) {
        // Pueden ir configuraciones iniciales si fuera necesario
    }

    @Override
    public boolean isValid(Integer valor, ConstraintValidatorContext context) {
        return valor != null && valor >= 0 && valor <= 100;
    }
}

La anotación `@ValorRango` define la restricción personalizada, la cual utilizará el validador `ValorRangoValidador` para determinar si un valor proporcionado es válido o no.

#### Testeo y Pruebas Unitarias

Además de la correcta implementación de las restricciones de datos, es recomendable validar su correcto funcionamiento a través de pruebas unitarias. Con ello, aseguramos la estabilidad de nuestras aplicaciones y prevenimos posibles regresiones en el futuro.

Para probar el endpoint y las validaciones de nuestra clase `PuntuacionController`, podríamos escribir test usando `MockMvc` y `JUnit` para simular peticiones al servidor y verificar respuestas esperadas.

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(PuntuacionController.class)
public class PuntuacionControllerTest {

    @Autowired
    private MockMvc mockMvc;

    // Suponemos que tenemos un servicio simulado para realizar las pruebas
    @MockBean
    private PuntuacionServicio puntuacionServicio;

    @Test
    public void cuandoPuntuacionEsInvalida_EntoncesRetornaBadRequest() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.post("/puntuaciones")
                .content("{"valor": -10}")
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isBadRequest());
    }
}

Este test valida que si tratamos de guardar una puntuación con un valor fuera del rango establecido, el servidor debe responder con un estado `400 BAD REQUEST`.

#### Importancia de la Validación en Aplicaciones

garantizar que la información proporcionada no solo cumpla con ciertas reglas de negocio sino que también prevenga posibles fallos. La validación de input es una de las primeras líneas de defensa contra datos erróneos o malintencionados que pueden afectar el rendimiento y la integridad de una aplicación.

Por lo tanto, tomarse el tiempo para validar adecuadamente los datos de entrada en su aplicación Spring Boot puede ahorrar tiempo y esfuerzo en el largo plazo, además de proveer una mejor experiencia de usuario y un código más fiable y libre de errores.

Seamos cautelosos en la definición y aplicación de nuestras restricciones, y así nuestra aplicación Spring Boot no admitirá valores inesperados que podrían desencadenar comportamientos erróneos o incluso fallos del sistema. Con estas herramientas y técnicas, Spring Boot nos facilita la creación de sistemas robustos y seguros.

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad