为啥 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 有关。 &lt;f:validateDoubleRange&gt; 其属性由 EL 绑定到视图范围的 bean 属性,由于令人讨厌的鸡蛋问题,将隐式重新创建整个 bean,因为验证器是基于每个请求创建的,并且这些属性将通过验证器传递建设。


如果您不想禁用部分状态保存(非常合理),那么最好的办法是自己在视图范围的托管 bean 中创建并保存验证器:

public Validator getValidator() 
    return new DoubleRangeValidator(foo.getMaximum(), foo.getMinimum());

(请注意,在 getter 中执行此操作是一个糟糕的设计,但由于您在 setter 中准备 foo 而不是 preRenderView 侦听器方法,因此没有其他方法,否则将是在同一个监听器方法中完成)

<h:inputText validator="#fooController.validator.validate" ...>

或者,或者,为替换 &lt;f:validateDoubleRange&gt; 的内容创建一个自定义验证器:

<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,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?