Verschillen in @Valid- en @Validated-annotaties in het voorjaar

1. Overzicht

In deze korte tutorial zullen we ons concentreren op de verschillen tussen @Geldig en @Gevalideerd annotaties in het voorjaar.

Het valideren van de input van gebruikers is een algemene functionaliteit in de meeste van onze applicaties. In het Java Ecosystem gebruiken we specifiek de Java Standard Bean Validation API om dit te ondersteunen. Bovendien is dit ook goed geïntegreerd met Spring vanaf versie 4.0. De @Geldig en @Gevalideerd annotaties komen voort uit deze Standard Bean API.

Laten we ze in de volgende secties in detail bekijken.

2. @Geldig en @Gevalideerd Annotaties

In het voorjaar gebruiken we JSR-303's @Geldig annotatie voor validatie op methode-niveau. Bovendien gebruiken we het ook om een ​​lidattribuut te markeren voor validatie. Deze annotatie ondersteunt echter geen groepsvalidatie.

Groepen helpen bij het beperken van de beperkingen die tijdens de validatie worden toegepast. Een specifieke use-case zijn UI-wizards. Hier, in de eerste stap, kunnen we een bepaalde subgroep velden hebben. In de volgende stap kan er een andere groep zijn die tot dezelfde boon behoort. Daarom moeten we bij elke stap beperkingen toepassen op deze beperkte velden, maar @Geldig ondersteunt dit niet.

In dit geval, voor groepsniveau moeten we Spring gebruiken @Gevalideerd, wat een variant is van deze JSR-303's @Geldig. Dit wordt gebruikt op het niveau van de methode. En voor het markeren van ledenattributen blijven we de @Geldig annotatie.

Laten we nu meteen naar binnen duiken en het gebruik van deze annotaties bekijken met een voorbeeld.

3. Voorbeeld

Laten we eens kijken naar een eenvoudig gebruikersregistratieformulier dat is ontwikkeld met Spring Boot. Om te beginnen hebben we alleen de naam en de wachtwoord attributen:

