实时事件

 所谓的实时事件(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
index.jsp
<%@ 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。

  基于范例的完整起见,我们列出这个程序Bean对象及faces-config.xml:

  • UserBean.java
UserBean.java
package onlyfun.caterpillar;

 import javax.faces.event.ActionEvent;

 public class UserBean {
    private String locale = "en";
    private String name;
    private String password;
    private String errMessage;

    public void changeLocale(ActionEvent e) {
        if(locale.equals("en"))
            locale = "zh_TW";
        else
            locale = "en";
    }

    public String getLocale() {
        if (locale == null) {
            locale = "en";
        }
        return locale;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPassword() {
        return password;
    }

    public void setErrMessage(String errMessage) {
        this.errMessage = errMessage;
    }

    public String getErrMessage() {
        return errMessage;
    }

    public String verify() {
        if(!name.equals("justin") ||
           !password.equals("123456")) {
            errMessage = "名称或密码错误";
            return "failure";
        }
        else {
            return "success";
        }
    }
 }
  • faces-config.xml
faces-config.xml
<?xml version="1.0"?>
 <!DOCTYPE faces-config PUBLIC
 "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
 "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">

 <faces-config>
    <navigation-rule>
        <from-view-id>/pages/index.jsp</from-view-id>
        <navigation-case>
            <from-outcome>success</from-outcome>
            <to-view-id>/pages/welcome.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
            <from-outcome>failure</from-outcome>
            <to-view-id>/pages/index.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>

    <managed-bean>
        <managed-bean-name>user</managed-bean-name>
        <managed-bean-class>
            onlyfun.caterpillar.UserBean
        </managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
 </faces-config>

  讯息资源文件的内容则是如下:

  • messages_en.properties
messages_en.properties
titleText=JSF Demo
 hintText=Please input your name and password
 nameText=name
 passText=password
 commandText=Submit
 Text=\u4e2d\u6587

  Text中设定的是「中文」转换为Java Unicode Escape格式的结果,另一个讯息资源文件的内容则是英文讯息的翻译而已,其转换为Java Unicode Escape格式结果如下:

  • messages_zh_TW.properties
messages_zh_TW.properties
titleText=JSF\u793a\u7bc4
 hintText=\u8acb\u8f38\u5165\u540d\u7a31\u8207\u5bc6\u78bc
 nameText=\u540d\u7a31
 passText=\u5bc6\u78bc
 commandText=\u9001\u51fa
 Text=English

  welcome.jsp就请自行设计了,程序的画面如下: