java创建 jsf项目_将JSF与Dojo小部件结合在一起以创建更好的用户体验

java创建 jsf项目

JSF是一种非常稳定的流行Web框架,已在Java™平台企业版(Java EE)域中得到广泛使用。 Dojo是功能最强大的Web 2.0库之一,使您能够为Web应用程序创建丰富的界面。

通过同时利用这两种技术,您可以获得两种技术的优势。 在服务器端,好处包括组件的端到端生命周期管理,后端bean数据绑定和事件处理。 在客户端,您可以利用Dojo的丰富窗口小部件,实时动画(例如淡入淡出和滑动)以及拖放功能。 此外,借助Dojo框架的API支持,您可以通过在客户端添加更多逻辑来提高性能。

本文介绍了以下利用JSF和Dojo技术的方法:

  • 在客户端延迟绑定JSF组件和Dojo小部件
  • 构建定制的JSF组件以启用Dojo小部件
  • 延迟注入和将JSF组件解析为Dojo小部件

本文中的示例JSF应用程序由两页组成:“创建项目”和“项目结果”。 图1和图2显示了这两页。 为了简单易懂,本文中描述的所有方法都使用了这些图中显示的样本,以演示如何将Dojo与JSF应用程序结合起来。 (您也可以查看图1的图。)

图1.创建项目
创建项目页面的屏幕截图
图2.项目结果
项目结果页面的屏幕截图

该场景确实非常简单。 用户可以输入一些信息来创建项目,然后单击提交按钮,将显示项目信息。 因此,您的任务是将输入框,文本区域和其他JSF组件转换为Dojo小部件。

方法1:在客户端延迟绑定JSF组件和Dojo小部件

这种方法是将Dojo样式应用于JSF组件的最简单方法。 我们只使用JavaScript在客户端将JSF组件和Dojo小部件绑定在一起。 通过使用JavaScript,可以在JSF组件和Dojo小部件之间传输数据并使它们保持一致。

首先,看一下原始的JSF页面。 清单1显示了JSF代码。 (清单1中的代码已格式化为适合本文的内容。单击此处查看完整的代码清单。)

清单1.原始的Create Project JSF页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://www.ibm.com/jsf/html_extended" prefix="hx"%>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

<body>
<f:view>
     <h2>Make your JSF application Dojoable</h2>
     <h3>Create Project</h3>
     <h:form id="project">
     <table>
          <tbody>
               <tr>
                    <td>Project Name:</td>
                    <td><h:inputText id="projectName" 
                          value="#{projectFormBean.projectName}" size="5"/></td>
               </tr>
               <tr>
                    <td>Project description:</td>
                    <td><h:inputTextarea id="projectDescription" 
                          value="#{projectFormBean.projectDescription}" rows="2" 
                          cols="15"/></td>
               </tr>
               <tr>
                    <td colspan=2>
                         <h:commandButton id="button_submit" action="success" 
                          value="Submit" type="submit"></h:commandButton>
                    </td>
               </tr>
          </tbody>
     </table>
     </h:form>
</f:view>
</body>

有两个输入字段:项目名称和项目描述。 这两个字段都与后端表单bean projectFormBean

让我们开始以Dojo样式转换此页面。

步骤1.隐藏JSF组件并添加Dojo小部件

您需要隐藏原始的JSF组件并将其更改为不可见,然后在此页面中添加相关的Dojo小部件。 第一步是导入Dojo库,并声明需要哪些小部件,如清单2所示。(清单2中的代码已经格式化为适合本文的内容。有关完整的代码,请单击此处 。)

