Validation — Bean Validation & Error Responses
Eingabevalidierung mit Bean Validation
Spring Boot unterstützt JSR 380 (Bean Validation 2.0) out of the box.
Lektion 16: Basis-Annotationen
record ProductDto(
@NotBlank String name,
@NotNull @Positive Double price,
@Size(min = 3, max = 50) String category
) {}
| Annotation | Bedeutung |
|---|---|
@NotBlank | Nicht null, nicht leer |
@NotNull | Nicht null |
@Size(min, max) | Länge zwischen min und max |
@Email | Gültige E-Mail-Adresse |
@Positive | Größer als 0 |
@Past / @Future | In der Vergangenheit / Zukunft |
Lektion 17: @Valid im Controller
@PostMapping
public ProductDto create(@Valid @RequestBody ProductDto dto) {
return service.create(dto);
}
Ungültige Eingabe -> 400 Bad Request mit Fehlerdetails.
Lektion 18: Custom Validators
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IbanValidator.class)
public @interface Iban {
String message() default "Invalid IBAN";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validation am Rand, nicht im Kern
Validiere am Controller-Rand (DTOs), nicht in der Domain-Logik. So bleibt der Service frei von Validierungs-Code und testbar. Der Controller ist der Trust Boundary — alles jenseits ist vertrauenswürdig.
Lektion 19: Validation Groups
interface OnCreate {}
interface OnUpdate {}
@Null(groups = OnCreate.class)
@NotNull(groups = OnUpdate.class)
Long id;
Lektion 20: Strukturierte Error-Responses
Spring Boot liefert bei Validierungsfehlern automatisch:
{
"timestamp": "2026-01-01T12:00:00",
"status": 400,
"error": "Bad Request",
"errors": [
{ "field": "name", "message": "must not be blank" }
]
}
@Validated vs. @Valid — Groups ermöglichen partielle Validierung
@Valid validiert alle Constraints. @Validated kann mit Groups arbeiten:
@Validated(OnCreate.class) prüft nur OnCreate-Constraints. So kann
dasselbe DTO für Create (id muss null) und Update (id muss nicht null)
genutzt werden.
Praxis-Szenario: CropGuard: PolicyDto-Validierung
Das PolicyDto verlangt coverageEur >= 1000, coverageEnd nach coverageStart, und ein gültiges deductible. Mit @Valid @RequestBody im Controller wird dies automatisch geprüft — bei Verletzung gibt Spring Boot 400 mit Feld-Liste zurück.
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren: