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

查看:103
本文介绍了为什么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 。一个< f:validateDoubleRange> 其属性由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());
}

(注意,在吸气剂中做这些东西是一个糟糕的设计,但由于你在setter而不是 preRenderView 监听器方法中准备 foo ,否则别无他法,否则它将在同一个监听方法中完成)

(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)

with

<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}" />

with

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天全站免登陆