编程知识 cdmana.com

Introduction à la vérification des données hibernantes

Nous rencontrons souvent des problèmes de vérification des paramètres dans notre entreprise,Par exemple, vérification des paramètres frontaux、KafkaVérification des paramètres du message, etc.,Si la logique d'entreprise est compliquée,Quand il y a plus d'entités,Nous avons vérifié ces données par Code.,Il y a beaucoup de code répétitif et de logique indépendante de l'entreprise principale.Spring MVCFournit un mécanisme de vérification des paramètres,Mais le fond passeHibernateVérification des données,Il est donc nécessaire de comprendreHibernateSomme de contrôle des donnéesJSRSpécification de vérification des données.

JSRSpécification de vérification des données

JavaLes autorités ont publiéJSR303AvecJSR349Un cadre standard pour la vérification de la validité des données est proposé.:BeanValidator,BeanValidatorDans le cadre,L'utilisateur passe parBeanLes propriétés [email protected]、@MaxLes notes d'autres normes précisent les règles de vérification,Et passer la paire d'interface de vérification standardBeanEffectuer la vérification.

JSRListe des commentaires

JSRLes commentaires sur la vérification des données dans la norme sont les suivants::

Nom de l'annotation Type de données d'annotation Effet d'annotation Exemple
AssertFalse boolean/Boolean L'élément commenté doit êtreFalse @AssertFalse private boolean success;
AssertTrue boolean/Boolean L'élément commenté doit êtreTrue @AssertTrue private boolean success;
DecimalMax BigDecimal/BigInteger/CharSequence/byte/short/int/longEt ses classes d'emballage La valeur annotée doit être inférieure ou égale à la valeur maximale spécifiée @DecimalMax("10") private BigDecimal value;
DecimalMin BigDecimal/BigInteger/CharSequence/byte/short/int/longEt ses classes d'emballage La valeur annotée doit être supérieure ou égale à la valeur minimale spécifiée @DecimalMin("10") private BigDecimal value;
Digits BigDecimal/BigInteger/CharSequence/byte/short/int/longEt ses classes d'emballage integerSpécifier le nombre maximum de bits pour la partie entière,fractionSpécifier le nombre maximum de chiffres pour la partie décimale @Digits(integer = 10,fraction = 4) private BigDecimal value;
Email CharSequence La chaîne est un format de boîte aux lettres valide @Email private String email;
Future javaDifférents types de dates dans La date spécifiée doit être postérieure à la date actuelle @Future private LocalDateTime future;
FutureOrPresent javaDifférents types de dates dans La date spécifiée doit être la date courante ou après cette date. @FutureOrPresent private LocalDateTime futureOrPresent;
Max BigDecimal/BigInteger/byte/short/int/longEt les emballages La valeur annotée doit être inférieure ou égale à la valeur maximale spécifiée @Max("10") private BigDecimal value;
Min BigDecimal/BigInteger/byte/short/int/longEt les emballages La valeur annotée doit être supérieure ou égale à la valeur minimale spécifiée @Min("10") private BigDecimal value;
Negative BigDecimal/BigInteger/byte/short/int/long/float/doubleEt les emballages La valeur annotée doit être négative @Negative private BigDecimal value;
NegativeOrZero BigDecimal/BigInteger/byte/short/int/long/float/doubleEt les emballages La valeur annotée doit être0Ou négatif @NegativeOrZero private BigDecimal value;
NotBlank CharSequence La chaîne annotée contient au moins un caractère non vide @NotBlank private String noBlankString;
NotEmpty CharSequence/Collection/Map/Array Le nombre d'éléments de collection annotés est supérieur à0 @NotEmpty private List<string> values;
NotNull any La valeur annotée n'est pas vide @NotEmpty private Object value;
Null any La valeur annotée doit être vide @Null private Object value;
Past javaDifférents types de dates dans La date spécifiée doit être antérieure à la date actuelle @Past private LocalDateTime past;
PastOrPresent javaDifférents types de dates dans La date indiquée doit être au plus tard à la date courante @PastOrPresent private LocalDateTime pastOrPresent;
Pattern CharSequence La chaîne annotée doit correspondre à l'expression régulière résultante donnée @Pattern(\d*) private String numbers;
Positive BigDecimal/BigInteger/byte/short/int/long/float/doubleEt les emballages La valeur annotée doit être un nombre positif @Positive private BigDecimal value;
PositiveOrZero BigDecimal/BigInteger/byte/short/int/long/float/doubleEt les emballages La valeur annotée doit être un nombre positif ou0 @PositiveOrZero private BigDecimal value;
Size CharSequence/Collection/Map/Array Le nombre d'éléments de collection annotés se situe dans la plage spécifiée @Size(min=1,max=10) private List<string> values;

