59

我正在使用@Email注释来验证电子邮件地址。我遇到的问题是它接受诸如ask@stackoverflow有效电子邮件地址之类的东西。我想这是因为他们想要支持 Intranet 地址,但我似乎找不到标志,所以它确实检查了扩展名。

我真的需要切换到@Pattern(以及任何关于灵活的电子邮件模式的建议)还是我错过了什么?

4

9 回答 9

60

您还可以使用约束组合作为解决方法。在下面的示例中,我依靠@Email验证器进行主要验证,并添加@Pattern验证器以确保地址的形式为x@y.z(我不建议仅使用@Pattern以下进行常规电子邮件验证)

@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 {};
}
于 2012-09-20T15:07:48.137 回答
38

实际上,@Email从 Hibernate Validator内部使用 regexp。您可以根据该正则表达式轻松定义自己的约束,并根据需要进行修改(注意+末尾的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
                    + ")$";
}
于 2010-12-16T13:28:29.063 回答
20

虽然仍然可以实现您自己的验证器或编写一个将聚合@Email和的自定义验证器@Pattern,但您不必再这样做了!

在最近的一个版本中(它肯定存在于 hibernate-validator 6.0.x 中),@Email具有新regexp属性,即“注释元素必须匹配的附加正则表达式”。换句话说,这是一种新方法:

@Email(regexp = ".+@.+\\..+")
private String email;
于 2020-01-01T19:08:24.713 回答
19

实际上验证电子邮件地址非常复杂。无法验证电子邮件地址在语法上是否正确并在注释中针对预期的收件人。注释是一种有用的@Email最小检查,不会受到假阴性问题的影响。

验证的下一步应该是发送一封带有质询的电子邮件,用户必须完成该质询才能确定用户有权访问该电子邮件地址。

最好在步骤 1 中接受一些误报并允许一些无效的电子邮件地址通过,而不是拒绝有效的用户。如果您想应用额外的规则,您可以添加更多检查,但要非常小心您认为是有效电子邮件地址的要求。例如,RFC 中没有任何内容规定i@nl无效,因为nl它是一个注册的国家顶级域。

于 2014-10-13T19:59:44.923 回答
5

这是一个使用 Apache Commons Validator 的 javax.validation 电子邮件验证器

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);
    }
}

和注释:

@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();
    }
}
于 2015-09-04T21:55:26.560 回答
2

显然我迟到了,我仍然在回答这个问题,

为什么我们不能像这样在我们的验证类中使用带有正则表达式的@Pattern 注释

public Class Sigunup {

    @NotNull
    @NotEmpty
    @Pattern((regexp="[A-Za-z0-9._%-+]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}")
    private String email;

}

它更容易。

于 2017-07-03T06:28:52.770 回答
2

如果您要尝试上述解决方案https://stackoverflow.com/a/12515543/258544在注释定义中添加@ReportAsSingleViolation,这样您将避免验证消息(一个来自@Email和一个来自@Pattern),因为它是一个组合注释:

    @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

来自@interface ReportAsSingleViolationjavax.validation:validation-api:1.1.0.Final) 注释定义:“......如果组合约束被 ReportAsSingleViolation 注释,则组合约束的评估在第一个验证错误时停止”

于 2018-07-18T03:43:08.180 回答
1

您可以使用电子邮件正则表达式,同时确保电子邮件为空时验证不会失败。

@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 {};
}
于 2018-11-20T16:47:19.097 回答
0

约束组合解决方案不起作用。当电子邮件与 Pattern 结合使用时,电子邮件正则表达式具有更高的优先级。我相信这是因为 Email 注释覆盖了一些 Pattern 属性,即 flags 和 regexp (这里的关键)如果我删除@Email,只有这样,@Pattern正则表达式才会应用于验证。

/**
 * @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 { };
于 2014-08-25T19:15:17.943 回答