Si vous voulez vérifier l'entrée avec «Java», c'est «Bean Validation». Il est facile à utiliser et pratique car il ajoute seulement une annotation: smile:. Créons maintenant une annotation qui vérifie si la valeur de la propriété est incluse dans le tableau de chaînes passées en argument, comme indiqué ci-dessous.
AcceptedStringValues.java
@Documented
@Constraint(validatedBy = {AcceptedStringValuesValidator.class})
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface AcceptedStringValues {
String message() default "{com.neriudon.example.validator.AcceptedStringValues.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] value();
@Target({METHOD, FIELD})
@Retention(RUNTIME)
@Documented
public @interface List {
AcceptedStringValues[] value();
}
}
Validator
vérifie si la chaîne passée à value () ʻ de l'annotation ʻAcceptedStringValues
contient la valeur de retour du champ annoté ou de la méthode.
AcceptedStringValuesValidator.java
public class AcceptedStringValuesValidator
implements ConstraintValidator<AcceptedStringValues, String> {
// accepted values array
private String[] validValues;
@Override
public void initialize(AcceptedStringValues constraintAnnotation) {
validValues = constraintAnnotation.value();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
// check to exist value or not in accepted values array
return Arrays.stream(validValues).anyMatch(s -> Objects.equals(value, s));
}
}
Le code de test ressemble à ↓.
ValidationSampleApplicationTests.java
public class ValidationSampleApplicationTests {
private ValidatorFactory validatorFactory;
private Validator validator;
@Before
public void setup() {
validatorFactory = Validation.buildDefaultValidatorFactory();
validator = validatorFactory.getValidator();
}
@Test
public void acceptedStringValuesNormal() throws UnsupportedEncodingException {
AcceptedStringValuesSample sample = new AcceptedStringValuesSample("1");
Set<ConstraintViolation<AcceptedStringValuesSample>> result = validator.validate(sample);
// no error
assertThat(result.isEmpty(), is(true));
}
@Test
public void acceptedStringValuesNg() throws Exception {
AcceptedStringValuesSample sample = new AcceptedStringValuesSample("0");
Set<ConstraintViolation<AcceptedStringValuesSample>> result = validator.validate(sample);
// error
assertThat(result.size(), is(1));
// assert error value and message
result.stream().forEach(r -> {
assertThat(r.getInvalidValue(), is("0"));
assertThat(r.getMessage(), is("not accepted value."));
});
}
private static class AcceptedStringValuesSample {
@AcceptedStringValues({"1", "2", "3", "4", "5"})
private String code;
public AcceptedStringValuesSample(String code) {
this.code = code;
}
}
}
Vous savez que les messages d'erreur sont automatiquement appelés si vous créez ValidationMessages.properties
sous le chemin de classe et définissez le message avec la valeur spécifiée dans message
de la classe d'annotation comme clé.
Dans cet exemple, cela ressemble à ↓.
ValidationMessages.properties
com.neriudon.example.validator.AcceptedStringValues.message = not accepted values.
Cela peut ressembler à ↑, mais si le message est corrigé, il peut être difficile à comprendre pour l'utilisateur.
Dans Bean Validation
, la valeur de propriété de la classe d'annotation peut être incorporée dans le message d'erreur, alors essayez de sortir la valeur définie dans la valeur de la classe d'annotation dans {valeur }
comme une chaîne de caractères.
ValidationMessages.properties
com.neriudon.example.validator.AcceptedStringValues.message = not contained accepted values: {value}.
Le message "ne contient pas les valeurs acceptées: [1, 2, 3, 4, 5].".
Bean Validation
prend en charge les expressions EL à partir de la version 1.1!
En spécifiant $ {validatedValue}
, vous pouvez incorporer l'objet qui a causé l'erreur ...
ValidationMessages.properties
com.neriudon.example.validator.AcceptedStringValues.message = ${validatedValue} is not contained accepted values.
Cela entraînera le message «xxx ne contient pas les valeurs acceptées». (XXX est l'objet qui a causé l'erreur)
** Cependant, $ {validatedValue}
renvoie l'objet par erreur tel quel, donc ne l'utilisez pas lorsque vous manipulez des informations confidentielles telles que des mots de passe. ** **
Eh bien, le sujet principal est d'ici.
Jusqu'à présent, nous avons traité de String
, mais avec ʻInteger` nous créons une annotation avec la même fonctionnalité.
AcceptedIntegerValues.java
@Documented
@Constraint(validatedBy = { AcceptedIntegerValuesValidator.class })
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
public @interface AcceptedIntegerValues {
String message() default "{com.neriudon.example.validator.AcceptedIntegerValues.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] value();
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
@Documented
@interface List {
AcceptedIntegerValues[] value();
}
}
AcceptedIntegerValuesValidator.java
public class AcceptedIntegerValuesValidator implements ConstraintValidator<AcceptedIntegerValues, Integer> {
// accepted values array
private Integer[] validValues;
@Override
public void initialize(AcceptedIntegerValues constraintAnnotation) {
validValues = ArrayUtils.toObject(constraintAnnotation.value());
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
// check to exist value or not in accepted values array
return Arrays.stream(validValues).anyMatch(s -> Objects.equals(value, s));
}
}
Définir un message d'erreur ...
ValidationMessages.properties
com.neriudon.example.validator.AcceptedIntegerValues.message = not contained accepted values: {value}.
Maintenant, testez
TestCode.java
@Test
public void acceptedIntegerValuesNormal() {
AcceptedIntegerValuesSample sample = new AcceptedIntegerValuesSample(1);
Set<ConstraintViolation<AcceptedIntegerValuesSample>> result = validator.validate(sample);
assertThat(result.isEmpty(), is(true));
}
@Test
public void acceptedIntegerValuesNg() {
AcceptedIntegerValuesSample sample = new AcceptedIntegerValuesSample(0);
Set<ConstraintViolation<AcceptedIntegerValuesSample>> result = validator.validate(sample);
assertThat(result.size(), is(1));
result.stream().forEach(r -> {
assertThat(r.getInvalidValue(), is(0));
});
}
private static class AcceptedIntegerValuesSample {
@AcceptedIntegerValues({ 1, 2, 3, 4, 5 })
private int code;
public AcceptedIntegerValuesSample(int code) {
this.code = code;
}
}
Alors ...
javax.validation.ValidationException: HV000149: An exception occurred during message interpolation
at org.hibernate.validator.internal.engine.ValidationContext.interpolate(ValidationContext.java:477)
at org.hibernate.validator.internal.engine.ValidationContext.createConstraintViolation(ValidationContext.java:322)
at org.hibernate.validator.internal.engine.ValidationContext.lambda$createConstraintViolations$0(ValidationContext.java:279)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.Collections$2.tryAdvance(Unknown Source)
at java.util.Collections$2.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.collect(Unknown Source)
at org.hibernate.validator.internal.engine.ValidationContext.createConstraintViolations(ValidationContext.java:280)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:182)
at org.hibernate.validator.internal.engine.constraintvalidation.SimpleConstraintTree.validateConstraints(SimpleConstraintTree.java:68)
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:73)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.doValidateConstraint(MetaConstraint.java:127)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:120)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateMetaConstraint(ValidatorImpl.java:533)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForSingleDefaultGroupElement(ValidatorImpl.java:496)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:465)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:430)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:380)
at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:169)
at com.neriudon.example.ValidationSampleApplicationTests.acceptedIntegerValuesNg(ValidationSampleApplicationTests.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.lang.ClassCastException: [I cannot be cast to [Ljava.lang.Object;
at org.hibernate.validator.internal.engine.messageinterpolation.ParameterTermResolver.interpolate(ParameterTermResolver.java:30)
at org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTerm.interpolate(InterpolationTerm.java:64)
at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.interpolate(ResourceBundleMessageInterpolator.java:76)
at org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator.interpolateExpression(AbstractMessageInterpolator.java:385)
at org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator.interpolateMessage(AbstractMessageInterpolator.java:274)
at org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator.interpolate(AbstractMessageInterpolator.java:220)
at org.hibernate.validator.internal.engine.ValidationContext.interpolate(ValidationContext.java:468)
... 55 more
Une erreur s'est produite: fatigué:.
Il semble que la conversion depuis le tableau de ʻInteger de "
[Je ne peux pas être convertie en [Ljava.lang.Object; "" "a échoué.
Essayons de créer une chaîne avec une expression EL.
ValidationMessages.properties
com.neriudon.example.validator.AcceptedIntegerValues.message = not contained accepted values: ${value.toString()}.
Quand je l'ai testé avec ceci, je n'ai pas eu d'erreur, mais cela ressemble à ceci:
not contained accepted values: [I@6e9319f. //Integer[]Édition
not contained accepted values: [1, 2, 3, 4, 5]. // String[]Édition
Donc, convertissons ʻInteger [] en
String avec ʻArrays.toString
.
ValidationMessages.properties
com.neriudon.example.validator.AcceptedIntegerValues.message = not contained accepted values: ${java.util.Arrays.toString(value)}.
Alors, quand vous l'exécutez ...
javax.el.PropertyNotFoundException: ELResolver cannot handle a null base Object with identifier [java]
Il n'y a pas d'objet comme java! J'ai eu l'erreur: déçu_relieved:.
Pour revenir au début, [Expression EL du message d'erreur Hibernate Validator 5](http://docs.jboss.org/hibernate/validator/5.2/reference/en-US/html/ch04.html#section-interpolation- Lisons à propos de (with-message-expressions). Alors ...
The validation engine makes the following objects available in the EL context:
the attribute values of the constraint mapped to the attribute names the currently validated value (property, bean, method parameter etc.) under the name validatedValue a bean mapped to the name formatter exposing the var-arg method format(String format, Object… args) which behaves like java.util.Formatter.format(String format, Object… args).
Si vous le traduisez librement ...
Le moteur de validation peut utiliser les objets suivants dans les expressions EL.
java.util.Formatter.format (String format, Object… args)
En d'autres termes, rien d'autre ne peut être utilisé ...? Même si vous vous référez à l'exemple sous le lien, vous n'avez pas appelé la classe fournie par Java pour traiter le message. / (^ O ^) \ Nantekotai.
Mais ce n'est pas sans chemin. Dans les conseils écrits sous l'exemple, il est écrit comme suit.
Only actual constraint attributes can be interpolated using message parameters in the form {attributeName}. When referring to the validated value or custom expression variables added to the interpolation context (see Section 11.9.1, “HibernateConstraintValidatorContext”), an EL expression in the form ${attributeName} must be used.
Si vous le traduisez librement ...
Si vous définissez la valeur que vous souhaitez utiliser pour le contexte, vous pouvez y faire référence avec $ {}
!
Et cela. Ensemble basé sur l'exemple écrit dans 11.9.1. HibernateConstraintValidatorContext Essayons.
Ajoutez le processus de conversion de ʻInterger [] en
String et de le stocker dans le contexte comme ʻacceptedValuesToString
à la méthode ʻisValid`.
AcceptedIntegerValuesValidator.java
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
// add acceptedValuesToString variable converted accepted integer values to string
context.unwrap(HibernateConstraintValidatorContext.class).addExpressionVariable("acceptedValuesToString", Arrays.toString(validValues));
// check to exist value or not in accepted values array
return Arrays.stream(validValues).anyMatch(s -> Objects.equals(value, s));
}
Donc, si vous appelez $ {allowedValuesToString}
dans ValidationMessages.properties
...
ValidationMessages.properties
com.neriudon.example.validator.AcceptedIntegerValues.message = not contained accepted values: ${acceptedValuesToString}.
J'ai reçu le message d'erreur «valeurs acceptées non contenues: [1, 2, 3, 4, 5].»! Je l'ai fait: stuck_out_tongue_closed_eyes:!
Dans cet article, je vous ai montré comment autoriser les messages d'erreur de validation de bean à appeler des valeurs arbitraires. Cependant, cette méthode pose deux problèmes.
--Il est nécessaire d'expliquer à l'utilisateur les valeurs qui peuvent être utilisées dans le message d'erreur.
Étant donné que la fonction de validation par défaut est étendue, il n'y a pas de problème si vous la développez individuellement, mais si vous la publiez en tant que bibliothèque, par exemple, vous devez décrire quelles valeurs peuvent être utilisées dans JavaDoc, etc. ..
~~ Écrit en WARN sous la section HibernateConstraintValidatorContext, cette fonctionnalité elle-même est sujette à changement dans le futur. ~~
~~ Comme le dit la personne qui a écrit l'article, c'est une fonctionnalité qui ne doit pas être utilisée trop souvent: rolling_eyes:. ~~
Dans Hibernate Validator 6.0.13.Final, l'avertissement ci-dessus a été supprimé. Cela a-t-il été réparé?
Donc, si votre projet décide d'utiliser Hibernate Validator
, cette fonctionnalité est utile (laquelle).
Recommended Posts