JSRContenu de l'annotation

C'est plus [email protected] d'annotation,Regardez ce que les notes contiennent.,Comme le montre le code source ci - dessous,Je [email protected]'annotation contient les éléments suivants::

  1. message:Messages d'erreur,L'exemple est le Code d'erreur,Peut être traduit dans différentes langues selon l'internationalisation.
  2. groups: Vérification de groupe,Différents groupes peuvent avoir des conditions de contrôle différentes,Comme le mêmeDTOPourcreateEtupdateLes conditions de vérification du temps peuvent être différentes.
  3. payload:BeanValidation APICet attribut permet aux consommateurs de spécifier un niveau de gravité pour une contrainte. Cette propriété n'est pasAPIUtilisé par lui - même.
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface NotNull {
	String message() default "{javax.validation.constraints.NotNull.message}";

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

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

	/** * Defines several {@link NotNull} annotations on the same element. */
	@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
	@Retention(RUNTIME)
	@Documented
	@interface List {

		NotNull[] value();
	}
}

Messages d'erreurmessage、GroupegroupCes fonctions sont plus utilisées dans nos programmes,Avant que je vous présenteSpring ValidatorLa vérification des données est détaillée dans l'article,Mais à propos depayloadOn est moins en contact,Voici quelques exemples:payloadUtilisation de,Dans l'exemple suivant,Nous utilisonspayloadPour identifier la gravité de l'échec de la vérification des données,Par le code suivant.Après vérificationContactDetailsAprès l'exemple de, Vous pouvez appelerConstraintViolation.getConstraintDescriptor().getPayload()Pour obtenir le niveau d'erreur précédemment spécifié,Et à partir de cette information, vous pouvez décider du comportement suivant.

public class Severity {
    public static class Info extends Payload {};
    public static class Error extends Payload {};
}

public class ContactDetails {
    @NotNull(message="Name is mandatory", payload=Severity.Error.class) private String name;

    @NotNull(message="Phone number not specified, but not mandatory", payload=Severity.Info.class) private String phoneNumber;

    // ...
}

JSRVérifier l'interface

Par devantJSRVérifier les notes,Nous pouvons ajouter des critères de vérification aux champs correspondants d'une classe,Comment vérifier ces conditions de vérification??JSRL'interface de base pour la vérification des données estValidation,Cette interface est définie comme suit:,Nous utilisons plus d'interfaces<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);,Cette méthode peut être utilisée pour vérifier unObjectConformité aux règles de vérification du Groupe spécifié,Si aucun groupe n'est spécifié,Seules les règles de vérification du Groupe par défaut sont alors en vigueur.

public interface Validator {

	/** * Validates all constraints on {@code object}. */
	<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);

	/** * Validates all constraints placed on the property of {@code object} * named {@code propertyName}. */
	<T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName,Class<?>... groups);

	/** * Validates all constraints placed on the property named {@code propertyName} * of the class {@code beanType} would the property value be {@code value}. */
	<T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups);

	/** * Returns the descriptor object describing bean constraints. * The returned object (and associated objects including * {@link ConstraintDescriptor}s) are immutable. */
	BeanDescriptor getConstraintsForClass(Class<?> clazz);

	/** * Returns an instance of the specified type allowing access to * provider-specific APIs. * <p> * If the Jakarta Bean Validation provider implementation does not support * the specified class, {@link ValidationException} is thrown.call */
	<T> T unwrap(Class<T> type);

	/** * Returns the contract for validating parameters and return values of methods * and constructors. */
	ExecutableValidator forExecutables();
}

HibernateVérification des données

Basé surJSRSpécification de vérification des données,HibernateAjout de nouveaux contrôles d'annotation,Et c'est arrivé.JSRDeValidatorInterface pour la vérification des données.

HibernateNouveau commentaire

