有人可以向我解释为什么我的示例中的Foo在到达validateDoubleRange类时始终为null?最终结果是验证器的最小值始终为0.在outputText元素中,数字3在页面上显示正常。
如果我将bean设为@SessionScoped
而不是@ViewScoped
控制器:
import java.io.Serializable;
import java.math.BigDecimal;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ViewScoped
@ManagedBean(name = "fooController")
public class FooController implements Serializable {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FooController.class);
private static final long serialVersionUID = 1L;
private Foo foo;
private BigDecimal amount;
private Long fooId;
public Long getFooId() {
return fooId;
}
public void setFooId(Long fooId) {
this.fooId = fooId;
this.foo = new Foo();
foo.setFooId(fooId);
foo.setMinAmount(Double.valueOf(3));
foo.setMaxAmount(Double.valueOf(10));
}
public Foo getFoo() {
return foo;
}
public void sendAmount() {
log.debug("sendAmount: " + amount);
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public static class Foo {
private Long fooId;
private Double minAmount;
private Double maxAmount;
public Foo() {
}
public void setFooId(Long fooId) {
this.fooId = fooId;
}
public void setMinAmount(Double minAmount) {
this.minAmount = minAmount;
}
public void setMaxAmount(Double maxAmount) {
this.maxAmount = maxAmount;
}
public Long getFooId() {
return fooId;
}
public Double getMaxAmount() {
return maxAmount;
}
public Double getMinAmount() {
return minAmount;
}
}
}
JSP:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
>
<f:metadata>
<f:viewParam name="fooId" value="#{fooController.fooId}" />
</f:metadata>
<h:form id="myForm">
<h:outputText value="This is correctly displayed: '#{fooController.foo.minAmount}'"/><br/>
<h:outputText value="My Input:" />
<h:inputText id="myInput"
value="#{fooController.amount}"
required="true"
>
<f:convertNumber maxFractionDigits="2"/>
<f:validateDoubleRange minimum="#{fooController.foo.minAmount}" maximum="80"/>
</h:inputText>
<h:message for="myInput"/>
<br/>
<h:commandButton id="myButton"
value="Save Amount"
action="#{fooController.sendAmount}"
>
</h:commandButton>
</h:form>
</ui:composition>
我在JBoss 6.1上使用JSF 2
如果你在那里@BalusC,这是我能想到的最简单的例子,和昨天一样,我希望,澄清并且更容易复制。
- 编辑,我应该补充说fooId是通过一个视图参数设置的,所以你需要在你的URL末尾使用?fooId = 3.
答案 0 :(得分:15)
我现在明白为什么我昨天无法重现这一点。在我的游乐场环境中,我意外地将以下上下文参数设置为与默认值不同:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
此问题与JSF issue 1492有关。一个<f:validateDoubleRange>
的属性由EL绑定到视图范围的bean属性将隐式重新创建整个bean,因为一个讨厌的鸡蛋问题,因为验证器是基于每个请求创建的,那些属性将被传递关于验证者的建设。
如果您不想禁用部分状态保存(非常合理),那么最好的办法是自己在视图范围内的托管bean中创建并保存验证器:
public Validator getValidator() {
return new DoubleRangeValidator(foo.getMaximum(), foo.getMinimum());
}
(注意,在getter中执行此操作是一个糟糕的设计,但由于您在setter而不是foo
侦听器方法中准备preRenderView
,所以没有其他办法,否则它将在同一个侦听器方法中完成)
与
<h:inputText validator="#{fooController.validator.validate}" ...>
或者,或者,为替换<f:validateDoubleRange>
:
<f:validator validatorId="bindableDoubleRangeValidator" />
<f:attribute name="minimum" value="#{fooController.foo.minAmount}" />
<f:attribute name="maximum" value="#{fooController.foo.maxAmount}" />
与
package com.example;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.DoubleRangeValidator;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.ValidatorException;
@FacesValidator("bindableDoubleRangeValidator")
public class BindableDoubleRangeValidator extends DoubleRangeValidator {
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
setMinimum((Double) component.getAttributes().get("minimum"));
setMaximum((Double) component.getAttributes().get("maximum"));
super.validate(context, component, value);
}
}
更新:鸡蛋问题1492自Mojarra 2.1.18(2013年1月)起修复。所以,如果你这些日子偶然发现,那么你也可以考虑升级。