我想请一些人帮助理解JSF在验证阶段显示的特定行为失败。
我正在使用:
- Tomcat 7.0.2
- JSF 1.2_12
- RichFaces 3.3.3
问题描述。
我写了一个有4个输入字段的表单:一个inputText和3个selectOneMenu。inputText是必需的而selectOneMenus不需要任何验证。附加到第一个selectOneMenu(第32行),是一个a4j:support标记,因此每当触发更改事件时以及第三个selectOneMenu(行44和58)被正确填充。特别是在加载之后在两个项目列表中,该方法强制第二个和第三个的值选择OneMenu设置为null。在我提交表格而不填写输入之前,这种机制似乎运行良好text:不出所料,JSF验证失败,但当我更改第一个selectOneMenu的值时,页面持续显示JSF验证第二次失败之前指定的值第三个选择OneMenu(注意actionListener仍然被调用,第二个和第三个selectOneMenu仍然被强制为null)。
由于我使用的是一个简单的PhaseListener,我注意到了以下内容:在JSF验证失败之前,每次我更改第一个selectOneMenu的值时,JSF生命在渲染期间,cycle总是为第二个和第三个selectOneMenu调用get方法响应阶段。通过这种方式,JSF能够"看到"在调用应用程序阶段。验证失败后,当我更改第一个getter的值时,JSF停止调用这些getter选择OneMenu。
这是我的看法
<?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 calledn");
return procedura;
}
public void setProcedura(String p) {
procedura = p;
}
public String getBanca() {
System.out.println("ngetBanca calledn");
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 calledn");
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("nnnAFTER setting:n");
System.out.println("nProcedura: "+procedura+"n");
System.out.println("Banca: "+banca+"n");
return "";
}
}
听起来您正在观察EditableValueHolder
类型的预期行为。
如果类型的验证或转换失败,表单将以提交时的状态重新提交。这在应用请求值阶段(JSF 2规范)的文档中有所暗示:
在此阶段结束时,组件树中的所有
EditableValueHolder
组件都将使用此请求中包含的新提交值进行更新(或者,如果存在转换错误,则将存储足够的数据来再现不正确的输入)
如果转换或验证失败,更新模型值阶段将不会运行(不会在bean上调用任何setter。)如果用户刚刚提交了一个复杂的表单,他们不会因为其中一个错误而期望擦除所有字段。渲染器发出用户提交的值,而不调用getter(请参见isValid()
和getSubmittedValue()
)。