我是JSF的新手,我对非常简单的Facelets视图有一个问题:
<!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:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core" >
<h:head>
<title></title>
</h:head>
<h:body>
<h:form id="form">
<h:panelGrid id="ciccio" columns="2">
<h:outputText value="Nome " />
<h:inputText value="#{thinBean.nome}" />
<h:commandButton id="ok" value="OK" />
<h:commandButton id="vai" value="Go" rendered="#{not empty thinBean.nome}" action="Vista1" />
</h:panelGrid>
</h:form>
</h:body>
</html>
和我简单的背豆。
package magazzino;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class ThinBean implements Serializable {
private String nome;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
}
第一次呼叫后,只显示第一个按钮。当我在字段nome
上输入test
并通过单击由ok
标识的按钮提交此表单时,还会出现第二个按钮。
当我点击由vai
标识的第二个按钮时,什么都没有发生:Vista1
没有被渲染。
我不理解这种行为:为什么跳过调用应用程序阶段?
感谢
UICommand
组件的rendered
属性在应用请求值阶段也进行了评估,作为防止被篡改/黑客入侵请求的一部分,例如,黑客试图调用UICommand
组件的操作,而这些操作不是为非管理员用户呈现的。
在您的特定情况下,您使用的是一个请求范围的bean。因此,bean在每个请求结束时被销毁,并在每个请求开始时被重新创建。通过第一个按钮提交表单算作一个请求。通过第二个按钮提交表单算作另一个请求。
在更新模型值阶段,UIInput
值被设置为托管bean属性,这是在应用请求值阶段之后的。因此,当按下第二个按钮时,将新建请求范围的bean,并将所有属性设置为默认值(null
)。在应用请求值阶段,rendered
属性正在检查输入值,但尚未设置,并且bean是新的且为空的。因此,它不会将按钮视为已渲染,并跳过对动作事件的解码。
如果您将bean放在视图范围中,那么它会起作用,原因很简单,只要您通过返回null
或void
与同一视图交互,视图范围的bean实例就会一直存在。
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
另一种选择是检查rendered
属性中的原始HTTP请求参数,而不是模型值。
<h:inputText binding="#{nome}" value="#{thinBean.nome}" />
<h:commandButton id="ok" value="OK" />
<h:commandButton id="vai" value="Go" rendered="#{not empty param[nome.clientId]}" action="Vista1" />
另请参阅:
- 如何选择正确的bean范围