zoukankan      html  css  js  c++  java
  • life cycle与四个事件

    jsf中有动作事件、即时事件、值变事件、Phase事件四种事件.
    下面将一一说明:
    动作事件:
    通过ActionListener来监听动作事件
    先来看一段简单的jsf页面代码:

    Java代码 
    1. <h:commandButton value="送出" action="#{user.verify}"/>  
    1. <h:commandButton value="送出" action="#{user.verify}"/>  
    <h:commandButton value="送出" action="#{user.verify}"/>


    以上代码中虽然没有涉及ActionListener,但jsf为其默认产生了预定义的ActionListener.
    实际过程是这样:
    JSF会先检查是否有指定的actionListener,然后再检查是否指定了动作方法并为其产生预定义的ActionListener,并根据其传回值导航页面.
    动作事件三种触发方法:
    方法一: 通过指定动作方法

    Java代码 
    1. <h:commandButton value="送出" action="#{user.verify}"/>  
    1. <h:commandButton value="送出" action="#{user.verify}"/>  
    <h:commandButton value="送出" action="#{user.verify}"/>


    方法二: 通过指定ActionListener属性

    Java代码 
    1. <h:commandButton value="送出" actionListener="#{user.verify}" action="#{user.outcome}"/>  
    1. <h:commandButton value="送出" actionListener="#{user.verify}" action="#{user.outcome}"/>  
    <h:commandButton value="送出" actionListener="#{user.verify}" action="#{user.outcome}"/>


    方法三: 通过<f:actionListener>标签向组件注册事件
    • LogHandler.java

    Java代码 
    1. package onlyfun.caterpillar;   
    2. import javax.faces.event.ActionListener;   
    3. ....   
    4. public class LogHandler implements ActionListener {   
    5. public void processAction(ActionEvent e) {   
    6. // 处理Log   
    7. }   
    8. }  
    1. package onlyfun.caterpillar;  
    2. import javax.faces.event.ActionListener;  
    3. ....  
    4. public class LogHandler implements ActionListener {  
    5. public void processAction(ActionEvent e) {  
    6. // 处理Log  
    7. }  
    8. }  
    package onlyfun.caterpillar;
    import javax.faces.event.ActionListener;
    ....
    public class LogHandler implements ActionListener {
    public void processAction(ActionEvent e) {
    // 处理Log
    }
    }


    • VerifyHandler.java

    Java代码 
    1. package onlyfun.caterpillar;   
    2. import javax.faces.event.ActionListener;   
    3. ....   
    4. public class VerifyHandler implements ActionListener {   
    5. public void processAction(ActionEvent e) {   
    6. // 处理验证   
    7. }   
    8. }  
    1. package onlyfun.caterpillar;  
    2. import javax.faces.event.ActionListener;  
    3. ....  
    4. public class VerifyHandler implements ActionListener {  
    5. public void processAction(ActionEvent e) {  
    6. // 处理验证  
    7. }  
    8. }  
    package onlyfun.caterpillar;
    import javax.faces.event.ActionListener;
    ....
    public class VerifyHandler implements ActionListener {
    public void processAction(ActionEvent e) {
    // 处理验证
    }
    }
    Java代码 
    1. <h:commandButton value="送出" action="#{user.outcome}">   
    2. <f:actionListener type="onlyfun.caterpillar.LogHandler"/>   
    3. <f:actionListener type="onlyfun.caterpillar.VerifyHandler"/>   
    4. </h:commandButton>  
    1. <h:commandButton value="送出" action="#{user.outcome}">  
    2. <f:actionListener type="onlyfun.caterpillar.LogHandler"/>  
    3. <f:actionListener type="onlyfun.caterpillar.VerifyHandler"/>  
    4. </h:commandButton>  
    <h:commandButton value="送出" action="#{user.outcome}">
    <f:actionListener type="onlyfun.caterpillar.LogHandler"/>
    <f:actionListener type="onlyfun.caterpillar.VerifyHandler"/>
    </h:commandButton>


    即时事件:
    所谓的即时事件(Immediate Events),是指JSF视图组件在取得请求中该取得的值之后,即立即处理指定的事件,而不再进行后续的转换器处理、验证器处理、更新模型值等流程。
    在JSF的事件模型中之所以会有所谓即时事件,是因为Web应用程序的先天特性不同于GUI程序,所以JSF的事件方式与GUI程序的事件方式仍有相当程度的不同,一个最基本的问题正因为HTTP无状态的特性,使得Web应用程序天生就无法直接唤起服务器端的特定对象。
    所有的对象唤起都是在服务器端执行的,至于该唤起什么对象,则是依一个基本的流程:
    重建视图(Restore View)
    依客户端传来的session数据或服务器端上的session数据,重建JSF视图组件。
    套用请求值(Apply Request Values)
    JSF视图组件各自获得请求中的属于自己的值,包括旧的值与新的值。
    执行验证(Process Validations)
    转换为对象并进行验证。
    更新模型值(Update Model Values)
    更新Bean或相关的模型值。
    唤起应用程序(Invoke Application)
    执行应用程序相关逻辑。
    绘制响应页面(Render Response)
    对先前的请求处理完之后,产生页面以反应客户端执行结果。
    对于动作事件(Action Event)来说,组件的动作事件是在套用请求值阶段就生成ActionEvent对象了,但相关的事件处理并不是马上进行,ActionEvent会先被排入队列,然后必须再通过验证、更新方式值阶段,之后才处理队列中的事件。
    这样的流程对于按下按钮然后执行后端的应用程序来说不成问题,但有些事件并不需要这样的流程,例如只影响页面的事件。
    举个例子来说,在表单中可能有使用者名称、密码等栏目,并提供有一个地区选项按钮,使用者可以在不填写名称、密码的情况下,就按下地区选项按钮,如果依照正常的流程,则会进行验证、更新模型值、唤起应用程序等流程,但显然的,使用者名称与密码是空白的,这会引起不必要的错误。
    您可以设定组件的事件在套用请求值之后立即被处理,并跳过后续的阶段,直接进行页面绘制以响应请求,对于JSF的input与command组件,都有一个immediate属性可以设定,只要将其设定为true,则指定的事件就成为即时事件。
    一个例子如下:
    • index.jsp

    Java代码 
    1. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   
    2. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   
    3. <%@page contentType="text/html;charset=UTF8"%>   
    4. <f:view locale="#{user.locale}">   
    5. <f:loadBundle basename="messages" var="msgs"/>   
    6. <html>   
    7. <head>   
    8. <title><h:outputText value="#{msgs.titleText}"/></title>   
    9. </head>   
    10. <body>   
    11. <h:form>   
    12. <h3><h:outputText value="#{msgs.hintText}"/></h3>   
    13. <h:outputText value="#{msgs.nameText}"/>:   
    14. <h:inputText value="#{user.name}"/><p>   
    15. <h:outputText value="#{msgs.passText}"/>:   
    16. <h:inputSecret value="#{user.password}"/><p>   
    17. <h:commandButton value="#{msgs.commandText}"  
    18. action="#{user.verify}"/>   
    19. <h:commandButton value="#{msgs.Text}"  
    20. immediate="true"  
    21. actionListener="#{user.changeLocale}"/>   
    22. </h:form>   
    23. </body>   
    24. </html>   
    25. </f:view>  
    1. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>  
    2. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>  
    3. <%@page contentType="text/html;charset=UTF8"%>  
    4. <f:view locale="#{user.locale}">  
    5. <f:loadBundle basename="messages" var="msgs"/>  
    6. <html>  
    7. <head>  
    8. <title><h:outputText value="#{msgs.titleText}"/></title>  
    9. </head>  
    10. <body>  
    11. <h:form>  
    12. <h3><h:outputText value="#{msgs.hintText}"/></h3>  
    13. <h:outputText value="#{msgs.nameText}"/>:  
    14. <h:inputText value="#{user.name}"/><p>  
    15. <h:outputText value="#{msgs.passText}"/>:  
    16. <h:inputSecret value="#{user.password}"/><p>  
    17. <h:commandButton value="#{msgs.commandText}"  
    18. action="#{user.verify}"/>  
    19. <h:commandButton value="#{msgs.Text}"  
    20. immediate="true"  
    21. actionListener="#{user.changeLocale}"/>  
    22. </h:form>  
    23. </body>  
    24. </html>  
    25. </f:view>  
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
    <%@page contentType="text/html;charset=UTF8"%>
    <f:view locale="#{user.locale}">
    <f:loadBundle basename="messages" var="msgs"/>
    <html>
    <head>
    <title><h:outputText value="#{msgs.titleText}"/></title>
    </head>
    <body>
    <h:form>
    <h3><h:outputText value="#{msgs.hintText}"/></h3>
    <h:outputText value="#{msgs.nameText}"/>:
    <h:inputText value="#{user.name}"/><p>
    <h:outputText value="#{msgs.passText}"/>:
    <h:inputSecret value="#{user.password}"/><p>
    <h:commandButton value="#{msgs.commandText}"
    action="#{user.verify}"/>
    <h:commandButton value="#{msgs.Text}"
    immediate="true"
    actionListener="#{user.changeLocale}"/>
    </h:form>
    </body>
    </html>
    </f:view>


    这是一个可以让使用者决定使用语系的示范,最后一个commandButton组件被设定了immediate属性,当按下这个按钮后,JSF套用请求值之后会立即处理指定的actionListener,而不再进行验证、更新模型值,需要注意的是,此时您在输入栏目与密码栏目中填入的值,不会影响您的user.name与user.password。
    值变事件
    如果使用者改变了JSF输入组件的值后提交表单,就会发生值变事件(Value Change Event),这会丢出一个javax.faces.event.ValueChangeEvent对象,如果您想要处理这个事件,有两种方法:
    方法一 直接设定JSF输入组件的valueChangeListener属性,例如:

    Java代码 
    1. <h:selectOneMenu value="#{user.locale}"  
    2. onchange="this.form.submit();"  
    3. valueChangeListener="#{user.changeLocale}">   
    4. <f:selectItem itemValue="zh_CN" itemLabel="Chinese"/>   
    5. <f:selectItem itemValue="en" itemLabel="English"/>   
    6. </h:selectOneMenu>  
    1. <h:selectOneMenu value="#{user.locale}"  
    2. onchange="this.form.submit();"  
    3. valueChangeListener="#{user.changeLocale}">  
    4. <f:selectItem itemValue="zh_CN" itemLabel="Chinese"/>  
    5. <f:selectItem itemValue="en" itemLabel="English"/>  
    6. </h:selectOneMenu>  
    <h:selectOneMenu value="#{user.locale}"
    onchange="this.form.submit();"
    valueChangeListener="#{user.changeLocale}">
    <f:selectItem itemValue="zh_CN" itemLabel="Chinese"/>
    <f:selectItem itemValue="en" itemLabel="English"/>
    </h:selectOneMenu>


    注意在此为了模拟GUI中选择了选单项目之后就立即发生反应,我们在onchange属性中使用了JavaScript,其作用是在选项项目发生改变之后,立即提交表单,而不用按下提交按钮
    方法二 实现javax.faces.event.ValueChangeListener接口,并定义其processValueChange()方法,例如:
    • SomeListener.java

    Java代码 
    1. package onlyfun.caterpillar;   
    2. ....   
    3. public class SomeListener implements ValueChangeListener {   
    4. public void processValueChange(ValueChangeEvent event) {   
    5. ....   
    6. }   
    7. ....   
    8. }  
    1. package onlyfun.caterpillar;  
    2. ....  
    3. public class SomeListener implements ValueChangeListener {  
    4. public void processValueChange(ValueChangeEvent event) {  
    5. ....  
    6. }  
    7. ....  
    8. }  
    package onlyfun.caterpillar;
    ....
    public class SomeListener implements ValueChangeListener {
    public void processValueChange(ValueChangeEvent event) {
    ....
    }
    ....
    }


    然后在JSF页面上使用<f:valueChangeListener>标签,并设定其type属性,例如:

    Java代码 
    1. <h:selectOneMenu value="#{user.locale}"  
    2. onchange="this.form.submit();">   
    3. <f:valueChangeListener   
    4. type="onlyfun.caterpillar.SomeListener"/>   
    5. <f:selectItem itemValue="zh_CN" itemLabel="Chinese"/>   
    6. <f:selectItem itemValue="en" itemLabel="English"/>   
    7. </h:selectOneMenu>  
    1. <h:selectOneMenu value="#{user.locale}"  
    2. onchange="this.form.submit();">  
    3. <f:valueChangeListener  
    4. type="onlyfun.caterpillar.SomeListener"/>  
    5. <f:selectItem itemValue="zh_CN" itemLabel="Chinese"/>  
    6. <f:selectItem itemValue="en" itemLabel="English"/>  
    7. </h:selectOneMenu>  
    <h:selectOneMenu value="#{user.locale}"
    onchange="this.form.submit();">
    <f:valueChangeListener
    type="onlyfun.caterpillar.SomeListener"/>
    <f:selectItem itemValue="zh_CN" itemLabel="Chinese"/>
    <f:selectItem itemValue="en" itemLabel="English"/>
    </h:selectOneMenu>


    Phase事件
    在即时事件中我们提到,JSF的请求执行到反应,完整的过程会经过六个阶段.
    在每个阶段的前后会引发javax.faces.event.PhaseEvent,如果您想尝试在每个阶段的前后捕捉这个事件,以进行一些处理,则可以实现javax.faces.event.PhaseListener,并向javax.faces.lifecycle.Lifecycle登记这个Listener,以在适当的时候通知事件的发生。
    PhaseListener有三个必须实现的方法getPhaseId()、beforePhase()与afterPhase(),其中getPhaseId()传回一个PhaseId对象,代表Listener想要被通知的时机,可以设定的时机有:
    PhaseId.RESTORE_VIEW
    PhaseId.APPLY_REQUEST_VALUES
    PhaseId.PROCESS_VALIDATIONS
    PhaseId.UPDATE_MODEL_VALUES
    PhaseId.INVOKE_APPLICATION
    PhaseId.RENDER_RESPONSE
    PhaseId.ANY_PHASE
    其中PhaseId.ANY_PHASE指的是任何的阶段转换时,就进行通知;您可以在beforePhase()与afterPhase()中编写阶段前后编写分别想要处理的动作,例如下面这个简单的类会列出每个阶段的名称:
    • ShowPhaseListener.java

    Java代码 
    1. package onlyfun.caterpillar;   
    2. import javax.faces.event.PhaseEvent;   
    3. import javax.faces.event.PhaseId;   
    4. import javax.faces.event.PhaseListener;   
    5. public class ShowPhaseListener implements PhaseListener {   
    6. public void beforePhase(PhaseEvent event) {   
    7. String phaseName = event.getPhaseId().toString();   
    8. System.out.println("Before " + phaseName);   
    9. }   
    10. public void afterPhase(PhaseEvent event) {   
    11. String phaseName = event.getPhaseId().toString();   
    12. System.out.println("After " + phaseName);   
    13. }   
    14. public PhaseId getPhaseId() {   
    15. return PhaseId.ANY_PHASE;   
    16. }   
    17. }  
    1. package onlyfun.caterpillar;  
    2. import javax.faces.event.PhaseEvent;  
    3. import javax.faces.event.PhaseId;  
    4. import javax.faces.event.PhaseListener;  
    5. public class ShowPhaseListener implements PhaseListener {  
    6. public void beforePhase(PhaseEvent event) {  
    7. String phaseName = event.getPhaseId().toString();  
    8. System.out.println("Before " + phaseName);  
    9. }  
    10. public void afterPhase(PhaseEvent event) {  
    11. String phaseName = event.getPhaseId().toString();  
    12. System.out.println("After " + phaseName);  
    13. }  
    14. public PhaseId getPhaseId() {  
    15. return PhaseId.ANY_PHASE;  
    16. }  
    17. }  
    package onlyfun.caterpillar;
    import javax.faces.event.PhaseEvent;
    import javax.faces.event.PhaseId;
    import javax.faces.event.PhaseListener;
    public class ShowPhaseListener implements PhaseListener {
    public void beforePhase(PhaseEvent event) {
    String phaseName = event.getPhaseId().toString();
    System.out.println("Before " + phaseName);
    }
    public void afterPhase(PhaseEvent event) {
    String phaseName = event.getPhaseId().toString();
    System.out.println("After " + phaseName);
    }
    public PhaseId getPhaseId() {
    return PhaseId.ANY_PHASE;
    }
    }


    编写好PhaseListener后,我们可以在faces-config.xml中向Lifecycle进行注册:
    • faces-config.xml

    Xml代码 
      1. <?xml version="1.0"?>  
      2. <!DOCTYPE faces-config PUBLIC   
      3. "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"   
      4. "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">  
      5. <faces-config>  
      6. <lifecycle>  
      7. <phase-listener>  
      8. onlyfun.caterpillar.ShowPhaseListener   
      9. </phase-listener>  
      10. </lifecycle>  
      11. ..
  • 相关阅读:
    C# 加载 SQLite DLL问题
    Linux chroot 并使用之前系统设备节点
    I.MX6 initramfs.cpio.gz.uboot unpack
    I.MX6 eMMC 添加分区
    Git 一次性 pull push 所有的分支
    ARM compiler No such file or directory
    Linux sed 替换第一次出现的字符串
    C# WinForm 应用程序 开启Console窗口
    No 'Access-Control-Allow-Origin' header is present on the requested resource.
    C# 集合已修改;可能无法执行枚举操作
  • 原文地址:https://www.cnblogs.com/betterprimebestus/p/8901618.html
Copyright © 2011-2022 走看看