Nom de l'annotation Type de données d'annotation Effet d'annotation Exemple
CNPJ CharSequence L'élément annoté doit être un numéro d'enregistrement national légal de la personne morale brésilienne. @CNPJ private String cnpj;
CPF CharSequence L'élément annoté doit être un numéro d'enregistrement légal du contribuable brésilien. @CPF private String cpf;
TituloEleitoral CharSequence L'élément annoté doit être un numéro d'identification d'électeur brésilien légal @TituloEleitoral private String tituloEleitoral;
NIP CharSequence L'élément annoté doit être un numéro fiscal polonais légal @NIP private String nip;
PESEL CharSequence L'élément annoté doit être un numéro d'identification polonais légal @PESEL private String pesel;
REGON CharSequence L'élément annoté doit être un numéro régional polonais légal @REGON private String regon;
DurationMax Duration Éléments annotésDurationEst inférieur à la durée spécifiée @DurationMax(day=1) private Duration duration;
DurationMin Duration Éléments annotésDurationEst plus long que la durée spécifiée @DurationMin(day=1) private Duration duration;
CodePointLength CharSequence Éléments annotésCodPointNombre dans la plage spécifiée,unicodeChaque caractère a un code d'identification unique,Ce code estCodePoint.Par exemple, nous devons limiter le nombre de caractères chinois,Vous pouvez utiliser ceci @CodePointLength(min=1) private String name;
ConstraintComposition Autres commentaires sur la vérification des données Relations combinatoires des notes combinatoires,Relation avec ou comme ---
CreditCardNumber CharSequence Utilisé pour déterminer si une carte de crédit est un format légal @CreditCardNumber private String credictCardNumber;
Currency CharSequence L'élément annoté est le taux de change du type spécifié @Currency(value = {"USD"}) private String currency;
ISBN CharSequence L'élément annoté est légalISBNLe numéro @ISBN private String isbn;
Length CharSequence L'élément commenté est de longueur dans la plage spécifiée @Length(min=1) private String name;
LuhnCheck CharSequence Les éléments annotés peuvent êtreLuhnVérification de l'algorithme @LuhnCheck private String luhn;
Mod10Check CharSequence Les éléments annotés peuvent passer par le module10Vérification de l'algorithme @Mod10Check private String mod10;
ParameterScriptAssert Méthodes Vérification du script des paramètres ————
ScriptAssert Catégorie Vérification du script de classe ————
UniqueElements Ensemble Chaque élément de la collection est unique @UniqueElements private List<String> elements;

HibiernateVérification des données

Comment utiliserHibernateVérification des données?Nous savons queJSRInterface pour la vérification des données spécifiéeValidator,HibernateAvecValidatorImplImplémenté dans la classeValidatorInterface,On peut passer parHibernateClasse d'usine fournieHibernateValidator.buildValidatorFactoryCréer unValidatorImplExemple.UtiliserHibernateCréer unValidatorLe Code de l'Instance est le suivant.

ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
    .configure()
    .addProperty( "hibernate.validator.fail_fast", "true" )
    .buildValidatorFactory();
Validator validator = validatorFactory.getValidator();

HibernateVérifier le code source

Par le contenu ci - dessus,Nous savons queHibernateVous pouvez instancier unValidatorExemple d'interface,Cet exemple peut être utilisé pour la vérification avec des annotations de vérificationJavaBean,AlorsHibernateComment la couche inférieure met - elle en œuvre ces logiques de contrôle?Nous sommes comme suitJavaBeanPar exemple,AnalyseHibernateSource vérifiée.

@Data
public class Person {

    @NotBlank
    @Size(max=64)
    private String name;

    @Min(0)
    @Max(200)
    private int age;
}

ConstraintValidatorIntroduction

ConstraintValidator- Oui.HibernateLa granularité la plus fine pour la vérification des données,Il peut vérifier si la valeur numérique de l'annotation et du type spécifiés est valide.Comme dans l'exemple ci - dessus@Max(200)private int age;,PourageLa vérification des champs utilise unMaxValidatorForIntegerDeConstraintValidator,C'estConstraintValidatorLors de la vérification, on détermine si la valeur spécifiée est supérieure à la valeur maximale spécifiée..

public class MaxValidatorForInteger extends AbstractMaxValidator<Integer> {

	@Override
	protected int compare(Integer number) {
		return NumberComparatorHelper.compare( number.longValue(), maxValue );
	}
}

public abstract class AbstractMaxValidator<T> implements ConstraintValidator<Max, T> {

	protected long maxValue;

	@Override
	public void initialize(Max maxValue) {
		this.maxValue = maxValue.value();
	}

