为啥 f:validateDoubleRange 仅适用于 @SessionScoped?
Posted
技术标签:
【中文标题】为啥 f:validateDoubleRange 仅适用于 @SessionScoped?【英文标题】:Why does f:validateDoubleRange only work for @SessionScoped?为什么 f:validateDoubleRange 仅适用于 @SessionScoped? 【发布时间】:2011-11-18 17:07:15 【问题描述】:有人可以向我解释为什么我的示例中的 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。
【问题讨论】:
【参考方案1】:我现在明白为什么我昨天无法重现这个了。在我的游乐场环境中,我不小心设置了与默认值不同的以下上下文参数:
<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);
更新:自 Mojarra 2.1.18(2013 年 1 月)以来,鸡蛋问题 1492 已得到修复。因此,如果您最近偶然发现了这一点,那么您也可以考虑升级。
【讨论】:
哇,内容丰富且乐于助人。我想我可能要疯了。非常感谢。以上是关于为啥 f:validateDoubleRange 仅适用于 @SessionScoped?的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 glTranslatef?为啥不直接更改渲染坐标?
为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?