验证阶段失败后,Java Server Faces会一直显示旧值(忽略actionListeners设置))

时间:2011-06-12 10:36:52

标签: jsf richfaces

我想请一些帮助来理解JSF在验证阶段时显示的特定行为 失败。

我正在使用:

  • Tomcat 7.0.2
  • JSF 1.2_12
  • RichFaces 3.3.3

问题描述。

我写了一个包含4个输入字段的表单:inputText和3 selectOneMenu。 inputText是必需的 而selectOneMenus不需要任何验证。附加到第一个selectOneMenu(第32行), 是一个a4j:支持标记,以便每当触发更改事件时,第二个项目列表 并正确填充第三个selectOneMenu(第44和58行)。特别是装载后 两个项目列表,该方法强制第二个和第三个selectOneMenu的值 为空。这个机制似乎工作正常,直到我提交表单而不填写输入 text:正如预期的那样,JSF验证失败但是当我更改第一个selectOneMenu的值时, 页面将继续显示在第二个和之后JSF验证失败之前指定的值 第三个selectOneMenu(注意仍然调用actionListener和第二个和的值 第三个selectOneMenu仍被强制为null。

由于我使用的是简单的PhaseListener,因此我注意到以下内容: 在JSF验证失败之前,每次我更改第一个selectOneMenu的值,JSF生命 循环始终在渲染期间为第二个和第三个selectOneMenu调用get方法 响应阶段。通过这种方式,JSF能够“看到”这些值在此期间已设置为null 调用应用程序阶段。 验证失败后,当我更改第一个值时,JSF停止调用这些getter selectOneMenu用于

这是我的观点

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:rich="http://richfaces.org/rich">

<head>
  <title>Prove Rich</title>
</head>

<body>

  <h2>Prove Rich</h2>

  <f:view>

  <a4j:outputPanel ajaxRendered="true">
    <h:messages style="color:red" />
  </a4j:outputPanel>

  <h:form>

  <p>
    Input required: <h:inputText value="#{provaProbReplyBean.inputRequired}" required="true" />
  </p>

  <p>
    <h:outputText value="Scegli il canale:" />
    <h:selectOneMenu value="#{provaProbReplyBean.canale}">

       <f:selectItem itemLabel="--" itemValue="" />
       <f:selectItem itemLabel="Profamily" itemValue="Profamily" />
       <f:selectItem itemLabel="Captive" itemValue="Captive" />

       <a4j:support event="onchange" action="#{provaProbReplyBean.caricaProcBanche}" ajaxSingle="true" reRender="procedure, banche" />
    </h:selectOneMenu>
  </p>

  <p>
    <h:outputText value="Scegli la procedura:" />
    <h:selectOneMenu id="procedure" value="#{provaProbReplyBean.procedura}">

       <f:selectItem itemLabel="--" itemValue="" />

       <f:selectItems value="#{provaProbReplyBean.procedureList}" />

       <!-- immediately save the current value -->
       <a4j:support event="onchange" ajaxSingle="true" />

    </h:selectOneMenu>
  </p>

  <p>
    <h:outputText value="Scegli la banca:" />
    <h:selectOneMenu id="banche" value="#{provaProbReplyBean.banca}">

       <f:selectItem itemLabel="--" itemValue="" />

       <f:selectItems value="#{provaProbReplyBean.bancheList}" />

       <!-- immediately save the current value -->
       <a4j:support event="onchange" ajaxSingle="true" />

    </h:selectOneMenu>
  </p>

  <p><h:commandButton value="Submit" /></p>

  </h:form>

  </f:view>

</body>

</html>

这是我的模特:

public class ProvaProbReply {

    private String inputRequired;

    private String canale;
    private String procedura;
    private String banca;

    private Map<String, List<SelectItem>> canaliProc = new HashMap<String, List<SelectItem>>();
    private Map<String, List<SelectItem>> canaliBanche = new HashMap<String, List<SelectItem>>();

    private List<SelectItem> procedureList = new ArrayList<SelectItem>();
    private List<SelectItem> bancheList = new ArrayList<SelectItem>();

    public ProvaProbReply() {

        List<SelectItem> l = new ArrayList<SelectItem>();
        l.add(new SelectItem("Cessione del quinto"));
        l.add(new SelectItem("Credito al consumo"));
        l.add(new SelectItem("Mutui"));

        canaliProc.put("Profamily", l);

        l = new ArrayList<SelectItem>();
        l.add(new SelectItem("Credito al consumo"));

        canaliProc.put("Captive", l);

        l = new ArrayList<SelectItem>();

        canaliBanche.put("Profamily", l);

        l = new ArrayList<SelectItem>();
        l.add(new SelectItem("BDL"));
        l.add(new SelectItem("BM"));
        l.add(new SelectItem("BPM"));
        l.add(new SelectItem("CRA"));

        canaliBanche.put("Captive", l);
    }

    public String getInputRequired() {

        return inputRequired;
    }

    public void setInputRequired(String ir) {

        inputRequired = ir;
    }

    public String getCanale() {

        return canale;
    }

    public void setCanale(String c) {

        canale = c;
    }

    public String getProcedura() {

        System.out.println("\ngetProcedura called\n");
        return procedura;
    }

    public void setProcedura(String p) {

        procedura = p;
    }

    public String getBanca() {

        System.out.println("\ngetBanca called\n");
        return banca;
    }

    public void setBanca(String b) {

        banca = b;
    }

    public List<SelectItem> getProcedureList() {

        return procedureList;
    }

    public List<SelectItem> getBancheList() {

        return bancheList;
    }

    public String caricaProcBanche() {

        System.out.println("\nListener called\n");

        procedureList.clear();
        bancheList.clear();

        if(canale != null && !canale.equals("")) {

            procedureList.addAll(canaliProc.get(canale));
            bancheList.addAll(canaliBanche.get(canale));
        }

        System.out.println("BEFORE setting:\n");

        System.out.println("\nProcedura: "+procedura+"\n");
        System.out.println("Banca: "+banca+"\n");

        procedura = null;
        banca = null;

        System.out.println("\n\n\nAFTER setting:\n");

        System.out.println("\nProcedura: "+procedura+"\n");
        System.out.println("Banca: "+banca+"\n");

        return "";
    }
}

1 个答案:

答案 0 :(得分:2)

听起来您正在观察EditableValueHolder类型的预期行为。

如果类型的验证或转换失败,表单将在提交的状态下重新呈现。这在应用请求值阶段(JSF 2规范)的文档中有所暗示:

  

在此阶段结束时,组件树中的所有EditableValueHolder组件都将使用此请求中包含的新提交值进行更新(或者,如果存储了用于重现错误输入的足够数据,则有转换错误。)

如果转换或验证失败,更新模型值阶段将不会运行(将不会在bean上调用任何setter。)如果用户刚刚提交了一个复杂的表单,他们就不会期望所有的领域都被擦除,因为一个是错的。渲染器会发出用户提交的值,而不会调用getter(请参阅isValid()getSubmittedValue())。