2009年1月16日星期五

JSF_016:使用PhaseListener观察JSF生命周期的各个阶段

本文最后一次修改时间:2012-05-02。
开发环境 :JDeveloper 11.1.2.1.0。
我们知道JSF把一个页面分为了六个阶段,组件上的不同的事件发生在不同的阶段。
组件上的有些属性可能会改变事件发生的阶段。
为了能够清楚地了解这些事件发生的阶段,我们需要使用PhaseListener来观察JSF生命周期。

1. PhaseListener 代码如下:
package com.javaneverdie.adf.lifecycle.view.phaselistener;

import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

public class MyPhaseListener implements PhaseListener {
public MyPhaseListener() {
super();
}

public void beforePhase(PhaseEvent pe) {
if (pe.getPhaseId() == PhaseId.RESTORE_VIEW)
System.out.println("###### Processing new Request!");

System.out.println("before - " + pe.getPhaseId().toString());
}

public void afterPhase(PhaseEvent pe) {
System.out.println("after - " + pe.getPhaseId().toString());

if (pe.getPhaseId() == PhaseId.RENDER_RESPONSE)
System.out.println("###### Done with Request!\n");
}

public PhaseId getPhaseId() {
return PhaseId.ANY_PHASE;
}
}

2. BackingBean 代码如下:
package com.javaneverdie.adf.lifecycle.view.backing;

public class MyBackingBean {
public MyBackingBean() {
super();
}

public String clickMe_action() {
System.out.println("$$$$$ Action event processed...");
return "success";
}
}

3. Validator 代码如下:
package com.javaneverdie.adf.lifecycle.view.validator;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

public class MyValidator implements Validator {
public MyValidator() {
super();
}

public void validate(FacesContext context, UIComponent component,
Object obj) throws ValidatorException {

System.out.println("$$$$$ Validate processed...");

}
}

4. ValueChangeListener 代码如下:

package com.javaneverdie.adf.lifecycle.view.valuechangelistener;

import javax.faces.event.ValueChangeListener;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.AbortProcessingException;

public class MyValueChangeListener implements ValueChangeListener {

public MyValueChangeListener() {
}

public void processValueChange(ValueChangeEvent vce) throws AbortProcessingException {
System.out.println("$$$$$ Value Change event processed...");
}
}

5. faces-config.xml 内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee">
<application>
<default-render-kit-id>oracle.adf.rich</default-render-kit-id>
</application>
<lifecycle>
<phase-listener>com.javaneverdie.adf.lifecycle.view.phaselistener.MyPhaseListener</phase-listener>
</lifecycle>
<managed-bean>
<managed-bean-name>myBackingBean</managed-bean-name>
<managed-bean-class>com.javaneverdie.adf.lifecycle.view.backing.MyBackingBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<validator>
<validator-id>myValidator</validator-id>
<validator-class>com.javaneverdie.adf.lifecycle.view.validator.MyValidator</validator-class>
</validator>
</faces-config>

好,下面我们就可以做一些有意思的实验了。

实验1:页面中只有一个Button,代码如下:
<h:commandButton value="Click Me" id="cb1" action="#{myBackingBean.clickMe_action}"/>
第一次Run的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

我们注意到,页面初始化时,只进入了两个生命周期阶段:RESTORE_VIEW 1 和 RENDER_RESPONSE 6。
这符合JSF生命周期的规范,详细说明请参考《JSF 的生命周期》。

点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
after - APPLY_REQUEST_VALUES 2
before - PROCESS_VALIDATIONS 3
after - PROCESS_VALIDATIONS 3
before - UPDATE_MODEL_VALUES 4
after - UPDATE_MODEL_VALUES 4
before - INVOKE_APPLICATION 5
$$$$$ Action event processed...
after - INVOKE_APPLICATION 5

before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

我们注意到,因为点击了按钮,相当于发出了POST请求,页面经历了完整的六个阶段。其中按钮上的action事件是在INVOKE_APPLICATION 5阶段被调用。

实验2:页面代码同上,只是增加immediate="true":
点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Action event processed...
after - APPLY_REQUEST_VALUES 2