清单2.导入Dojo库并声明小部件
<style type="text/css">
    @import url("${pageContext.request.contextPath}/script/
     dojo_lib/dijit/themes/tundra/tundra.css");
     @import url("${pageContext.request.contextPath}/script/dojo_lib/
     dojo/resources/dojo.css");
</style>
<script type="text/javascript" src="${pageContext.request.contextPath}/script/
     dojo_lib/dojo/dojo.js" 
    djConfig="parseOnLoad: true, isDebug:false"></script>

<script type="text/javascript">
   dojo.require("dojo.parser");
   dojo.require("dijit.form.ValidationTextBox");
   dojo.require("dijit.form.Textarea");
</script>

在此示例中,我们使用tundra主题作为默认样式,因此必须首先导入tundra.css和dojo.css。 接下来,您需要导入dojo.js文件,该文件是Dojo的主要js脚本文件。 最后,您必须声明要使用的窗口小部件。 在这种情况下,我们将使用validationTextBoxTextarea 。 Dojo使用按需机制。 它只会根据声明加载所需的文件。 因此,它可以提高应用程序的性能并减少网络传输。

下一步是将JSF组件更改为不可见,并添加Dojo小部件以进行显示。 修改后的jsp如清单3所示。

清单3.将JSF组件更改为不可见,并添加Dojo小部件
<tr>
<td>Project name:</td>
<td><h:inputHidden value="#{projectFormBean.projectName}"/><f:verbatim> 
     <input type="text" name="projectName"
 dojoType="dijit.form.ValidationTextBox"
 regExp="[\w]+"
 required="true"
 invalidMessage="Invalid project name."/></f:verbatim>
</td>
</tr>
<tr>
<td>Project description: </td>
<td><h:inputHidden value="#{projectFormBean.projectDescription}"/><f:verbatim> 
 <textarea dojoType="dijit.form.Textarea" style="width:80%">
     </textarea></f:verbatim>
</td>
</tr>

我们将原始JSF组件更改为inputHidden ,但仍与后端projectFormBean数据绑定。 在这个隐藏的组件之后,我们添加了相应的Dojo小部件。 对于“项目名称”字段,我们使用validationTextBox来验证客户端的输入框,对于“项目描述”字段,我们使用dojo textarea ,它可以自动扩展而无需滚动条。

步骤2.在页面渲染阶段将数据从JSF组件复制到Dojo小部件

之前,我们用页面中的Dojo小部件替换了JSF组件,但是页面中的数据未显示在Dojo小部件中。 接下来,我们将向您展示如何将数据从JSF组件复制到Dojo小部件。

在渲染阶段,我们使用JavaScript从JSF组件中提取数据并将其设置为相关的Dojo小部件。 清单4显示了JavaScript代码。

清单4.在渲染阶段将数据从JSF组件复制到Dojo小部件
<script type="text/javascript">   
   function dojoInit(){
        dijit.registry.byClass('dijit.form.ValidationTextBox').forEach(function(pane){
          pane.setValue(pane.domNode.previousSibling.value);
     });
     
     dijit.registry.byClass('dijit.form.Textarea').forEach(function(pane){
          pane.setValue(pane.domNode.previousSibling.value);
     });
   }
   
   dojo.addOnLoad(dojoInit);
</script>

dojoInit函数中,您将找到由类名查询的所有Dojo小部件。 对于每个窗口小部件,您都可以在Dom树(它是JSF组件)中找到其先前的同级节点。 然后,您从JSF组件中提取数据并将其设置为查询的Dojo小部件。 这样,您可以在JSF组件和Dojo小部件之间同步数据。 最后,您使用dojo.addOnLoad函数来确保在渲染阶段调用了dojoInit函数。

注意 :使用Dojo工具包时,应避免使用<body onload="...">window.onload因为Dojo具有使用window.onload自己的初始化机制。 您自己使用此机制将干扰Dojo的初始化例程。 Dojo提供了dojo.addOnLoad ,它使您可以在Dojo完成自己的初始化之后加载函数。

步骤3.在页面提交阶段将数据从Dojo小部件复制到JSF组件

当前,可以在页面中以正确的数据显示dojo小部件。 但是,如果用户更改了数据,这些更改如何反映到相应的后端Form bean? 在这一步中,我们展示了在页面提交阶段如何在Dojo小部件和JSF组件之间同步数据。

首先,您必须创建一个JavaScript函数以将数据从Dojo小部件复制到JSF组件。 代码如清单5所示。

清单5.将数据从Dojo小部件复制到JSF组件
function setDojoValue(){
     dijit.registry.byClass('dijit.form.ValidationTextBox').forEach(function(pane){
          pane.domNode.previousSibling.value = pane.getValue();
     });
     
     dijit.registry.byClass('dijit.form.Textarea').forEach(function(pane){
          pane.domNode.previousSibling.value = pane.getValue();
     });
}

此函数类似于第2步中显示的dojoInit函数。我们仍然使用dojo查询方法通过指定的类名查找所有dojo小部件。 然后,我们从这些Dojo小部件中提取数据并将其设置为相应的JSF组件。

接下来,我们必须在页面提交时调用setDojoValue函数,因此我们将更改原始的setDojoValue按钮,如清单6所示。

清单6.带有JavaScript函数的Submit按钮
<h:commandButton id="button_submit" action="success" 
    value="Submit" type="submit" onclick="setDojoValue();"></h:commandButton>

我们在JSF commandButton添加onclick属性,因此当用户单击此按钮时,将首先调用JavaScript函数,然后提交页面。 这样,我们可以在提交页面之前将Dojo小部件中的所有数据复制到JSF组件,并且数据更改将反映到后端Form Bean。

这就是使用此方法所需要做的。 图3显示了新的Create Project页面。

图3.使用方法1创建项目
使用方法1完成的Create项目的屏幕截图

如您所见,我们使用一个经过验证的输入框来支持客户端验证。 我们还使用了dojo textarea ,它可以在没有滚动条的情况下自动扩展。

方法2:构建定制的JSF组件以启用Dojo小部件

JSF是功能强大的Web框架。 它不仅为Web应用程序提供了标准的用户界面组件,而且还是允许用户自定义的非常灵活的API。 在本节中,我们将说明如何结合Dojo风格开发自己的JSF组件。

通常,JSF组件将包含以下部分:

  • UIComponent类:从UIComponentBase或其他现有JSF组件(例如outputText派生的类。 此类表示整个JSF组件的核心逻辑。
  • 渲染类:此类用于渲染组件。 通常,它将处理如何生成用于渲染HTML代码,因此对于本节至关重要。 我们需要更改此类,并使其生成Dojo样式HTML代码。
  • UI组件标签类:这是一个JSP标签处理程序类,它使UI组件可以在JSP页面中使用。 它还可以将单独的呈现类与UIComponent类相关联。
  • 标记库描述符文件:这是标准的JavaEE JSP标记库描述符(tld)文件,该文件将标记处理程序类与JSP页面中的可用标记相关联。

我们将继续以创建项目场景为例,并且将展示如何创建具有dojo验证功能的输入文本JSF组件。

首先,看一下定制的JSF标记。 清单7显示了如何在Web应用程序中使用定制的JSF标记:

清单7.使用定制的JSF标记
<h:form id="project">
<table>
<tbody>
     <tr>
     <td>Project Name:</td>
     <td>
     <jsfdojo:input id="projectName" type="text" 
     invalidMessage="Invalid project name." 
     dojoType="dijit.form.ValidationTextBox" 
     dojoRequired="true" 
     regExp="[\w]+" 
     value="#{projectFormBean.projectName}"/>
     </td>
     </tr>

图4显示了使用这种方法的网页。 (您还可以查看图4的图。)

图4.创建项目-方法2
该屏幕快照显示了使用方法2创建项目页面

要开发具有Dojo风格的自己的JSF输入框,可以使用现有的JSF输入框作为指南,因此不需要实现自己的UIComponent类。 您可以重用现有的。 您确实需要实现render和tag类,但这并不是很困难。 您可以继承现有的JSF API,只需重写一些功能即可。

清单8显示了用于在JSP页面中处理标签的标签类的代码。 它还将UIComponent和Render类相关联。

清单8.标签类
public class InputTag extends InputTextTag {

    @Override
    public String getComponentType() {
        return "javax.faces.HtmlInputText";
    }

    @Override
    public String getRendererType() {
        return "jsfdojo.input.render";
    }

    private String dojoType;

    private String invalidMessage;

    private String regExp;

    private String type;
    
    private String dojoRequired;

    public String getDojoRequired() {
        return dojoRequired;
    }

    public void setDojoRequired(String dojoRequired) {
        this.dojoRequired = dojoRequired;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getRegExp() {
        return regExp;
    }

    public void setRegExp(String regExp) {
        this.regExp = regExp;
    }

    public String getDojoType() {
        return dojoType;
    }

    public void setDojoType(String dojoType) {
        this.dojoType = dojoType;
    }

    public String getInvalidMessage() {
        return invalidMessage;
    }

    public void setInvalidMessage(String invalidMessage) {
        this.invalidMessage = invalidMessage;
    }

    @Override
    protected void setProperties(UIComponent component) {
        super.setProperties(component);
  
        component.getAttributes().put("dojoType", dojoType);
        component.getAttributes().put("dojoRequired", dojoRequired);
        component.getAttributes().put("invalidMessage", invalidMessage);
        component.getAttributes().put("regExp", regExp);
        component.getAttributes().put("type", type);
    }

}

标签类从InputTextTag继承。 您需要重写某些功能,并为此标签中使用的新属性添加一些新字段。

getComponentType函数指定UIComponent类,而getRendererType函数指定Render类。 因此,如果JSF组件已经分离了render类,则在标记类中,这两个函数用于将它们链接在一起。

标记类中的字段表示JSP标记中使用的属性。 setProperties函数用于将这些属性存储在此组件的属性映射中。 该地图将在render类中使用。

如上所述,我们将实现一个单独的渲染类。 此类负责生成HTML代码以在网页中呈现。 清单9显示了此render类的代码。

清单9.分离的渲染类
public class InputRender extends TextRenderer {

    @Override
    public void encodeEnd(FacesContext context, UIComponent component) 
     throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("input", component);
        String id = (String) component.getClientId(context);
        writer.writeAttribute("id", id, "id");
        writer.writeAttribute("name", id, "id");
        writer.writeAttribute("value", getValue(component), "value");
        
        writer.writeAttribute("type", (String) 
     component.getAttributes().get("type"), null);
writer.writeAttribute("dojoType", (String) 
     component.getAttributes().get("dojoType"), null);
writer.writeAttribute("required", (String) 
     component.getAttributes().get("dojoRequired"), null);
writer.writeAttribute("invalidMessage", (String) 
     component.getAttributes().get("invalidMessage"), null);
writer.writeAttribute("regExp", (String) component.getAttributes().get("regExp"), null);
        
        writer.endElement("input");
    }

    protected Object getValue(UIComponent component) {
        Object value = null;
        if (component instanceof UIInput) {
            value = ((UIInput) component).getSubmittedValue();
        }
        if (null == value && component instanceof ValueHolder) {
            value = ((ValueHolder) component).getValue();
        }
        if (value == null) {
            value = "";
        }
        return value;
    }
}

标记类继承自TextRenderer ,因此您无需担心解码问题。 您所需要做的就是实现编码输出,该输出由encodeEnd函数实现。 在此功能中, ResponseWrite对象使生成HTML代码变得容易。 对于诸如typedojoTyperequiredinvalidMessageregExp type的新添加属性,这些属性的值是从组件的属性映射中检索的,该属性映射在标记类中设置。

getValue函数中实现的UIComponent检索value属性的value

在实现标记和渲染类之后,还需要为此JSF组件定义标记库描述符文件(tld文件)。 清单10显示了此tld文件的内容。

清单10.标签库描述符文件– tld文件
<taglib>
     <tlib-version>1.0</tlib-version>
     <jsp-version>1.2</jsp-version>
     <short-name>jsfdojo</short-name>
     <uri>http://jsfdojo.ibm.com</uri>

     <tag>
        <name>input</name>
        <tag-class>jsf.input.InputTag</tag-class>
        <body-content>empty</body-content>
        <description>
            
        </description>
        <attribute>
            <name>dojoType</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                
            </description>
        </attribute>
        <attribute>
            <name>dojoRequired</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                
            </description>
        </attribute>
        <attribute>
            <name>type</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                
            </description>
        </attribute>
        <attribute>
            <name>invalidMessage</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                
            </description>
        </attribute>
         <attribute>
            <name>regExp</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                
            </description>
        </attribute>
        <attribute>
            <name>value</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <description>
                Value reference expression pointing the attribute that
                will have the credit card number.
            </description>
        </attribute>
        ……
    </tag>
</taglib>

在此tld文件中,“标签类别”字段指定已实现的标签类别。 它还描述了将在此标记中使用的属性。 在这种情况下,我们添加了几个新属性: dojoTypedojoRequiredtypeinvalidMessageregExp 。 还有许多超类属性,例如idvalue等。

最后,您需要在faces-config.xml文件中注册新组件。 清单11显示了此组件的register部分。

清单11.在faces-config.xml中注册JSF组件
<render-kit>
<renderer>
        <description>
            Renderer customized input with dojo style
        </description>
        <component-family>javax.faces.Input</component-family>
        <renderer-type>jsfdojo.input.render</renderer-type>
        <renderer-class>
             jsf.input.InputRender
         </renderer-class>
      </renderer>
   </render-kit>

组件族和渲染器类型字段与标​​记类中的函数完全映射。 清单12显示了这些功能。

清单12.覆盖组件和渲染器字段
@Override
public String getComponentType() {
return "javax.faces.HtmlInputText";
}

@Override
public String getRendererType() {
return "jsfdojo.input.render";
}

这是实现自己的JSF组件所需要做的全部工作。 它涉及几个不同的类和xml实现,但是它非常简单且不复杂,尤其是在基于现有组件的情况下。 在这种情况下,我们只需添加一些新属性并覆盖编码功能即可生成Dojo HTML代码。

方法3:惰性注入(将JSF组件后解析到Dojo小部件中)

这种方法是使用JavaScript在客户端完全执行的,但是与本文中的第一种方法完全不同。 惰性注入意味着在整个页面加载之后将Dojo小部件信息注入到JSF组件中。 然后,使用Dojo解析器来解析JSF组件并将其转换为Dojo小部件。 在注入过程中,可能会注册一个处理程序,稍后将在提交JSF表单时调用该处理程序。 这样,可以将精确的数据传送回服务器端的相应JSF侦听器。 图5显示了此方法的详细工作流程。 (您还可以查看图5的大图。)

图5.惰性注入方法的工作流程
该图显示了惰性注入方法的过程

步骤1:将Dojo小部件信息注入JSF组件。

您可能已经注意到,在整个页面加载完成之后,JSF组件已转换为HTML标记。 例如,清单13是JSF inputText组件的语法。 加载页面之后,将inputText组件转换为HTML标记,如清单14所示。

清单13. JSF inputText组件的语法
<td>
     <h:inputText id="projectName" value="#{projectFormBean.projectName}" size="5"/>
</td>
清单14.为JSF inputText组件生成HTML标记
<td>
     <input type="text" name="project:projectName" id="project:projectName" size="5"/>
</td>

因此,这个想法很简单。 将必要的窗口小部件信息添加到生成HTML标记中,以便Dojo解析器可以识别并将其解析为Dojo窗口小部件。 另外,为了区分普通HTML标记和从JSF组件生成的标记,在JSF组件的包装器节点上标记了特殊属性jsf2dojo='true' 。 清单15显示了针对Create Project示例的更新后的JSF页面。 您可以在NewProject_lazy_inject.jsp文件中查看更多详细信息。

清单15.使用jsf2dojo ='true'属性更新的JSF页面
<tr>
     <td jsf2dojo='true'>
          <h:inputText id="projectName" value="#{projectFormBean.projectName}" 
          size="5"/>
     </td>
</tr>
<tr>
     <td jsf2dojo='true'>
     <h:inputTextarea id="projectDescription" 
     value="#{projectFormBean.projectDescription}" rows="2" cols="15"/>
     </td>
</tr>

这样,我们可以在页面中标记部分JSF组件,并将它们转换为Dojo小部件。 其他JSF组件将保持不变。 请注意,将jsf2dojo='true'属性添加到包装器节点而不是JSF组件本身,因为否则,JSF编译器会将其视为带有编译错误的无效属性。

步骤2:将注入的JSF组件解析到Dojo小部件中

Dojo注入完成后,下一步是将JSF组件解析为Dojo小部件。 Dojo解析器是所有小部件最重要的基础。 默认情况下,页面加载后,Dojo解析器会扫描整个页面以查找带有Dojo标记的标签(例如dojoType='xxx' )并将其解析为小部件。 Dojo解析器的另一种用法是动态地解析标签,或者,正如我们所说的, 延迟解析 。 这是我们的方法。

所有解析逻辑都封装在jsf2dojo.js文件中,因此第一步是将其包含在JSF页面中,如清单16所示。

清单16.导入jsf2dojo.js
<script type="text/javascript" src="script/jsf2dojo.js"></script>

接下来,将所有解析步骤添加到jsf2dojo.js。 第一步是小部件声明,如清单17所示。

清单17.窗口小部件类声明和页面onload处理程序
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.Textarea");
dojo.require("dojo.parser");

var TYPE_MAP = {
     text      : 'dijit.form.ValidationTextBox',
     textarea : 'dijit.form.Textarea'
};

dojo.addOnLoad(init);

小部件类是为“创建项目”示例声明的。 在这里,使用了Dojo ValidationTextBoxTextarea小部件。 还包括Dojo解析器。 TYPE_MAP常量定义了我们稍后将使用的类映射。 dojo.addOnLoad(init)函数注册一个回调函数,该函数将在整个页面加载完毕且Dojo完成初始化之后被调用。

清单18显示了函数init的内容。

清单18.将JSF组件解析为Dojo小部件
function init(){          
     var jsfContainerList = dojo.query("[jsf2dojo='true']");     

     for(var i = 0 ; i < jsfContainerList.length; i++){
          var jsfWidget = _getJsfWidget(jsfContainerList[i]);//get JSF component node
          if(!jsfWidget) continue;     
               
          if('input' == jsfWidget.tagName.toLowerCase() 
          && 'text' == jsfWidget.type.toLowerCase()){ // input 
               jsfWidget.setAttribute('dojoType',
                    TYPE_MAP[jsfWidget.type.toLowerCase()]);
               jsfWidget.setAttribute('promptMessage',
                    "Please Enter your information");
               jsfWidget.setAttribute('required',"true");                    
               
          }else{
               jsfWidget.setAttribute('dojoType', 
                    TYPE_MAP[jsfWidget.tagName.toLowerCase()]);
          }
          dojo.parser.parse(jsfContainerList[i]);//parse wrapper node
       }
}

init函数包含所有解析逻辑。 首先使用dojo.query("[jsf2dojo='true']")获取包含我们先前定义的JSF组件的所有包装器( <td> )。 然后, _getJsfWidget()用于获取从JSF组件生成的确切HTML标记。 对于JSF inputText组件,我们添加了dojoType=' dijit.form.ValidationTextBox'和其他特定属性,包括提示消息以及该属性是否为必需。 对于JSF inputTextarea组件,我们添加了dojoType=' dijit.form.Textarea' 。 因为一切准备就绪, dojo.parser.parse()调用dojo.parser.parse()生成Dojo小部件。 这里,JSF组件的包装器节点(<td>)用于解析。

步骤3:验证页面

您可以通过访问http:// [服务器ip]:[服务器端口] /JSFSampleEarWeb/faces/NewProject_lazy_inject.jsp来验证结果。 您应该在页面上看到Dojo小部件,如图6所示。

图6.创建项目-方法3
使用方法3创建项目页面的屏幕截图

单击提交之后,项目名称和描述字段将传输到服务器端的JSF侦听器,并显示在另一个名为Project_result.jsp的JSF页面上。

进阶主题

您可能已经注意到,上面列出的步骤仅处理JSF组件与Dojo小部件具有紧密映射的简单情况。 如果映射不是那么简单怎么办? 如前所述,需要一些额外的技巧。

首先,我们将向页面添加更多的JSF组件,如清单19所示。

清单19.添加了更多组件的JSF页面
<tr>
     <td jsf2dojo='true'>
          <h:selectOneMenu id="projectOption" value="location">
          <f:selectItem id="select1" itemValue="Shanghai" itemLabel="Shanghai"/>
          <f:selectItem id="select2" itemValue="London" itemLabel="London"/>
          <f:selectItem id="select3" itemValue="New York" itemLabel="New York"/>
          </h:selectOneMenu>
     </td>
</tr>
<tr>
     <td jsf2dojo='true' jsfType='radio'>
          <h:selectOneRadio id="newPrjRadio" value="NYPrj">
                 <f:selectItem id="rd1" itemLabel="Yes" itemValue="y" />
          <f:selectItem id="rd2" itemLabel="No" itemValue="n" />
          </h:selectOneRadio>
     </td>
</tr>
<tr>
     <td jsf2dojo='true'>
          <h:selectBooleanCheckbox id="ck1" value="manager" />Project Manager
          <h:selectBooleanCheckbox id="ck2" value="technical leader"/>Techinal Leader
          <h:selectBooleanCheckbox id="ck3" value="member" /> Developer&Tester
     </td>
</tr>
<tr>
     <td jsf2dojo='true'>
          <h:commandButton id="btnSubmit" action="success" value="Submit"
           type="submit"></h:commandButton>
     </td>
     <td><input id='btnSubmit_mock' type='text' style='display:none'/></td>
</tr>

在这里,为JSF selectOneRadio组件添加了新属性jsfType='radio' ,并且还为JSF commandButton组件添加了隐藏的输入文本。 这些属性稍后在解析过程中使用。 有关更新页面的更多详细信息,请参考NewProject_lazy_inject_advanced.jsp文件。

接下来,您将解析新的JSF组件。

在某些情况下,将JSF组件转换为Dojo小部件后,HTML源将变得完全不同。 例如,清单20显示了JSF selectOneMenu组件HTML源,清单21显示了selectOneMenu被转换为Dojo ComboBox小部件之后的源。

清单20. JSF selectOneMenu组件HTML源
<select id="project:projectOption" size="1" name="project:projectOption">
     <option value="Shanghai">Shanghai</option>
     <option value="London">London</option>
     <option value="New York">New York</option>
</select>
清单21. Dojo ComboBox小部件HTML源
<div id="widget_project:projectOption" class="dijit ..." value="Shanghai" 
     widgetid="project:projectOption" ...>
     <div style="overflow: hidden;">
               ...
          <div class="dijitReset dijitInputField">
               <input id="project:projectOption" class="dijitReset" type="text"/>
          </div>
     </div>
</div>

为了使这些差异对服务器端的JSF侦听器透明,在提交JSF表单时将注册并调用一个处理程序。 清单22显示了将更多JSF组件解析为Dojo小部件的更新逻辑。

清单22.将更多的JSF组件解析为Dojo小部件
for(var n = 0; n < jsfWidgets.length; n++){
     var jsfWidget = jsfWidgets[n];
     
     if ('select' == jsfWidget.tagName.toLowerCase()){
          jsfWidget.setAttribute(DOJO_TYPE, 
               TYPE_MAP[jsfWidget.tagName.toLowerCase()]);
          mockFunc = _mockSelect;
          
     }else if('textarea' == jsfWidget.tagName.toLowerCase()){
          jsfWidget.setAttribute(DOJO_TYPE, 
               TYPE_MAP[jsfWidget.tagName.toLowerCase()]);
          
     }else if('input' == jsfWidget.tagName.toLowerCase()){
          var type = jsfWidget.type.toLowerCase();
          
          if('submit' == type){
               var params = {label: jsfWidget.value};
               var dojoWidget = new dijit.form.Button(params, jsfWidget);
               dojo.connect(dojoWidget, 'onClick', window, 'formSubmit');
               mockFunc = _mockSubmitInput;

          }else if('text' == type){
               jsfWidget.setAttribute(DOJO_TYPE, TYPE_MAP[type]);
               jsfWidget.setAttribute('promptMessage',
                    "Please Enter your information");
               jsfWidget.setAttribute('required',"true");                    
          
          }else if ('checkbox' == type || 'radio' == type){     
               jsfWidget.setAttribute(DOJO_TYPE, TYPE_MAP[type]);
          }
     }
     if(!dojoWidget){
          dojoWidget = dojo.parser.parse(jsfList[j])[0];//parse wrapper node
     }     
     if(dojoWidget && mockFunc){
          mockFuncMap.push({'dojoWidget': dojoWidget, 'mockFunc': mockFunc});
     }
}

回调处理程序_mockSelect_ mockSubmitInput已为JSF selectOneMenu和commandButton注册。 如清单23所示,这些处理程序将数据绑定到相应的字段,以确保表单信息在HTTPRequest保持相同。 这样,服务器端的JSF侦听器不会意识到任何更改。 请注意,Dojo Button是专门为commandButton创建的。

清单23. JSF selectOneMenu的示例回调处理程序
Function _mockSelect(dojoWidget){
     var mockedSelect = dojo.byId(dojoWidget.id);
     mockedSelect.value = (dojoWidget.item) ? dojoWidget.item.value : 
          dojoWidget.store.root.value;
}

基本上,所有回调处理程序都有两个步骤:首先找到相应的字段,然后添加必要的值。 如清单22所示,通过使用dojo.connect(dojoWidget, 'onClick', window, 'formSubmit')函数,在提交JSF表单时将调用formSubmit 。 清单24显示了formSubmit的详细信息。

清单24.在提交JSF表单之前调用formSubmit函数。
function formSubmit(event){
        for(var i = 0 ; i < mockFuncMap.length; i++){     
          mockFuncMap[i]['mockFunc']( mockFuncMap[i]['dojoWidget'] );        
     }
     event.target.form.submit(); //event.target - submit button
}

formSubmit唯一要做的就是调用所有已注册的回调处理程序,以便表单信息正确。 一切对服务器端的JSF侦听器都是透明的。

现在,通过访问http:// [服务器ip]:[服务器端口] /JSFSampleEarWeb/faces/NewProject_lazy_inject_advanced.jsp来验证结果。 您将看到所有JSF组件现在都已转换为Dojo小部件,如图7所示。

图7.创建带有更多小部件的项目-方法3
使用方法3创建具有更多小部件的项目的屏幕快照

比较方式

在前面的部分中,我们列出了将JSF应用程序与Dojo结合起来的三种方法。 每种方法都有其优点和缺点。 本节从以下方面比较这三种方法:

  • 复杂性-实施起来容易还是困难? 它需要修改许多文件还是需要修改配置文件?
  • 适用性-是否适用于所有JSF组件? 有什么限制吗?
  • 可重用性-是否易于重用? 是否有可能成为可以直接由其他项目使用的独立组件?

表1显示了这三种方法的比较。

表1.这三种方法的比较
方法 复杂 适用性 可重用性
方法1 1个 2 2
方法2 3 3 3
方法3 2 3 2

注意 :我们只使用1到3之间的数字来表示各个方面的程度。 1表示最低级别,而3表示最高级别。

从该表中可以看出,方法1是最容易实现的方法,但有其局限性。 这种方法不适用于每个JSF组件,例如Checkbox 。 因此,方法1是将某些JSF组件( input boxtextarea等)快速转换为Dojo小部件的好方法。

方法2稍微复杂一点,因为构建自己的JSF组件不是很简单。 但是这种方法适用于许多JSF组件,并且非常易于重用。 带有Dojo的JSF组件可以被其他项目直接使用。 因此,方法2是企业开发的不错选择,因为许多项目可能具有相同的要求。

方法3是中级。 它不像方法2那样复杂,并且适用于许多JSF组件,但是重用并不是很容易。 它需要有关Dojo小部件框架的更多知识。 因此,此方法适用于单个项目的开发。 如果只有一个项目需要Dojo的JSF组件,并且您不想花费很多时间来实现它,那么方法3是您的最佳选择。

结论

集成JSF和Dojo非常有用。 它利用JSF的服务器端功能和Dojo的强大小部件,使您可以轻松构建具有更好用户体验的Web应用程序。 本文提供了三种使用Dojo修改JSF应用程序的方法。 每种方法都有其优点和缺点,因此您可以选择最适合您的项目要求的方法。


翻译自: https://www.ibm.com/developerworks/web/library/wa-aj-jsfdojo/index.html

java创建 jsf项目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值