Maison  >  Article  >  Java  >  Création d'annotations personnalisées pour la validation dans Spring Boot

Création d'annotations personnalisées pour la validation dans Spring Boot

WBOY
WBOYoriginal
2024-07-25 01:52:13498parcourir

Creating Custom Annotations for Validation in Spring Boot

Création d'annotations personnalisées pour la validation dans Spring Boot

1. Aperçu

Bien que les annotations standard Spring (@NotBlank, @NotNull, @Min, @Size, etc.) couvrent de nombreux cas d'utilisation lors de la validation des entrées utilisateur, il arrive parfois que nous devions créer une logique de validation personnalisée pour un type d'entrée plus spécifique. . Dans cet article, je vais montrer comment créer des annotations personnalisées pour la validation.

2. Configuration

Nous devons ajouter la dépendance spring-boot-starter-validation à notre fichier pom.xml.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

3. Validation personnalisée au niveau du champ

3.1 Création de l'annotation

Créons des annotations personnalisées pour valider les attributs du fichier, tels que l'extension du fichier, la taille du fichier et le type MIME.

  • Extension de fichier valide
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = {FileExtensionValidator.class}
)
public @interface ValidFileExtension {
    String[] extensions() default {};

    String message() default "{constraints.ValidFileExtension.message}";

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

    Class<? extends Payload>[] payload() default {};
}
  • ValidFileMaxSize
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = {FileMaxSizeValidator.class}
)
public @interface ValidFileMaxSize {
    long maxSize() default Long.MAX_VALUE; // MB

    String message() default "{constraints.ValidFileMaxSize.message}";

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

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

  • FileMimeTypeValidator
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = {FileMimeTypeValidator.class}
)
public @interface ValidFileMimeType {
    String[] mimeTypes() default {};

    String message() default "{constraints.ValidFileMimeType.message}";

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

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

Décomposons les composants de ces annotations :

  • @Constraint : Spécifie la classe de validateur responsable de la logique de validation.
  • @Target({ElementType.FIELD}) : indique que cette annotation ne peut être appliquée qu'aux champs.
  • message() : Le message d'erreur par défaut si la validation échoue.

3.2 Création du validateur

  • Validateur d'extension de fichier
public class FileExtensionValidator implements ConstraintValidator<ValidFileExtension, MultipartFile> {

    private List<String> extensions;

    @Override
    public void initialize(ValidFileExtension constraintAnnotation) {
        extensions = List.of(constraintAnnotation.extensions());
    }

    @Override
    public boolean isValid(MultipartFile file, ConstraintValidatorContext constraintValidatorContext) {
        if (file == null || file.isEmpty()) {
            return true;
        }
        var extension = FilenameUtils.getExtension(file.getOriginalFilename());
        return StringUtils.isNotBlank(extension) && extensions.contains(extension.toLowerCase());
    }
}
  • FichierMaxSizeValidator
public class FileMaxSizeValidator implements ConstraintValidator<ValidFileMaxSize, MultipartFile> {

    private long maxSizeInBytes;

    @Override
    public void initialize(ValidFileMaxSize constraintAnnotation) {
        maxSizeInBytes = constraintAnnotation.maxSize() * 1024 * 1024;
    }

    @Override
    public boolean isValid(MultipartFile file, ConstraintValidatorContext constraintValidatorContext) {
        return file == null || file.isEmpty() || file.getSize() <= maxSizeInBytes;
    }
}

  • FileMimeTypeValidator
@RequiredArgsConstructor
public class FileMimeTypeValidator implements ConstraintValidator<ValidFileMimeType, MultipartFile> {

    private final Tika tika;
    private List<String> mimeTypes;

    @Override
    public void initialize(ValidFileMimeType constraintAnnotation) {
        mimeTypes = List.of(constraintAnnotation.mimeTypes());
    }

    @SneakyThrows
    @Override
    public boolean isValid(MultipartFile file, ConstraintValidatorContext constraintValidatorContext) {
        if (file == null || file.isEmpty()) {
            return true;
        }
        var detect = tika.detect(TikaInputStream.get(file.getInputStream()));
        return mimeTypes.contains(detect);
    }
}

Ces classes sont des implémentations de l'interface ConstraintValidator et contiennent la logique de validation réelle.
Pour FileMimeTypeValidator, nous utiliserons Apache Tika (une boîte à outils conçue pour extraire les métadonnées et le contenu de nombreux types de documents).

3.3 Application de l'annotation

Créons une classe TestUploadRequest destinée à gérer les téléchargements de fichiers, spécifiquement pour un fichier PDF.

@Data
public class TestUploadRequest {

    @NotNull
    @ValidFileMaxSize(maxSize = 10)
    @ValidFileExtension(extensions = {"pdf"})
    @ValidFileMimeType(mimeTypes = {"application/pdf"})
    private MultipartFile pdfFile;

}

@RestController
@Validated
@RequestMapping("/test")
public class TestController {

    @PostMapping(value = "/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public ResponseEntity<String> testUpload(@Valid @ModelAttribute TestUploadRequest request) {
        return ResponseEntity.ok("test upload");
    }
}

  • @Target({ElementType.TYPE}) : indique que cette annotation cible une déclaration de type.

4. Validation du niveau de classe personnalisée

Une annotation de validation personnalisée peut également être définie au niveau de la classe pour valider une combinaison de champs au sein d'une classe.

4.1 Création de l'annotation

Créons l'annotation @PasswordMatches pour garantir que deux champs de mot de passe correspondent dans une classe.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = {PasswordMatchesValidator.class}
)
public @interface PasswordMatches {
    String message() default "{constraints.PasswordMatches.message}";

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

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

4.2 Création du validateur

  • Mot de passeDto
public interface PasswordDto {
    String getPassword();

    String getConfirmPassword();
}


  • Mot de passeMatchesValidator
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, PasswordDto> {

    @Override
    public boolean isValid(PasswordDto password, ConstraintValidatorContext constraintValidatorContext) {
        return StringUtils.equals(password.getPassword(), password.getConfirmPassword());
    }
}

L'interface PasswordDto est une interface pour les objets qui contiennent un mot de passe et un champ de confirmation du mot de passe.
La classe PasswordMatchesValidator implémente l'interface ConstraintValidator et contient la logique permettant de valider que les champs de mot de passe et de confirmation du mot de passe correspondent.

4.3 Application de l'annotation

Créons une classe RegisterAccountRequest destinée à gérer les données d'enregistrement des utilisateurs.

@PasswordMatches
@Data
public class RegisterAccountRequest implements PasswordDto {

    @NotBlank
    private String username;

    @NotBlank
    @Email
    private String email;

    @NotBlank
    @ToString.Exclude
    private String password;

    @NotBlank
    @ToString.Exclude
    private String confirmPassword;
}

@RestController
@Validated
@RequestMapping("/auth")
public class AuthController {

    @PostMapping("/register")
    public ResponseEntity<String> register(@RequestBody @Valid RegisterAccountRequest request) {
        return ResponseEntity.ok("register success");
    }
}

5. Résumé

Dans ce court article, nous avons découvert à quel point il est simple de créer des annotations personnalisées pour vérifier un champ ou une classe. Le code de cet article est disponible sur mon Github.

  • spring-boot-microservices
  • service-utilisateur

6. Références

  • Baeldung. (s.d.). Validateur personnalisé Spring MVC. Récupéré à partir de https://www.baeldung.com/spring-mvc-custom-validator

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn