可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm using the @Email
annotation to validate an e-mail address.
The issue I'm having is that it's accepting things like ask@stackoverflow
as a valid e-mail address.
I guess this is because they want to support intranet addresses, but I can't seem to find a flag so it does check for an extension.
Do I really need to switch to @Pattern
(and any recommendations for an e-mail pattern that's flexible) or am I missing something?
回答1:
Actually, @Email
from Hibernate Validator uses regexp internally. You can easily define your own constraint based on that regexp, modified as you need (note the +
at the end of 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
+ ")$";
}
回答2:
You can also use constraint composition as a work-around. In the example below, I rely on the @Email
validator to do the main validation, and add a @Pattern
validator to make sure the address is in the form of x@y.z
(I don't recommend using just the @Pattern
below for regular Email validation)
@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 {};
}
回答3:
Actually validating e-mail addresses is really complex. It is not possible to validate that an e-mail address is both syntactically correct and addresses the intended recipient in an annotation. The @Email
annotation is a useful minimal check that doesn't suffer from the problem of false negatives.
The next step in validation should be sending an e-mail with a challenge that the user has to complete to establish that the user has access to the e-mail address.
It is better to be accept a few false positives in step 1 and allow some invalid e-mail addresses to pass through than to reject valid users. If you want to apply additional rules you can add more checks, but be really careful about what you assume to be a requirement of a valid e-mail address. For instance there is nothing in the RFCs that dictates that i@nl
would be invalid, because nl
is a registered country top-level domain.
回答4:
Here's a javax.validation email validator using 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);
}
}
And the annotation:
@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();
}
}
回答5:
The constraint composition solution does not work. When Email is used in conjunction with Pattern, the Email regex is held in higher precedence. I believe this is because the Email annotation overrides a few Pattern attributes, namely flags and regexp (the key one here) If I remove @Email
, only then will the @Pattern
regular expression apply in validations.
/**
* @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 { };
回答6:
Obviously I am late to the Party, Still I am replying to this question,
Why cant we use @Pattern annotation with regular expressions in our Validation class like this
public Class Sigunup {
@NotNull
@NotEmpty
@Pattern((regexp="[A-Za-z0-9._%-+]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}")
private String email;
}
Its easier.
回答7:
If you are going to try the above solution https://stackoverflow.com/a/12515543/258544 add the @ReportAsSingleViolation in the annotation defination, this way you will avoid both validation message(one from @Email and one from @Pattern) as it is a composed annotation :
@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
From @interface ReportAsSingleViolation javax.validation:validation-api:1.1.0.Final) annotation definition :
"... Evaluation of composed constraints stops on the first validation
error in case the composing constraint is annotated with ReportAsSingleViolation"
回答8:
You can use Email regexp, also making sure that the validation doesn't fail when the email is empty.
@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 {};
}