使用DAO实现JSF注册邮箱验证失效问题求助
看起来你的问题核心是验证阶段未正确捕获邮箱重复的异常,导致JSF生命周期没有中断,最终执行了用户保存逻辑,同时DAO方法的异常处理不完整也是关键诱因。让我一步步帮你梳理和修复:
1. DAO方法的异常处理漏洞
你的findNutzerByMail方法只捕获了NoResultException,但当数据库中存在多个相同邮箱的用户时,getSingleResult()会抛出NonUniqueResultException,这个异常没有被捕获,会直接传播到验证器中,打断正常的验证流程。
修改后的DAO方法:
public Nutzer findNutzerByMail(String mail) { try { return em.createNamedQuery("findNutzerByMail", Nutzer.class) .setParameter("mail", mail) .getSingleResult(); } catch (NoResultException | NonUniqueResultException e) { // 没找到结果 或 找到多个结果,都返回null表示邮箱未被唯一匹配 return null; } }
2. 验证器的逻辑缺陷
你的validateNutzer方法依赖捕获NullPointerException来判断邮箱不存在,这种方式既不健壮也容易遗漏异常。当DAO抛出NonUniqueResultException时,这个方法没有捕获,会导致验证器无法抛出ValidatorException,JSF就会认为验证通过,进而进入Invoke Application阶段执行保存操作。
修改后的验证器代码:
@FacesValidator("mailValidatorRegistrieren") public class MailValidatorRegistrieren implements Validator { @EJB private DAO dao; private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE); @Override public void validate(FacesContext facesContext, UIComponent uiComponent, Object o) throws ValidatorException { String mail = (String) o; boolean matchesPattern = EMAIL_PATTERN.matcher(mail).matches(); // 用matches()替代find(),确保整个字符串匹配邮箱规则 if (!matchesPattern) { throw new ValidatorException(new FacesMessage("Ungültige E-Mail-Adresse!")); } // required="true"已经会处理空值,无需额外判断 if (isMailAlreadyUsed(mail)) { throw new ValidatorException(new FacesMessage("Diese E-Mail-Adresse ist bereits registriert!")); } } private boolean isMailAlreadyUsed(String mail) { // 直接判断返回的Nutzer是否为null,更简洁可靠 Nutzer existingUser = dao.findNutzerByMail(mail); return existingUser != null; } }
3. 数据库层面的最后防线
为了彻底防止重复邮箱被存入数据库,建议在Nutzer实体的mail字段上添加唯一约束,即使验证逻辑出现漏洞,数据库也会阻止脏数据插入:
@Entity public class Nutzer { // 其他字段... @Column(unique = true, nullable = false) private String mail; // Getter & Setter... }
为什么原来的代码会导致重复用户被存入?
当数据库中存在多个相同邮箱的用户时,DAO抛出NonUniqueResultException,而你的验证器没有捕获这个异常,导致验证流程被中断,JSF没有收到“验证失败”的信号(因为没有抛出ValidatorException),所以会继续执行到Invoke Application阶段,最终执行用户保存逻辑。即使只有一个重复邮箱,依赖NullPointerException的判断方式也不够可靠,容易出现意外情况。
内容的提问来源于stack exchange,提问作者Luis