	@Override
	public boolean isValid(T value, ConstraintValidatorContext constraintValidatorContext) {
		// null values are valid
		if ( value == null ) {
			return true;
		}

		return compare( value ) <= 0;
	}

	protected abstract int compare(T number);
}

ConstraintValidatorInitialisation

Comme nous l'avons dit précédemment,HibernateOffreValidatorImplPour la vérification des données,AlorsValidatorImplEtConstraintValidatorQuelle est la relation?,En termes simples,ValidatorImplTous lesConstraintValidator,Appelez cesConstraintValidatorDonnées de contrôle.IntégréConstraintValidatorNote correspondante [email protected](validatedBy = { })C'est vide..

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { }) // C'est vide ici
public @interface AssertFalse {

	String message() default "{javax.validation.constraints.AssertFalse.message}";

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

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

	/** * Defines several {@link AssertFalse} annotations on the same element. * * @see javax.validation.constraints.AssertFalse */
	@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
	@Retention(RUNTIME)
	@Documented
	@interface List {

		AssertFalse[] value();
	}
}

PersonnalisationConstraintValidator

SiHibernateEtJSRIl n'y a pas assez de notes dans,Je dois personnaliser une annotation et des contraintes,Comment y parvenir.La mise en œuvre d'une logique de vérification personnalisée se fait en deux étapes:1.Mise en œuvre des annotations.2.Mise en œuvre de la logique de contrôle.Par exemple, nous avons besoin d'une annotation pour vérifier l'état du champ,Nous pouvons définir une annotation en utilisant l'exemple suivant:

@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = StatusValidator.class)
@Documented
public @interface ValidStatus {
    String message() default "Erreur d'état ";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    /** * Ensemble de valeurs d'état valides,Par défaut{1,2} */
    int[] value() default {1,2};
}

Après avoir mis en œuvre l'annotation,Nous devons mettre en œuvre@Constraint(validatedBy = StatusValidator.class),Voici un exemple de code::

/** * Vérifier si l'état appartient à l'ensemble d'état spécifié (ConstraintValidatorLe type d'objet générique spécifié après est Classes d'annotation et types de champs d'annotation<ValidStatus, Integer>) */
public class StatusValidator implements ConstraintValidator<ValidStatus, Integer> {
    private Integer[] validStatus;

    @Override
    public void initialize(ValidStatus validStatus) {
        int[] ints = validStatus.value();
        int n = ints.length;
        Integer[] integers = new Integer[n];
        for (int i = 0; i < n; i++) {
            integers[i] = ints[i];
        }
        this.validStatus = integers;
    }

    @Override
    public boolean isValid(Integer n, ConstraintValidatorContext constraintValidatorContext) {
        List<Integer> status = Arrays.asList(validStatus);
        if (status.contains(n)) {
            return true;
        }
        return false;
    }
}

ValidatorCaractéristiques de

Quatre niveaux de contrainte

Contraintes au niveau des variables membres

Les contraintes peuvent être exprimées en annotant les variables membres d'une classe.Le code ci - dessous:

@Data
public class Person {

    @NotBlank
    @Size(max=64)
    private String name;

    @Min(0)
    @Max(200)
    private int age;
}

Contraintes de propriété

Si votre classe modèle suitjavabeanLa norme,Il pourrait aussi annoter cecibeanPropriété de, au lieu de sa variable membre.À propos deJavaBeanPour en savoir plus, consultez mon autre blog.

@Data
public class Person {

    private String name;

    @Min(0)
    @Max(200)
    private int age;

    @NotBlank
    @Size(max=64)
    public String getName(){
        return name;
    }
}

Ensemble de contraintes

Annotation par [email protected] spécifiée dans la définition de contrainteElementType.TYPE_USE,.Il est possible de restreindre les éléments à l'intérieur d'un conteneur

Contraintes au niveau de la classe

Une contrainte est placée au niveau de la classe,Dans ce cas,,L'objet validé n'est pas une propriété simple,Mais un objet entier.Utiliser des contraintes au niveau de la classe,Vous pouvez vérifier la corrélation entre plusieurs propriétés d'un objet,Par exemple, tous les champs ne sont pas autorisés à êtrenullAttendez..

@Data
@NotAllFieldNull
public class Person {

    private String name;

    @Min(0)
    @Max(200)
    private int age;

    @NotBlank
    @Size(max=64)
    public String getName(){
        return name;
    }
}

Vérifier l'Héritabilité des annotations

