JSF生命周期
分为几个阶段:
Restore View:当(重新)访问JSP的时候,重建server端组件树。
Apply Request Value:将request parameters 复制到component submitted values。
Process Validators:执行验证。
Update Model Values:更新model数据:<h:inputText value="#{user.name}"/>
Invoke Application:调用应用程序:Action。
Render Response:渲染Response:保存状态并装载下一个视图。
FacesContext.renderResponse()可以跳过其他阶段,直接到RenderResponse;
FacesContext.responseComplete()可以跳过所有阶段。
ValueChangeEvent
<h:selectOneMenu value="#{eventDemo.provinceId}" onchange="submit()" valueChangeListener="#{eventDemo.onProvincesChange}"> <f:selectItems value="#{eventDemo.provinces}"/> </h:selectOneMenu> |
eventDemo是一个ManagedBean,onProvincesChange的代码:
/** * Value改变事件 * @param event instance of ValueChangeEvent */ public void onProvincesChange(ValueChangeEvent event) { String pId = event.getNewValue().toString(); //修改provincesFlags以改变getProvinces()的输出结果 provincesFlags = Integer.valueOf(pId).intValue(); } |
方法的名字是任意的,但是参数类型和返值类型不能改变。
getOldValue()和getNewValue是ValueChangeEvent常用方法。
上述代码可以工作但是,每次修改下拉菜单都导致submit事件,所有“阶段都会执行”,而我们不希望执行验证等阶段,所以修改为:
<h:selectOneMenu value="#{eventDemo.provinceId}" onchange="submit()" valueChangeListener="#{eventDemo.onProvincesChange}" immediate="true"> <f:selectItems value="#{eventDemo.provinces}"/> </h:selectOneMenu> |
/** * Value改变事件 * @param event instance of ValueChangeEvent */ public void onProvincesChange(ValueChangeEvent event) { String pId = event.getNewValue().toString(); //修改provincesFlags以改变getProvinces()的输出结果 provincesFlags = Integer.valueOf(pId).intValue(); //页面组件定义为immediate,调用renderResponse以跳过验证阶段 FacesContext ctx = FacesContext.getCurrentInstance(); ctx.renderResponse(); } |
注意黑体部分。
ActionListener事件
在执行Action的同时执行,与Action的区别在于:
ActiontListener可以获取页面信息,所以被用来处理与页面有关的事情;而Action可以调用业务逻辑并控制页面导航。
调用Action Listener的代码:
<h:commandButton value="OK" action="#{eventDemo.demoAction}" actionListener="#{eventDemo.demoActionListener}"/> |
/** * 事件监听,用于处理与View事件有关的事情 * @param event */ public void demoActionListener(ActionEvent event) { //这里处理页面显示相关的代码 } |
事件标签
除了使用actionListener和valueChangeListener属性之外,还可以使用事件标签:
<h:selectOneMenu value="#{eventDemo.provinceId}" onchange="submit()" valueChangeListener="#{eventDemo.onProvincesChange}" immediate="true"> <f:valueChangeListener type="net.chinasam.samples.jsf.ValueChangeEventDemo"/> <f:selectItems value="#{eventDemo.provinces}"/> |
package net.chinasam.samples.jsf;
import javax.faces.event.AbortProcessingException; import javax.faces.event.ValueChangeEvent; import javax.faces.event.ValueChangeListener;
public class ValueChangeEventDemo implements ValueChangeListener {
public void processValueChange(ValueChangeEvent event) throws AbortProcessingException { System.out.println("DEMO"); }
} |
注意:与valueChangeListener属性不同,标签可以声明多个,也就是说,valueChange事件可以被多个Listener监听,Action事件也一样。另外标签中type属性指向一个类名,该类必须实现ValueChanageListener接口(Action事件则是ActionListener接口)。
阶段事件
<lifecycle> <phase-listener>net.chinasam.samples.jsf.PhaseEventDemo</phase-listener> </lifecycle> |
可以监听各个阶段,<phase-listener>中声明的类必须实现javax.faces.event.PhaseListener接口,该接口有3个方法:
public void afterPhase(PhaseEvent event) { System.out.println(event.getPhaseId()); }
public void beforePhase(PhaseEvent event) { System.out.println(event.getPhaseId()); }
public PhaseId getPhaseId() { return PhaseId.INVOKE_APPLICATION; } |
afterPhase在执行某个阶段之后被调用,beforePhase方法则反之,getPhaseId被JSF调用以决定在那个阶段执行他们。