为什么 f:validateDoubleRange 仅适用于 @SessionScoped? [英] Why does f:validateDoubleRange only work for @SessionScoped?

查看:16
本文介绍了为什么 f:validateDoubleRange 仅适用于 @SessionScoped?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释为什么我的示例中的 Foo 在到达 validateDoubleRange 类时总是为 null 吗?最终结果是验证器的最小值始终为 0.当在 outputText 元素中时,数字 3 在页面上显示得很好.如果我使 bean @SessionScoped 而不是 @ViewScoped

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

控制器:

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

I am using JSF 2 on JBoss 6.1

如果你在@BalusC,这是我能想到的最简单的例子,和昨天的问题一样,只是,我希望,澄清和更容易复制.

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.

-- 编辑,我应该添加 fooId 是通过视图参数设置的,因此您需要在 URL 末尾添加 ?fooId=3.

-- edit, I should add that fooId is set via a view param, so you need ?fooId=3 at the end of your URL.

推荐答案

我现在明白为什么我昨天无法重现这个问题.在我的操场环境中,我不小心设置了与默认值不同的以下上下文参数:

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:

<context-param>
    <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
    <param-value>false</param-value>
</context-param>

这个问题与 JSF issue 1492有关. 其属性由 EL 绑定到视图范围的 bean 属性,由于令人讨厌的鸡蛋问题,它将隐式地重新创建整个 bean,因为验证器是在每个请求上创建的基础,这些属性将在验证器的构造中传递.

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.

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

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:

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

(注意,在 getter 中做这些事情是一个糟糕的设计,但是因为你在 setter 中准备 foo 而不是 preRenderView 侦听器方法, 没有别的办法了,不然就在同一个监听器方法里做对了)

(note, doing this stuff in a getter is a bad design, but since you're preparing foo in a setter instead of a preRenderView listener method, there's no other way, otherwise it would be done right in the same listener method)

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

<小时>

或者,或者,为替换 的内容创建自定义验证器:


Or, alternatively, to create a custom validator for that which replaces the <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 已修复.所以如果你最近偶然发现了这个,那么你也可以考虑升级.


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.

这篇关于为什么 f:validateDoubleRange 仅适用于 @SessionScoped?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