Validation 如何在actionListener或action方法中执行JSF验证?
我的应用程序中的Bean验证工作得很好。现在我想检查新用户是否没有选择已经选择的用户名Validation 如何在actionListener或action方法中执行JSF验证?,validation,jsf,bean-validation,Validation,Jsf,Bean Validation,我的应用程序中的Bean验证工作得很好。现在我想检查新用户是否没有选择已经选择的用户名 在actionlistener中,我有检查数据库的代码,但是如果用户选择了一个已经存在的用户名,我如何强制用户返回到他们所在的页面?为此,最好使用action方法而不是actionlistener。然后,如果用户名存在,您可以从此方法返回null(重新加载触发该操作的页面)。下面是一个例子: 在facelet中: <h:commandButton action="#{testBean.doAction}
在actionlistener中,我有检查数据库的代码,但是如果用户选择了一个已经存在的用户名,我如何强制用户返回到他们所在的页面?为此,最好使用action方法而不是actionlistener。然后,如果用户名存在,您可以从此方法返回
null
(重新加载触发该操作的页面)。下面是一个例子:
在facelet中:
<h:commandButton action="#{testBean.doAction}" value="and... Action"/>
您可以在faces-config.xml文件中定义导航案例。这将允许您根据bean的返回值将用户重定向到给定页面 在下面的示例中,根据“myMethod()”的返回值,suer被重定向到两个页面中的一个
/index.xhtml
#{myBean.myMethod()}
真的
/correct.xhtml
#{myBean.myMethod()}
假的
/error.xhtml
简介
您可以这样做,但是JSF ajax/action/listener方法在语义上是错误的。如果表单中有错误的输入值,实际上您不想在JSF生命周期中走那么远。您希望JSF生命周期在JSF验证阶段之后停止
您希望使用JSR303 Bean验证注释(@NotNull
和friends)和/或约束验证器,或者使用JSF验证器(required=“true”
,
,等等)来代替。它将在JSF验证阶段被正确调用。这样,当验证失败时,模型值不会更新,业务操作也不会被调用,您将保持在相同的页面/视图中
由于没有标准的Bean验证注释或JSF验证器来检查给定的输入值是否根据数据库是唯一的,因此您需要为其定制一个自定义验证器
对于这两种方法,我都将演示如何创建一个检查用户名唯一性的自定义验证器
自定义JSR303 Bean验证注释
首先创建自定义的@Username
约束注释:
@Constraint(validatedBy = UsernameValidator.class)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Username {
String message() default "Username already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
最后在模型中使用它,如下所示:
@Username
private String username;
自定义JSF验证器
另一种方法是使用自定义JSF验证器。只需实现JSF接口:
@ManagedBean
@RequestScoped
public class UsernameValidator implements Validator {
@EJB
private UserService userService;
@Override
public void validate(FacesContext context, UIComponent component, Object submittedAndConvertedValue) throws ValidatorException {
String username = (String) submittedAndConvertedValue;
if (username == null || username.isEmpty()) {
return; // Let required="true" or @NotNull handle it.
}
if (userService.exist(username)) {
throw new ValidatorException(new FacesMessage("Username already in use, choose another"));
}
}
}
最后,在视图中使用它,如下所示:
<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
请注意,您通常会在验证程序
类上使用@FacesValidator
注释,但在即将推出的JSF2.3之前,它不支持@EJB
或@Inject
。另请参见。是的,您可以。您可以在action listener方法中执行验证,如果自定义验证失败,则添加faces消息,然后在返回之前调用FacesContext.validationFailed()
这个解决方案的唯一问题是,它发生在JSF验证和bean验证之后。即,在验证阶段之后。如果您有多个操作侦听器,比如listener1和listener2:如果您在listener1中的自定义验证失败,它将继续执行listener2。但毕竟,AJAX响应中会出现validationFailed。如果您想向最终用户提供反馈:
xhtml:
<p:commandButton value="Go" process="@this" action="#{myBean.checkEntity()}" oncomplete="if(args.validationFailed){PF('widgetOldInfoNotice').show();}"/>
<p:confirmDialog id="dialogOldInfoNotice" header="NOTICE" severity="alert" widgetVar="widgetOldInfoNotice">
-- feedback message--
<p:button value="Ok" onclick="PF('widgetOldInfoNotice').hide();"/>
</p:confirmDialog>
我认为你不应该首先重定向到另一个页面,除非用户名是有效的。谢谢BalusC。这个验证器是在bean验证进行检查之前还是之后调用,或者没有指定顺序?JSF验证在bean验证之前执行。但是如果该值为null
或空,那么除了required
之外的JSF验证将不会执行。因此,如果您的@NotNull
没有required=“true”
,那么它将首先执行。但是如果它不是空的,并且您有一个例如@模式
,那么JSF验证器将首先被调用。但是我能不能不仅仅使用普通的jsf验证器,而且只使用bean验证来验证属性?如果它是有效的,那么我可以检查数据库。我尝试了Validator类的validateProperty方法,但我无法让它正常工作,因为它要求组和其他我不理解的语义。如果这是在actionListener中完成的,则需要确保action方法检查facesContext.isValidationFailed()
继续。这里的问题是向最终用户提供正确的反馈。
@ManagedBean
@RequestScoped
public class UsernameValidator implements Validator {
@EJB
private UserService userService;
@Override
public void validate(FacesContext context, UIComponent component, Object submittedAndConvertedValue) throws ValidatorException {
String username = (String) submittedAndConvertedValue;
if (username == null || username.isEmpty()) {
return; // Let required="true" or @NotNull handle it.
}
if (userService.exist(username)) {
throw new ValidatorException(new FacesMessage("Username already in use, choose another"));
}
}
}
<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
<p:commandButton value="Go" process="@this" action="#{myBean.checkEntity()}" oncomplete="if(args.validationFailed){PF('widgetOldInfoNotice').show();}"/>
<p:confirmDialog id="dialogOldInfoNotice" header="NOTICE" severity="alert" widgetVar="widgetOldInfoNotice">
-- feedback message--
<p:button value="Ok" onclick="PF('widgetOldInfoNotice').hide();"/>
</p:confirmDialog>
public String checkEntity() {
if (!dao.whateverActionToValidateEntity(selectedEntity)) {
FacesContext context = FacesContext.getCurrentInstance();
context.validationFailed();
return "";
}
return "myPage.xhtml";
}