JSF生命周期详解

来源:互联网 发布:单片机 蓝牙 编辑:程序博客网 时间:2024/06/06 03:49

我们知道JSF生命周期一共有6个phase.关于这六个phase的图表说明,很多参考资料上都有,我个人觉得JSF in action这本书上的图标说明比较直观,也比较好理解。现在我将用一个例子来说明JSF的生命周期。这个例子是JSF1.1环境下编写的。

为了方便理解:我先把这6个phase写到这里:

1.Restore view

2.Apply request values.

3.Process validations.

4.Update model values.

5.Invoke applications.

6.Render response.

为了演示具体的步骤,首先我们需要一个自定义的Listener. 实现PhaseListener接口。

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}" />.这部分比较简单。我就不详细写了。

到目前为止,我们整个代码已经写完了。读者可以把这些代码COPY自己环境里运行。然后查看打印出来的信息。

相信会对你理解生命周期有很大的帮助。在运行的过程中,你可以通过改变按钮的:immediate属性。和input输入域的immediate属性。得到不同的信息。

由于时间关系,今天写到这里。我只能下次来详细介绍上面代码运行显示的结果及其原因。不过读者现在已经可以自己运行代码来理解生命周期。