Hibernate Validator: @Email accetta chiedere @ StackOverflow come valido?
-
10-10-2019 - |
Domanda
Sto usando l'annotazione @Email
per convalidare un indirizzo di posta elettronica.
Il problema che sto avendo è che si tratta di accettare le cose come ask@stackoverflow
come un indirizzo e-mail valido.
Credo che questo è perché vogliono indirizzi supporto Intranet, ma io non riesco a trovare una bandiera in modo che fa controllo per un estensione.
Ho davvero bisogno di passare a @Pattern
(e le eventuali raccomandazioni per un modello di e-mail che è flessibile) o mi sto perdendo qualcosa?
Soluzione
In realtà, @Email
da Hibernate Validator uses regExp internamente . Si può facilmente definire il proprio vincolo sulla base di tale regexp, modificato come avete bisogno (notare il +
alla fine del DOMAIN
):
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Pattern(regexp = Constants.PATTERN, flags = Pattern.Flag.CASE_INSENSITIVE)
public @interface EmailWithTld {
String message() default "Wrong email";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
interface Constants {
static final String ATOM = "[a-z0-9!#$%&'*+/=?^_`{|}~-]";
static final String DOMAIN = "(" + ATOM + "+(\\." + ATOM + "+)+";
static final String IP_DOMAIN = "\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\]";
static final String PATTERN =
"^" + ATOM + "+(\\." + ATOM + "+)*@"
+ DOMAIN
+ "|"
+ IP_DOMAIN
+ ")$";
}
Altri suggerimenti
È inoltre possibile utilizzare vincolo composizione come work-around. Nell'esempio che segue, mi baso sul validatore @Email
di fare la convalida principale, e aggiungere un validatore @Pattern
per assicurarsi che l'indirizzo è nella forma di x@y.z
(Non consiglio utilizzando solo il @Pattern
sotto per regolare la convalida e-mail)
@Email(message="Please provide a valid email address")
@Pattern(regexp=".+@.+\\..+", message="Please provide a valid email address")
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface ExtendedEmailValidator {
String message() default "Please provide a valid email address";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
In realtà la validazione indirizzi e-mail è davvero complesso. Non è possibile convalidare che un indirizzo e-mail è sia sintatticamente corretta e indirizzi il destinatario in un'annotazione. L'annotazione @Email
è un utile verifica minima che non soffre il problema di falsi negativi.
Il passo successivo nella convalida dovrebbe essere l'invio di una e-mail con una sfida che l'utente deve completare per stabilire che l'utente ha accesso all'indirizzo e-mail.
E 'meglio essere accettano un paio di falsi positivi al punto 1 e consentire ad alcuni indirizzi e-mail non validi il passaggio di respingere gli utenti validi. Se si desidera applicare regole aggiuntive è possibile aggiungere più controlli, ma essere molto attenti a ciò che si assume essere un requisito di un indirizzo e-mail valido. Per esempio non v'è nulla nelle RFC che impone che i@nl
sarebbero validi, perché nl
è un dominio di paese di primo livello registrato.
Ecco un validatore javax.validation e-mail usando Apache Commons Validator
public class CommonsEmailValidator implements ConstraintValidator<Email, String> {
private static final boolean ALLOW_LOCAL = false;
private EmailValidator realValidator = EmailValidator.getInstance(ALLOW_LOCAL);
@Override
public void initialize(Email email) {
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if( s == null ) return true;
return realValidator.isValid(s);
}
}
E l'annotazione:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CommonsEmailValidator.class})
@Documented
@ReportAsSingleViolation
public @interface Email {
String message() default "{org.hibernate.validator.constraints.Email.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface List {
Email[] value();
}
}
Ovviamente sono in ritardo alla festa, Still I rispondo a questa domanda,
Perchè non usiamo annotazione @Pattern con le espressioni regolari nella nostra classe di convalida come questo
public Class Sigunup {
@NotNull
@NotEmpty
@Pattern((regexp="[A-Za-z0-9._%-+]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}")
private String email;
}
La sua più facile.
La soluzione composizione vincolo non funziona. Quando mail viene utilizzato in combinazione con il modello, la regex mail è tenuto in precedenza maggiore. Credo che questo sia perché l'annotazione Email sovrascrive alcuni attributi del modello, vale a dire bandiere e regexp (la chiave di uno qui) Se rimuovo @Email
, solo allora l'espressione regolare @Pattern
applicare in convalide.
/**
* @return an additional regular expression the annotated string must match. The default is any string ('.*')
*/
@OverridesAttribute(constraint = Pattern.class, name = "regexp") String regexp() default ".*";
/**
* @return used in combination with {@link #regexp()} in order to specify a regular expression option
*/
@OverridesAttribute(constraint = Pattern.class, name = "flags") Pattern.Flag[] flags() default { };
È possibile utilizzare Email regexp, anche fare in modo che la convalida non manca quando l'email è vuota.
@Email(regexp = ".+@.+\\..+|")
@Target({METHOD, FIELD, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface ExtendedEmail {
@OverridesAttribute(constraint = Email.class, name = "message")
String message() default "{javax.validation.constraints.Email.message}";
@OverridesAttribute(constraint = Email.class, name = "groups")
Class<?>[] groups() default {};
@OverridesAttribute(constraint = Email.class, name = "payload")
Class<? extends Payload>[] payload() default {};
}
Se avete intenzione di provare la soluzione sopra https://stackoverflow.com/a/12515543/258544 add il @ReportAsSingleViolation
nel defination annotazione, in questo modo si evita entrambi messaggio di convalida (uno da @Email
e uno da @Pattern
) in quanto è un'annotazione composta:
@Email(message="Please provide a valid email address")
@Pattern(regexp=".+@.+\\..+", message="Please provide a valid email address")
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
@ReportAsSingleViolation
Da @interface ReportAsSingleViolation
javax.validation: validazione-api: 1.1.0.Final) Definizione della nota:
" ... La valutazione di vincoli composti si ferma sulla prima convalida
errore nel caso in cui il vincolo comporre è annotata con ReportAsSingleViolation "