Si je l'ai implémenté avec de nombreuses annotations dans le modèle d'origine, j'ai reçu une critique disant "C'est difficile à voir, donc si vous faites vos propres annotations et que vous l'utilisez, ce sera plus facile à voir", alors je l'ai essayé.
before
classe de contrôleur
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {
/**
*Exemple d'API d'acquisition de données
*
* @id de paramètre ID de données d'échantillon
* @retour Informations détaillées sur les exemples de données
*/
@GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
@ResponseStatus(HttpStatus.OK)
public Response getSampleDataDetails(@Nonnull @Pattern(regexp = "[0-9]{8}")
@PathVariable final String id) {
log.info(String.format("SampleController { id : %s }", id));
return idUseCase.getSampleDataDetails(id);
}
}
classe de modèle
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ModelSample {
@NotBlank
@Size(max = 1024)
private String name;
@Digits(integer = 3, fraction = 2)
private Double percentage;
}
after
classe de contrôleur
@Validated
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {
/**
*Exemple d'API d'acquisition de données
*
* @id de paramètre ID de données d'échantillon
* @retour Informations détaillées sur les exemples de données
*/
@GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
@ResponseStatus(HttpStatus.OK)
public Response getSampleDataDetails(@Id @Valid @Nonnull
@PathVariable final String id) {
log.info(String.format("SampleController { id : %s }", id));
return idUseCase.getSampleDataDetails(id);
}
}
classe de modèle
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Validated
public class ModelSample {
@Name
@Valid
private String name;
@Percentage
@Valid
private Double percentage;
}
Vous pouvez sentir que les annotations sont actualisées avant / après. Pour réaliser cela, créez d'abord une classe d'annotations.
ʻId annotation class`
@Target(ElementType.PARAMETER)
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Pattern(regexp = "[0-9]{8}")
@Nonnull
public @interface Id {
String message() default "id: don't match format";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Target
L'argument @ Target
spécifie où appliquer l'annotation.
valeur | Où postuler |
---|---|
ElementType.TYPE | Classe, interface, annotation, type enum |
ElementType.FIELD | champ |
ElementType.CONSTRUCTOR | constructeur |
ElementType.METHOD | Méthode |
@Retention Dans l'argument de «@ Retention», spécifiez la plage pour contenir l'annotation.
valeur | Plage à tenir |
---|---|
RetentionPolicy.RUNTIME | Tenez au moment de l'exécution. |
RetentionPolicy.CLASS | Gardez dans le fichier de classe. (Non conservé lors de l'exécution.) |
RetentionPolicy.SOURCE | Gardez dans le fichier source. (Il n'est pas conservé dans le fichier de classe.) |
Si vous n'ajoutez pas * @Retention, RetentionPolicy.CLASS
sera la valeur par défaut.
@Constraint
Dans l'argument de @ Constraint
, attribut validateBy, spécifiez la validation à exécuter par cette annotation. Si vous souhaitez implémenter votre propre processus de validation, spécifiez ici la classe de validateur qui implémente le processus. Cette fois, nous allons créer une combinaison de contraintes existantes, donc cet argument est laissé vide.
Ajoutez des annotations de contrainte telles que «@ Pattern» et «@ Nonnull» à votre propre classe d'annotations. L'annotation ajoutée ici est vérifiée lors de la validation de la classe à l'aide de l'annotation d'origine.
@interface
Vous pouvez définir vos propres annotations en utilisant @ interface
.
message
Pour message
, spécifiez le message lorsque la contrainte est violée.
groups
groups
spécifie un attribut pour déterminer s'il faut exécuter la vérification des contraintes en fonction de la situation. L'attribut groups vous permet de regrouper des contraintes dans n'importe quel groupe, et vous pouvez spécifier ce groupe lors de l'exécution de la validation pour vérifier différentes contraintes pour chaque groupe. Cette fois, il n'est pas nécessaire de les regrouper, il est donc implémenté vide.
payload
payload
spécifie un attribut qui donne une catégorie arbitraire, telle que la gravité, pour les violations de contrainte. Je vais l'utiliser au besoin, mais cette fois il n'y a pas de catégorie particulière, donc je l'implémente vide.
List
List
est une annotation imbriquée et est utilisée lorsque la même contrainte est définie plusieurs fois dans des conditions différentes. Cette fois, nous n'utiliserons pas la même contrainte car nous ne la définirons pas plusieurs fois dans des conditions différentes.
De même, créez des annotations pour «nom» et «pourcentage».
Classe d'annotation pour name
@Target(ElementType.FIELD)
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Size(max = 1024)
@NotBlank
public @interface Name {
String message() default "name: don't match format";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Classe d'annotation pour «pourcentage»
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Digits(integer = 3, fraction = 2)
public @interface Percentage {
String message() default "percentage: don't match format";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Size Indique que la longueur de la chaîne dans le champ cible se situe dans la plage de tailles spécifiée.
@Digits
Spécifiez le nombre maximum de chiffres dans la partie entière pour ʻintégrateuret le nombre maximum de chiffres pour la partie fractionnaire dans
fraction.
@Digits (integer = 3, fraction = 2)` signifie que "sur le nombre maximum de chiffres, 2 chiffres sont le maximum après la virgule décimale".
classe de contrôleur
@Validated
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {
/**
*Exemple d'API d'acquisition de données
*
* @id de paramètre ID de données d'échantillon
* @retour Informations détaillées sur les exemples de données
*/
@GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
@ResponseStatus(HttpStatus.OK)
public Response getSampleDataDetails(@Id @Valid @Nonnull
@PathVariable final String id) {
log.info(String.format("SampleController { id : %s }", id));
return idUseCase.getSampleDataDetails(id);
}
}
classe de modèle
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Validated
public class ModelSample {
@Name
@Valid
private String name;
@Percentage
@Valid
private Double percentage;
}
Vous pouvez ajouter votre propre processus de validation au lieu de combiner des contraintes existantes pour créer une annotation comme celle-ci. Dans un tel cas, nous implémenterons la classe de validateur. Nous mettrons en œuvre le processus de validation des identifiants créé cette fois.
ʻId annotation class`
@Target(ElementType.PARAMETER)
@Retention(RUNTIME)
@Constraint(validatedBy = {idValidator.class})
@Pattern(regexp = "[0-9]{8}")
@Nonnull
public @interface Id {
String message() default "id: don't match format";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Classe d'implémentation du traitement de validation
public class IdValidator implements ConstraintValidator<id, String> {
@Override
public void initialize(Id id) {}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
String pattern = "[0-9]{8}";
if (!StringUtils.isEmpty(value)) {
return value.matches(pattern);
}
return false;
}
}
@Constraint
Définissez la classe de traitement de validation dans @ Constraint
.
ConstraintValidator<A,T>
Varidata doit implémenter ConstraintValidator <A, T>
. A est l'annotation de contrainte et T est le type de valeur d'entrée. Cette fois, j'ai créé une annotation de contrainte par moi-même, donc je l'ai implémentée en supposant que A recevra la classe id et T recevra la valeur sous forme de chaîne.
A est initialize et T est le type d'argument de isValid.
initialize ʻInitialize` vous permet d'obtenir la valeur d'attribut de l'annotation de contrainte définie dans la propriété JavaBeans. Je n'en ai pas besoin cette fois, alors je l'ai créé vide.
isValid Si la validation est effectuée avec ʻisValid` et que la valeur de retour est false, ConstraintVaiolation sera générée comme un échec de validation. Le processus sera décrit ici. Cette fois, il détermine si la valeur reçue correspond à l'expression régulière et renvoie vrai ou faux. S'il n'est pas inclus dans l'instruction if en premier lieu, il peut être déterminé que la valeur reçue n'est pas une chaîne, donc false est renvoyé.
L'utilisation est la même que lors de la création en combinant des annotations existantes.
@Validated
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping(path = "/sample")
public class SampleController {
/**
*Exemple d'API d'acquisition de données
*
* @id de paramètre ID de données d'échantillon
* @retour Informations détaillées sur les exemples de données
*/
@GetMapping(path = "{id}", produces = "application/json; charset=UTF-8")
@ResponseStatus(HttpStatus.OK)
public Response getSampleDataDetails(@Id @Valid @Nonnull
@PathVariable final String id) {
log.info(String.format("SampleController { id : %s }", id));
return idUseCase.getSampleDataDetails(id);
}
}
Encore une fois, faites attention à ce qui suit.
On m'a dit: «Faites vos propres annotations!» Et j'ai appris que vous pouvez faire vos propres annotations. Quand je l'ai fait, la classe de modèles est devenue beaucoup plus propre et plus facile à voir. J'ai pensé que c'était un mérite qu'il soit devenu plus facile de comprendre quel type de validation était appliqué à chacun. L'implémentation des annotations n'a pas été trop difficile, mais il m'a fallu un certain temps pour réaliser que cela ne fonctionnerait pas sans les «@ Validated» et «@ Valid» dans le Controller et les classes qui utilisent les annotations.
Démarrez avec Java EE 7 (23) - Bases de la validation de Bean http://enterprisegeeks.hatenablog.com/entry/2016/02/15/072944
Démarrez avec Java EE 7 (24) - Créez des contraintes personnalisées avec Bean Validation http://enterprisegeeks.hatenablog.com/entry/2016/02/29/072811
Détails fonctionnels de TERASOLUNA Global Framework --5.5 Vérification des entrées https://terasolunaorg.github.io/guideline/public_review/ArchitectureInDetail/Validation.html#validation-basic-validation
Recommended Posts