作为下一代WEB框架标准,JSF在视图颗粒度与生命周期规划方面都做的不错。
对于生命周期的执行,所有的操作都归结到Lifecycle这个接口。接口包括了两个主要的方法:
public abstract void execute(FacesContext context) throws FacesException和public abstract void render(FacesContext context) throws FacesException;前者是用来执行各个生命周期的阶段,也就是除了render之外的其他五个阶段,而且是按照相应的顺序执行。而 render,是执行最后一个阶段,展示页面。可能有人不太理解,为什么不把两个方法合并成一个方法,刚开始,我也是这么认为。既然已经定义了相应的Phase,何必要把最后的render过程分离出来。看了sun 的RI实现类,发现在render之前需要进行context.getResponseComplete()判断,可能规范中,认为render是必须要执行的阶段,其他的阶段可以跳过,所以分离了相应的方法,同时在执行前,为了避免重复输出,需要对render过程进行特殊的处理.
周期阶段如下图所示:
[img]http://dl.iteye.com/upload/picture/pic/75903/f91f4c63-d097-3408-b3f6-b729e7ff8202.png[/img]
关于六个阶段的说明:
1 RESTORE_VIEW:查找原有的view ,恢复原有的状态,如果没有,则调用ViewHandler.createView,如果为post操作,则按照顺序执行各个阶段。
否则执行RENDER_RESPONSE阶段。
2 APPLY_REQUEST_VALUES:读取客户端参数,处理各个组件的processDecodes方法,内部调用decode方法,由Renderer执行decode方法
3 PROCESS_VALIDATIONS:执行组件的processValidators方法,对于UIInput执行validate方法,用于绑定值,调用convert,和validate
4 UPDATE_MODEL_VALUES:执行组件的processUpdates方法,对于UIViewRoot,执行broadcastEvents和notifyPhaseListeners
所有的UIInput,执行updateModel方法。
5 INVOKE_APPLICATION:调用UIViewRoot.processApplication方法。这一过程主要读取相应的action配置,如果存在action,则调用 action,也就是调用应用逻辑。在执行完相应的逻辑后,查询action是否返回值,如果有,由navigationHandler去读取下一个 view id。
6 RENDER_RESPONSE:展示view,调用ViewHandler.renderView,展示view。
每 个阶段定义定义的都比较清晰,有一点需要注意的是,在处理请求时,并不一定会执行每个阶段,可能其中会直接跳到最后的render response阶段。举例来说,如果validator时,存在错误信息,那么就会直接到render response阶段,而下一个阶段不会执行。
对应不同的解析阶段,可以对应不同的解析监听,示例程序如下:
注意:getPhaseId()方法的返回值,这个监听器的作用很简单,就是为了显示信息。
当然还需要在faces-config.xml中进行配置:
接下来,我们再准备一个自定义的Validator.和一个自定义的Convorter.他们分别实现Validator接口和Converter接口。
大家可以看到。这些代码的作用就是为了打印信息,以便我们可以跟踪生命周期的过程。当然不要忘记在faces-config.xml中配置上
以上准备工作完成后,我们需要准备一个简单的登录页面,和一个简单的BackBean.就可以开始我们验证了。
这里是一个代码片段,使用到了Tomahwark技术。读者可以把全部的<t:>开头的标签换成<h: >的标签就可以了。
最后:使用一个Back Bean.一个很简单的Bean就可以了。加上Name 和Password属性。加一个login方法。
返回字符串。在配置文件中,导航到一个显示页面。在现实页面中,用<h:outputText>标签显示信息就可以了
如:<h:outputText value="#{bean.name}" />.这部分比较简单。
注:本文参照了帖子http://www.iteye.com/topic/76988和http://blog.csdn.net/woai_432/archive/2008/05/11/aspx
对于生命周期的执行,所有的操作都归结到Lifecycle这个接口。接口包括了两个主要的方法:
public abstract void execute(FacesContext context) throws FacesException和public abstract void render(FacesContext context) throws FacesException;前者是用来执行各个生命周期的阶段,也就是除了render之外的其他五个阶段,而且是按照相应的顺序执行。而 render,是执行最后一个阶段,展示页面。可能有人不太理解,为什么不把两个方法合并成一个方法,刚开始,我也是这么认为。既然已经定义了相应的Phase,何必要把最后的render过程分离出来。看了sun 的RI实现类,发现在render之前需要进行context.getResponseComplete()判断,可能规范中,认为render是必须要执行的阶段,其他的阶段可以跳过,所以分离了相应的方法,同时在执行前,为了避免重复输出,需要对render过程进行特殊的处理.
周期阶段如下图所示:
[img]http://dl.iteye.com/upload/picture/pic/75903/f91f4c63-d097-3408-b3f6-b729e7ff8202.png[/img]
关于六个阶段的说明:
1 RESTORE_VIEW:查找原有的view ,恢复原有的状态,如果没有,则调用ViewHandler.createView,如果为post操作,则按照顺序执行各个阶段。
否则执行RENDER_RESPONSE阶段。
2 APPLY_REQUEST_VALUES:读取客户端参数,处理各个组件的processDecodes方法,内部调用decode方法,由Renderer执行decode方法
3 PROCESS_VALIDATIONS:执行组件的processValidators方法,对于UIInput执行validate方法,用于绑定值,调用convert,和validate
4 UPDATE_MODEL_VALUES:执行组件的processUpdates方法,对于UIViewRoot,执行broadcastEvents和notifyPhaseListeners
所有的UIInput,执行updateModel方法。
5 INVOKE_APPLICATION:调用UIViewRoot.processApplication方法。这一过程主要读取相应的action配置,如果存在action,则调用 action,也就是调用应用逻辑。在执行完相应的逻辑后,查询action是否返回值,如果有,由navigationHandler去读取下一个 view id。
6 RENDER_RESPONSE:展示view,调用ViewHandler.renderView,展示view。
每 个阶段定义定义的都比较清晰,有一点需要注意的是,在处理请求时,并不一定会执行每个阶段,可能其中会直接跳到最后的render response阶段。举例来说,如果validator时,存在错误信息,那么就会直接到render response阶段,而下一个阶段不会执行。
对应不同的解析阶段,可以对应不同的解析监听,示例程序如下:
package com.achievo.jason.listener;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import javax.faces.component.UIInput;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.CharSet;
public class MyPhaseListener implements PhaseListener
...{
public void afterPhase(PhaseEvent event)
...{
if(event.getPhaseId().equals(PhaseId.RESTORE_VIEW))
...{
System.out.println("after restore view: phase id - " + PhaseId.RESTORE_VIEW);
}
if(event.getPhaseId().equals(PhaseId.APPLY_REQUEST_VALUES))
...{
System.out.println("after APPLY_REQUEST_VALUES: phase id - " + PhaseId.APPLY_REQUEST_VALUES);
}
if(event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS))
...{
System.out.println("after PROCESS_VALIDATIONS: phase id - " + PhaseId.PROCESS_VALIDATIONS);
}
if(event.getPhaseId().equals(PhaseId.UPDATE_MODEL_VALUES))
...{
System.out.println("after UPDATE_MODEL_VALUES: phase id - " + PhaseId.UPDATE_MODEL_VALUES);
}
if(event.getPhaseId().equals(PhaseId.INVOKE_APPLICATION))
...{
System.out.println("after INVOKE_APPLICATION: phase id - " + PhaseId.INVOKE_APPLICATION);
}
if(event.getPhaseId().equals(PhaseId.RENDER_RESPONSE))
...{
System.out.println("after RENDER_RESPONSE: phase id - " + PhaseId.RENDER_RESPONSE);
}
}
public void beforePhase(PhaseEvent event)
...{
if(event.getPhaseId().equals(PhaseId.RESTORE_VIEW))
...{
System.out.println("before restore view: phase id - " + PhaseId.RESTORE_VIEW);
}
if(event.getPhaseId().equals(PhaseId.APPLY_REQUEST_VALUES))
...{
System.out.println("before APPLY_REQUEST_VALUES: phase id - " + PhaseId.APPLY_REQUEST_VALUES);
}
if(event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS))
...{
System.out.println("before PROCESS_VALIDATIONS: phase id - " + PhaseId.PROCESS_VALIDATIONS);
}
if(event.getPhaseId().equals(PhaseId.UPDATE_MODEL_VALUES))
...{
System.out.println("before UPDATE_MODEL_VALUES: phase id - " + PhaseId.UPDATE_MODEL_VALUES);
}
if(event.getPhaseId().equals(PhaseId.INVOKE_APPLICATION))
...{
System.out.println("before INVOKE_APPLICATION: phase id - " + PhaseId.INVOKE_APPLICATION);
}
if(event.getPhaseId().equals(PhaseId.RENDER_RESPONSE))
...{
System.out.println("before RENDER_RESPONSE: phase id - " + PhaseId.RENDER_RESPONSE);
}
}
public PhaseId getPhaseId()
...{
// TODO Auto-generated method stub
return PhaseId.ANY_PHASE;
}
}
注意:getPhaseId()方法的返回值,这个监听器的作用很简单,就是为了显示信息。
当然还需要在faces-config.xml中进行配置:
<lifecycle>
<phase-listener>com.achievo.jason.listener.MyPhaseListener</phase-listener>
</lifecycle>
接下来,我们再准备一个自定义的Validator.和一个自定义的Convorter.他们分别实现Validator接口和Converter接口。
package com.achievo.jason.validator;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
public class MyRequiredValidator implements Validator
...{
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException
...{
System.out.println("my validdator: component id=====>" + component.getId()
+ " value====>" + value);
//throw new ValidatorException(new FacesMessage("my validator failed"));
}
}
package com.achievo.jason.converter;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
public class MyConverter implements Converter
...{
public Object getAsObject(FacesContext context, UIComponent component, String value)
throws ConverterException
...{
System.out.println("getAsObject : value====>" + value);
return value;
}
public String getAsString(FacesContext context, UIComponent component, Object value)
throws ConverterException
...{
System.out.println("getAsString : value====>" + value);
return (String)value;
}
}
大家可以看到。这些代码的作用就是为了打印信息,以便我们可以跟踪生命周期的过程。当然不要忘记在faces-config.xml中配置上
<converter>
<converter-id>myConverter</converter-id>
<converter-class>com.achievo.jason.converter.MyConverter</converter-class>
</converter>
<validator>
<validator-id>myRequiredValidator</validator-id>
<validator-class>com.achievo.jason.validator.MyRequiredValidator</validator-class>
</validator>
以上准备工作完成后,我们需要准备一个简单的登录页面,和一个简单的BackBean.就可以开始我们验证了。
<f:view>
<h:form id="form">
<t:panelGrid columns="3" cellpadding="3" cellspacing="3" headerClass="login-heading">
<h:outputLabel for="userNameInput">
<t:outputText value="Name" />
</h:outputLabel>
<t:inputText id="userNameInput" maxlength="30" >
<f:validateLength maximum="30" minimum="3" />
</t:inputText>
<h:message for="userNameInput" errorClass="errors" />
<h:outputLabel for="passwordInput">
<t:outputText value="Password" />
</h:outputLabel>
<t:inputSecret id="passwordInput" maxlength="20" size="20">
<f:validator validatorId="myRequiredValidator" />
</t:inputSecret>
<h:message for="passwordInput" errorClass="errors" />
<h:commandButton action="#{authentication.login}" value="submit">
<t:panelGrid>
</h:form>
</f:view>
这里是一个代码片段,使用到了Tomahwark技术。读者可以把全部的<t:>开头的标签换成<h: >的标签就可以了。
最后:使用一个Back Bean.一个很简单的Bean就可以了。加上Name 和Password属性。加一个login方法。
返回字符串。在配置文件中,导航到一个显示页面。在现实页面中,用<h:outputText>标签显示信息就可以了
如:<h:outputText value="#{bean.name}" />.这部分比较简单。
注:本文参照了帖子http://www.iteye.com/topic/76988和http://blog.csdn.net/woai_432/archive/2008/05/11/aspx