openbare klasse UserAccount {@NotNull @Size (min = 4, max = 15) privé String-wachtwoord; @NotBlank private String naam; // standard constructors / setters / getters / toString} 

Laten we vervolgens naar de controller kijken. Hier hebben we de saveBasicInfo methode met de @Geldig annotatie om de gebruikersinvoer te valideren:

@RequestMapping (value = "/ saveBasicInfo", method = RequestMethod.POST) public String saveBasicInfo (@Valid @ModelAttribute ("useraccount") UserAccount gebruikersaccount, BindingResult-resultaat, ModelMap-model) {if (result.hasErrors ()) {return " fout"; } "succes" teruggeven; }

Laten we nu deze methode testen:

@Test openbare leegte gegevenSaveBasicInfo_whenCorrectInput_thenSuccess () genereert Uitzondering {this.mockMvc.perform (MockMvcRequestBuilders.post ("/ saveBasicInfo") .accept (MediaType.TEXT_HTML) .param ("naam", "test123") wachtwoord ", param (" naam "," test123 ") .param "pass")) .andExpect (view (). name ("success")) .andExpect (status (). isOk ()) .andDo (print ()); }

Nadat we hebben bevestigd dat de test met succes wordt uitgevoerd, gaan we nu de functionaliteit uitbreiden. De volgende logische stap is om dit om te zetten naar een registratieformulier in meerdere stappen, zoals bij de meeste wizards het geval is. De eerste stap met de naam en de wachtwoord blijft onveranderd. In de tweede stap halen we aanvullende informatie op, zoals leeftijd en telefoon. Daarom werken we ons domeinobject bij met deze extra velden:

openbare klasse UserAccount {@NotNull @Size (min = 4, max = 15) privé String-wachtwoord; @NotBlank private String naam; @Min (waarde = 18, message = "Leeftijd mag niet lager zijn dan 18") private int leeftijd; @NotBlank privé String-telefoon; // standard constructors / setters / getters / toString} 

Deze keer zullen we echter merken dat de vorige test mislukt. Dit komt omdat we niet passeren in de leeftijd en telefoon velden, die nog steeds niet in de afbeelding op de gebruikersinterface staan. Om dit gedrag te ondersteunen, hebben we groepsvalidatie nodig en de @Gevalideerd annotatie.

Hiervoor moeten we de velden groeperen om twee verschillende groepen te maken. Eerst moeten we twee markeringsinterfaces maken. Een aparte voor elke groep of elke stap. Voor de exacte implementatie hiervan kunnen we verwijzen naar ons artikel over groepsvalidatie. Laten we ons hier concentreren op de verschillen in de annotaties.

We hebben de Basis informatie interface voor de eerste stap en de AdvanceInfo voor de tweede stap. Verder zullen we onze Gebruikers account klasse om deze markeringsinterfaces als volgt te gebruiken:

openbare klasse UserAccount {@NotNull (groepen = BasicInfo.class) @Size (min = 4, max = 15, groepen = BasicInfo.class) privé String-wachtwoord; @NotBlank (groups = BasicInfo.class) private String naam; @Min (waarde = 18, message = "Leeftijd mag niet minder zijn dan 18", groups = AdvanceInfo.class) private int age; @NotBlank (groups = AdvanceInfo.class) privé String-telefoon; // standard constructors / setters / getters / toString} 

Bovendien zullen we nu onze controller updaten om de @Gevalideerd annotatie in plaats van @Geldig:

@RequestMapping (value = "/ saveBasicInfoStep1", method = RequestMethod.POST) openbare String saveBasicInfoStep1 (@Validated (BasicInfo.class) @ModelAttribute ("useraccount") UserAccount gebruikersaccount, BindingResult-resultaat, ModelMap-model) {if (result.hasErrors ( )) {retourneer "fout"; } "succes" teruggeven; }

Als gevolg van deze update verloopt onze test nu met succes. Laten we nu ook deze nieuwe methode testen:

@Test openbare leegte gegevenSaveBasicInfoStep1_whenCorrectInput_thenSuccess () gooit uitzondering {this.mockMvc.perform (MockMvcRequestBuilders.post ("/ saveBasicInfoStep1") .accept (MediaType.TEXT_HTML) .param ("naam", "test123" wachtwoord) .param ("naam", "test123" wachtwoord. "pass")) .andExpect (view (). name ("success")) .andExpect (status (). isOk ()) .andDo (print ()); }

Ook dit loopt met succes. Daarom kunnen we zien hoe het gebruik van @Gevalideerd is essentieel voor groepsvalidatie.

Laten we vervolgens kijken hoe @Geldig is essentieel om de validatie van geneste attributen te activeren.

4. Met behulp van @Geldig Aantekening om geneste objecten te markeren

De @Geldig annotatie wordt met name gebruikt om geneste attributen te markeren. Dit activeert de validatie van het geneste object. Laten we bijvoorbeeld in ons huidige scenario een Gebruikersadres voorwerp:

openbare klasse UserAddress {@NotBlank private String countryCode; // standard constructors / setters / getters / toString}

Om validatie van dit geneste object te garanderen, versieren we het attribuut met de @Geldig annotatie:

openbare klasse UserAccount {// ... @Valid @NotNull (groepen = AdvanceInfo.class) privé UserAddress gebruikersadres; // standard constructors / setters / getters / toString}

5. Voors en tegens

Laten we eens kijken naar enkele voor- en nadelen van het gebruik @Geldig en @Gevalideerd annotaties in het voorjaar.

De @Geldig annotatie zorgt voor de validatie van het hele object. Belangrijk is dat het de validatie van de grafieken van het hele object uitvoert. Dit veroorzaakt echter problemen voor scenario's die slechts gedeeltelijk moeten worden gevalideerd.

Aan de andere kant kunnen we gebruiken @Gevalideerd voor groepsvalidatie, inclusief de bovenstaande gedeeltelijke validatie. In dit geval moeten de gevalideerde entiteiten echter de validatieregels kennen voor alle groepen of use-cases waarin het wordt gebruikt. Hier mengen we zorgen, vandaar dat dit kan resulteren in een antipatroon.

6. Conclusie

In deze korte tutorial hebben we de belangrijkste verschillen tussen @Geldig en @Gevalideerd Annotaties.

Tot slot gebruiken we voor elke basisvalidatie de JSR @Geldig annotatie in onze methodeaanroepen. Aan de andere kant, voor elke groepsvalidatie, inclusief groepsreeksen, moeten we Spring gebruiken @Gevalideerd annotatie in onze methodeaanroep. De @Geldig annotatie is ook nodig om de validatie van geneste eigenschappen te activeren.

Zoals altijd is de code die in dit artikel wordt gepresenteerd, beschikbaar op GitHub.