Champs avec contraintes ajoutées à la classe mère,La Sous - classe vérifie également les champs de la classe mère lors de la vérification.

Vérification récursive

Supposons que dans l'exemple ci - dessus,PersonUn de plus.AddressChamp de type,EtAddressJ'ai aussi ma propre vérification,Comment vérifierAddressEt les champs dans?Peut être réalisé [email protected]'annotation implémente la vérification récursive.

@Data
public class Person {

    private String name;

    @Min(0)
    @Max(200)
    private int age;

    @Valid
    public Address address;
}

@Data
public class Address{

    @NotNull
    private string city;
}

Vérification des paramètres de la méthode

Nous pouvons ajouter des annotations de contrôle aux paramètres de la méthode,Mise en œuvre de la vérification des paramètres au niveau de la méthode,Bien sûr, ces notes doivent passer parAOPRéalisation(Par exemple,SpringVérification des paramètres de la méthode pour).


public void createPerson(@NotNull String name,@NotNull Integer age){

}

Vérification croisée des paramètres de la méthode

La méthode supporte également la vérification entre les paramètres,Par exemple, l'annotation suivante ne permet pas que le nom d'utilisateur et l'âge soient vides lors de la création de l'utilisateur.,La logique de vérification des annotations doit être mise en œuvre par elle - même.Les paramètres de la vérification croisée sontObject[]Type,Différents emplacements de paramètres correspondent à différentsObj.

@NotAllPersonFieldNull
public void createPerson( String name,Integer age){

}

Vérification de la valeur de retour de la méthode

public @NotNull Person getPerson( String name,Integer age){
    return null;
}

Fonction de regroupement

Je vous présenteSpringComme indiqué dans l'article pour vérifier les annotations,InSpringDans le système d'étalonnage de,@ValidL'annotation ne supporte pas la vérification de groupe,@ValidatedLes annotations supportent la vérification de groupe. En fait, ce n'est pasJSRDans les [email protected] vérification de groupe n'est pas prise en charge,[email protected] fonction de vérification de groupe annotée est masquée.

Donc, NativeJSRNotes etHibernateLa fonction de vérification de groupe est prise en charge pour la vérification,Pour plus de détails sur la logique de vérification, veuillez consulter monSpringArticle sur la vérification des données.

Héritage de groupe

Nous savons queJSRLa fonction de vérification de groupe est utilisée dans l'annotationgroupChamp,groupLe champ stocke les catégories groupées,Donc s'il y a une relation héréditaire entre les classes groupées,La vérification du Groupe sera - t - elle héritée??La réponse est oui..

Ordre de regroupement

Si nous devons spécifier l'ordre de vérification pendant la vérification,Ensuite, nous pouvons grouper les critères de vérification,Les attributs individuels de l'objet sont vérifiés séquentiellement après le regroupement.

GroupSequence({ Default.class, BaseCheck.class, AdvanceCheck.class }) public interface OrderedChecks { }

Payload

Si nous avons besoin de différentes méthodes de vérification dans différentes situations,,Comme l'environnement chinois et anglais,Ce n'est pas un bon moment pour grouper.,Peut envisager d'utiliserPayLoad.L'utilisateur peut initialiserValidatorPour spécifier l'environnement actuelpayload,Et ensuite obtenir lepayloadSuivre un processus de vérification différent:

ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure()
        .constraintValidatorPayload( "US" )
        .buildValidatorFactory();

Validator validator = validatorFactory.getValidator();

public class ZipCodeValidator implements ConstraintValidator<ZipCode, String> {

    public String countryCode;

    @Override
    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
        if ( object == null ) {
            return true;
        }

        boolean isValid = false;

        String countryCode = constraintContext
                .unwrap( HibernateConstraintValidatorContext.class )
                .getConstraintValidatorPayload( String.class );

        if ( "US".equals( countryCode ) ) {
            // checks specific to the United States
        }
        else if ( "FR".equals( countryCode ) ) {
            // checks specific to France
        }
        else {
            // ...
        }

        return isValid;
    }
}

Je suis le Dieu du renard,Bienvenue à suivre mon numéro public Wechat:wzm2zsd

qrcode_for_gh_83670e17bbd7_344-2021-09-04-10-55-16

Cet article a été publié pour la première fois sur Wechat public,Copyright,Interdiction de réimprimer!

版权声明
本文为[Dieu du renard Royal]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/11/20211125171653793o.html

Scroll to Top