before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

点击了按钮,相当于发出了POST请求,本来页面应该经历完整的六个阶段。
但是,因为按钮上的immediate="true",我们发现只经历了三个阶段,并且按钮上的action事件是在APPLY_REQUEST_VALUES 2阶段被调用。

实验3:一个InputText,一个validator,一个valueChangeListener,一个Button,页面代码如下:
<h:inputText value="hello">
<f:valueChangeListener type="com.javaneverdie.adf.lifecycle.view.valuechangelistener.MyValueChangeListener"/>
<f:validator validatorId="myValidator"/>
</h:inputText>
<h:commandButton value="Submit" id="cb1" action="#{myBackingBean.clickMe_action}"/>

点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
after - APPLY_REQUEST_VALUES 2
before - PROCESS_VALIDATIONS 3
$$$$$ Validate processed...
$$$$$ Value Change event processed...
after - PROCESS_VALIDATIONS 3

before - UPDATE_MODEL_VALUES 4
after - UPDATE_MODEL_VALUES 4
before - INVOKE_APPLICATION 5
$$$$$ Action event processed...
after - INVOKE_APPLICATION 5

before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

点击了按钮,相当于发出了POST请求,页面经历了完整的六个阶段。
其中值得注意的是,validator先调,valueChangeListener后调,两个事件都在PROCESS_VALIDATIONS 3阶段中被调用。
这其实符合我们一般的认识:只有验证通过了,才应该产生值变事件。

实验4:页面代码同上,只是在按钮上增加immediate="true":
点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Action event processed...
after - APPLY_REQUEST_VALUES 2
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

点击了按钮,相当于发出了POST请求,本来页面应该经历完整的六个阶段。
但是,因为按钮上的immediate="true",我们发现只经历了三个阶段。
其中值得注意的是,InputText上的validator和valueChangeListener并没有被调用!
这其实是我们在命令组件上使用immediate="true"的最常用的一个原因:跳过验证,直接处理action事件。
另外我们注意到,按钮上的action事件是在APPLY_REQUEST_VALUES 2阶段被调用得。

实验5:如果在输入组件上设置immediate="true",会有怎样的效果呢?代码如下:
<af:form id="f1">
<h:inputText value="hello" immediate="true">
<f:valueChangeListener type="com.javaneverdie.adf.lifecycle.view.valuechangelistener.MyValueChangeListener"/>
<f:validator validatorId="myValidator"/>
</h:inputText>
<h:inputText value="hello2">
<f:valueChangeListener type="com.javaneverdie.adf.lifecycle.view.valuechangelistener.MyValueChangeListener2"/>
<f:validator validatorId="myValidator2"/>
</h:inputText>
<h:commandButton value="Submit" id="cb1" action="#{myBackingBean.clickMe_action}"/>
</af:form>

点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Validate processed...
$$$$$ Value Change event processed...
after - APPLY_REQUEST_VALUES 2

before - PROCESS_VALIDATIONS 3
$$$$$ Validate 2 processed...
$$$$$ Value Change 2 event processed...
after - PROCESS_VALIDATIONS 3

before - UPDATE_MODEL_VALUES 4
after - UPDATE_MODEL_VALUES 4
before - INVOKE_APPLICATION 5
$$$$$ Action event processed...
after - INVOKE_APPLICATION 5
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

我们注意到第1个InputText的validator和valueChanger发生在APPLY_REQUEST_VALUES 2阶段,这是因为在这个InputText上的immediate="true"。
而第2个InputText的validator和valueChanger发生在PROCESS_VALIDATIONS 3阶段。

实验6:如果在第1个InputText上验证错误了以后,是否还会验证第2个InputText呢?
我们让第1个InputText上的validator抛出异常 throw new ValidatorException(message);
点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Validate processed...
after - APPLY_REQUEST_VALUES 2
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

从结果可以看出,由于第1个InputText验证没有通过,因此第2个InputText的validator也不再被调用了。
也就是说,在没有改正第1个InputText的错误之前,其它的验证器都不会起作用。

Project 下载:JSF_Lifecycle.7z

没有评论: