我们最近将系统从JSF 1.2升级到JSF 2.0,并且正在使一切正常运行。但是,当在数据表或类似组件中使用时,我们遇到验证器问题。基本上,问题是验证器不能使用数据表设置的变量。
以下是一个例子:
VALIDATOR:
package test;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
@FacesValidator("test.TestValidator")
public class TestValidator implements Validator {
private Integer length;
public TestValidator() {
super();
}
@Override
public void validate(FacesContext context,
UIComponent component, Object value) throws ValidatorException {
String text = (String) value;
if (text == null || text.trim().length() == 0) {
return;
}
if (length != null && text != null && length.intValue() < text.length()) {
String message = "The text is too long. It was " + text.length() +
", but only " + length + " characters are allowed.";
FacesMessage fm = new FacesMessage(
FacesMessage.SEVERITY_ERROR, message, null);
throw new ValidatorException(fm);
}
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
}
TAGLIB:
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
version="2.0">
<namespace>http://industry-supply.dk/test</namespace>
<tag>
<tag-name>testValidator</tag-name>
<validator>
<validator-id>test.TestValidator</validator-id>
</validator>
<attribute>
<name>length</name>
<required>true</required>
<type>java.lang.Integer</type>
</attribute>
</tag>
</facelet-taglib>
MANAGED BEAN:
package test;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean(name = "testBean")
@RequestScoped
public class TestBean {
public TestBean() {
}
public String[] getKey() {
return new String[]{
"0",
"1",
"2",
"3"
};
}
public String[] getValue() {
return new String[]{
"This is a text and it's too long.",
"This is a text and it's too long.",
"This is a text and it's too long.",
"This is a text and it's too long."
};
}
}
JSF:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:test="http://industry-supply.dk/test">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:dataTable value="#{testBean.key}" var="k">
<h:column>
<h:message for="val"/>
<h:inputText id="val" value="#{testBean.value[k]}">
<test:testValidator length="#{testBean.key[k]}"/>
</h:inputText>
</h:column>
</h:dataTable>
<h:commandButton value="Submit"/>
</h:form>
</h:body>
</html>
运行项目时,会显示4个输入字段和一个命令按钮。每个输入字段包含33个字符的长文本。当您单击“提交”时,错误消息“文本太长。它是33,但只允许0个字符。”显示每个行/字段。这是错误的,因为“test:testValidator length =”#{testBean.key [k]}“”指定第一行的长度为0,第二行的长度为1,第三行的长度为2,第四行的长度为3。因此,对于最后一行,错误消息应该说:“文本太长。它是33,但只允许3个字符。”。
问题是验证器似乎无法访问JSF文件中dataTable组件的k变量。这在JSF 1.2中有效,但我们无法在JSF 2.0中使用它。我们现在花了几天时间解决这个问题,真的需要一些帮助。任何想法?
答案 0 :(得分:1)
好吧,现在看来一切正常。我已经按照McDowell的建议创建了一个自定义的ValidatorHandler。以下是我的更改:
TAGLIB:
<handler-class>test.CustomValidatorHandler</handler-class>
VALIDATOR:
package test;
import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
@FacesValidator("test.TestValidator")
public class TestValidator implements Validator {
public TestValidator() {
super();
}
@Override
public void validate(FacesContext context,
UIComponent component, Object value) throws ValidatorException {
String text = (String) value;
if (text == null || text.trim().length() == 0) {
return;
}
Integer length = getLengthValue();
if (length != null && text != null && length.intValue() < text.length()) {
String message = "The text is too long. It was " + text.length() +
", but only " + length + " characters are allowed.";
FacesMessage fm = new FacesMessage(
FacesMessage.SEVERITY_ERROR, message, null);
throw new ValidatorException(fm);
}
}
private ValueExpression lengthExpression;
public ValueExpression getLength() {
return lengthExpression;
}
public void setLength(ValueExpression length) {
this.lengthExpression = length;
}
public Integer getLengthValue() {
Integer length = null;
if (lengthExpression != null) {
length = (Integer) lengthExpression.getValue(
FacesContext.getCurrentInstance().getELContext());
}
return length;
}
}
VALIDATOR HANDLER:
package test;
import javax.el.ValueExpression;
import javax.faces.context.FacesContext;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.ValidatorConfig;
import javax.faces.view.facelets.ValidatorHandler;
public class CustomValidatorHandler extends ValidatorHandler {
private ValueExpression lengthExpression;
public CustomValidatorHandler(ValidatorConfig config) {
super(config);
FacesContext facesContext = FacesContext.getCurrentInstance();
FaceletContext faceletContext = (FaceletContext) facesContext.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
lengthExpression = config.getTag().getAttributes().get("length").getValueExpression(faceletContext, Integer.class);
}
@Override
public void setAttributes(FaceletContext ctx, Object instance) {
// super.setAttributes(ctx, instance);
if (instance instanceof TestValidator) {
TestValidator validator = (TestValidator) instance;
validator.setLength(lengthExpression);
}
}
}
答案 1 :(得分:0)
我相信你的验证器中有一个错误,你在以前的实现中只是幸运。
...如果
Validator
类希望使用视图保存和恢复配置属性值,则实现还必须实现StateHolder
。
在POST操作期间恢复视图时,长度状态可能不再存在。
我不记得ValueExpressions在验证器上会发生什么 - 与组件不同,验证器往往没有binding maps来保存它们。您可能必须创建自己的ValidatorHandler或其他东西 - 我没有详细查看API的这一部分。