为什么 f:validateDoubleRange 仅适用于 @SessionScoped?
有人可以向我解释为什么我的示例中的 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 。
Can someone explain to me why Foo in my example is always null when it gets to the validateDoubleRange class? The end result is the min value for the validator is always 0. The number 3 displays just fine on the page when in the outputText element.
It validates fine if I make the bean @SessionScoped
instead of @ViewScoped
Controller:
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>
I am using JSF 2 on JBoss 6.1
If you are out there @BalusC, this is the simplest example I could come up with, and is the same problem as yesterday, just, I hope, clarified and simpler to replicate.
-- edit, I should add that fooId is set via a view param, so you need ?fooId=3 at the end of your URL.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我现在明白为什么我昨天无法重现这个了。在我的游乐场环境中,我意外地将以下上下文参数设置为与默认值不同:
此问题与 JSF 问题 1492。其属性通过 EL 绑定到视图作用域 bean 属性的
将由于令人讨厌的先有鸡还是先有蛋的问题而隐式重新创建整个 bean,因为验证器是根据每个请求创建的基础,这些属性将在验证器的构造中传递。如果您不想禁用部分状态保存(非常合理),那么您最好的选择是自己在视图范围的托管 bean 中创建并保存验证器:
(注意,在 getter 中执行此操作是一个糟糕的设计,但由于您是在 setter 中准备
foo
而不是preRenderView
侦听器方法,因此没有其他方法,否则它将在相同的侦听器方法中完成)< /em>与
Or,或者, 更新替换
::创建一个自定义验证器,用
自 Mojarra 2.1.18(2013 年 1 月)以来,先有鸡还是先有蛋的问题 1492 已得到修复。因此,如果您最近偶然发现这一点,那么您也可以考虑升级。
I now see why I couldn't reproduce this yesterday. In my playground environment I had accidentally the following context param set differently from the default value:
This problem is related to JSF issue 1492. A
<f:validateDoubleRange>
whose attributes are by EL bound to a view scoped bean property will implicitly recreate the whole bean due to a nasty chicken-egg issue, because validators are created on a per-request basis and those properties are to be passed on validator's construction.If you do not want to disable partial state saving (very reasonable), then your best bet is to create and hold the validator in the view scoped managed bean yourself:
(note, doing this stuff in a getter is a bad design, but since you're preparing
foo
in a setter instead of apreRenderView
listener method, there's no other way, otherwise it would be done right in the same listener method)with
Or, alternatively, to create a custom validator for that which replaces the
<f:validateDoubleRange>
:with
Update: the chicken-egg issue 1492 is fixed since Mojarra 2.1.18 (January 2013). So if you stumble upon this these days, then you could also consider to just upgrade.