f:validateWholeBean 在 JSF 2.3 中
f:validateWholeBean in JSF 2.3
我想用 JSF 2.3 实现 f:validateWholeBean
。
我试图用 Mojarra 2.3.0-m05
和 Tomcat 8:
来实现这个例子
<h:form>
<h:panelGroup>
<h:inputSecret id="passwd" value="#{bean.dataList['passwd']}">
<f:ajax event="blur" render="passwdvalidator" />
</h:inputSecret>
<h:message id="passwdvalidator" for="passwd" />
</h:panelGroup>
<h:panelGroup>Confirm Password</h:panelGroup>
<h:panelGroup>
<h:inputSecret id="confurmpasswd" value="#{bean.dataList['passwd']}">
<f:ajax event="blur" render="confurmpasswdvalidator" />
</h:inputSecret>
<h:message id="confurmpasswdvalidator" for="confurmpasswd" />
</h:panelGroup>
<h:commandButton action="#{bean.submit}">
<f:ajax render="@form" execute="@form"></f:ajax>
</h:commandButton>
<f:validateWholeBean value="#{contactBean}" validationGroups="validateBean.ContactGroup" />
</h:form>
自定义验证器
@Named
@ViewScoped
public class NewAccountValidator implements Validator, Serializable
{
@Override
public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException
{
// not used
}
public void validatePasswords(FacesContext context, UIComponent component, Object value)
{
String l;
String s = value.toString().trim();
if (s != null)
{
// compare passwords
}
else
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_INFO,
s.isEmpty() ? " This field cannot be empty!" : " '" + s + "' is not a number!", null));
}
}
}
使用 f:validateWholeBean
和自定义 JSF 验证器实现解决方案的正确方法是什么?
您不应该实现“标准”验证器,而应该实现 ConstraintValidator
。
您可以在 Arjan Tijms Weblog 上找到示例:
<h:form>
<h:inputText value="#{indexBean.foo}">
<f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/>
</h:inputText>
<h:inputText value="#{indexBean.bar}">
<f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/>
</h:inputText>
<f:validateWholeBean value="#{indexBean}" validationGroups="java.util.RandomAccess"/>
<h:commandButton value="submit"/>
</h:form>
带有支持 bean:
@Named
@RequestScoped
@ValidIndexBean(groups = java.util.RandomAccess.class)
public class IndexBean implements ConstraintValidator<ValidIndexBean, IndexBean> {
@Constraint(validatedBy = IndexBean.class)
@Documented
@Target(TYPE)
@Retention(RUNTIME)
public @interface ValidIndexBean {
String message() default "Invalid Bean";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Inject // @EJB
private PersistenceService service;
@NotNull
private String foo;
@NotNull
private String bar;
@Override
public void initialize(ValidIndexBean constraintAnnotation) {
//
}
@Override
public boolean isValid(IndexBean other, ConstraintValidatorContext context) {
// return other.getFoo().equals(other.getBar());
return service.query("select count(p) from Person p where p.foo like ?1 and p.bar like ?2", other.getFoo(), other.getBar()) == 0;
}
...
}
评论回答:
- 这是一个普通的 bean,所以是的,它可以是 @ViewScoped。
- 那么您应该创建多个验证器:让单个验证器执行多个逻辑是一种不好的做法。
无关:
正如我从您发布的代码中看到的那样,您误解了“经典”验证器的使用,使其成为 ManagedBean(CDI 风格),但这是 不是 “普通”使用 JSF Validators/Converters.
我想你没有使用验证器,而是使用验证方法。
“经典”验证器应如下所示(参见 here):
@FacesValidator("usernameValidator")
public class UsernameValidator implements Validator, Serializable
{
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
// you should use THIS method to validate a single Component's Value
if(query("select count(*) from user where username = '?'", String.valueOf(value)) > 0)
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "invalid username"));
}
}
}
应该像这样使用:
<h:inputText value="#{someBean.username}" validator="usernameValidator" />
所以:
- “经典”人脸验证器很难验证 一个 组件的值
- 他们不应该是@ManagedBean或@Named
- 它们应该通过名称引用(
validator="usernameValidator"
不使用 EL 表达式 validator="#{usernameValidator}"
)
但是,Validators/Converters 的最佳做法是“专业化”:他们应该执行单一验证逻辑。
如果您需要验证组件值,即日期,它必须是非空 并且 大于 01/01/1970,您将需要 两个个专门的验证器。
我想用 JSF 2.3 实现 f:validateWholeBean
。
我试图用 Mojarra 2.3.0-m05
和 Tomcat 8:
<h:form>
<h:panelGroup>
<h:inputSecret id="passwd" value="#{bean.dataList['passwd']}">
<f:ajax event="blur" render="passwdvalidator" />
</h:inputSecret>
<h:message id="passwdvalidator" for="passwd" />
</h:panelGroup>
<h:panelGroup>Confirm Password</h:panelGroup>
<h:panelGroup>
<h:inputSecret id="confurmpasswd" value="#{bean.dataList['passwd']}">
<f:ajax event="blur" render="confurmpasswdvalidator" />
</h:inputSecret>
<h:message id="confurmpasswdvalidator" for="confurmpasswd" />
</h:panelGroup>
<h:commandButton action="#{bean.submit}">
<f:ajax render="@form" execute="@form"></f:ajax>
</h:commandButton>
<f:validateWholeBean value="#{contactBean}" validationGroups="validateBean.ContactGroup" />
</h:form>
自定义验证器
@Named
@ViewScoped
public class NewAccountValidator implements Validator, Serializable
{
@Override
public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException
{
// not used
}
public void validatePasswords(FacesContext context, UIComponent component, Object value)
{
String l;
String s = value.toString().trim();
if (s != null)
{
// compare passwords
}
else
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_INFO,
s.isEmpty() ? " This field cannot be empty!" : " '" + s + "' is not a number!", null));
}
}
}
使用 f:validateWholeBean
和自定义 JSF 验证器实现解决方案的正确方法是什么?
您不应该实现“标准”验证器,而应该实现 ConstraintValidator
。
您可以在 Arjan Tijms Weblog 上找到示例:
<h:form>
<h:inputText value="#{indexBean.foo}">
<f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/>
</h:inputText>
<h:inputText value="#{indexBean.bar}">
<f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/>
</h:inputText>
<f:validateWholeBean value="#{indexBean}" validationGroups="java.util.RandomAccess"/>
<h:commandButton value="submit"/>
</h:form>
带有支持 bean:
@Named
@RequestScoped
@ValidIndexBean(groups = java.util.RandomAccess.class)
public class IndexBean implements ConstraintValidator<ValidIndexBean, IndexBean> {
@Constraint(validatedBy = IndexBean.class)
@Documented
@Target(TYPE)
@Retention(RUNTIME)
public @interface ValidIndexBean {
String message() default "Invalid Bean";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Inject // @EJB
private PersistenceService service;
@NotNull
private String foo;
@NotNull
private String bar;
@Override
public void initialize(ValidIndexBean constraintAnnotation) {
//
}
@Override
public boolean isValid(IndexBean other, ConstraintValidatorContext context) {
// return other.getFoo().equals(other.getBar());
return service.query("select count(p) from Person p where p.foo like ?1 and p.bar like ?2", other.getFoo(), other.getBar()) == 0;
}
...
}
评论回答:
- 这是一个普通的 bean,所以是的,它可以是 @ViewScoped。
- 那么您应该创建多个验证器:让单个验证器执行多个逻辑是一种不好的做法。
无关:
正如我从您发布的代码中看到的那样,您误解了“经典”验证器的使用,使其成为 ManagedBean(CDI 风格),但这是 不是 “普通”使用 JSF Validators/Converters.
我想你没有使用验证器,而是使用验证方法。
“经典”验证器应如下所示(参见 here):
@FacesValidator("usernameValidator")
public class UsernameValidator implements Validator, Serializable
{
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException
{
// you should use THIS method to validate a single Component's Value
if(query("select count(*) from user where username = '?'", String.valueOf(value)) > 0)
{
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "invalid username"));
}
}
}
应该像这样使用:
<h:inputText value="#{someBean.username}" validator="usernameValidator" />
所以:
- “经典”人脸验证器很难验证 一个 组件的值
- 他们不应该是@ManagedBean或@Named
- 它们应该通过名称引用(
validator="usernameValidator"
不使用 EL 表达式validator="#{usernameValidator}"
)
但是,Validators/Converters 的最佳做法是“专业化”:他们应该执行单一验证逻辑。
如果您需要验证组件值,即日期,它必须是非空 并且 大于 01/01/1970,您将需要 两个个专门的验证器。