dwr和jsf的区别_使用JSF / DWR / DOJO创建动态Web应用程序

dwr和jsf的区别

抽象

本文提供了一种方法,该方法介绍如何将JSF,DWR,DOJO集成在一起以创建使用Portlet和Facelets的富Web应用程序。 假定读者对这些框架及其提供的功能有基本的了解。

样品申请

本文讨论的示例应用程序是产品管理应用程序。 该应用程序为其用户提供以下功能:

  1. 用户可以根据名称搜索产品类型
  2. 当用户选择产品时,将使用拆分窗格向用户显示一个新屏幕。 拆分窗格的左侧以树的形式(如您在Windows资源管理器中看到的)显示了属于该产品类型的所有产品子类型。 每个产品子类型可能都有自己的子类型。 窗格的右侧显示带有标签的选项卡式窗格:
  • 产品 -此选项卡显示属于所选子类型的产品列表
  • 添加产品子类型 -此选项卡显示一个表单,该表单接受用于将新产品子类型添加到所选产品子类型的值
  • 在拆分窗格的底部,提供了一个后退按钮,可返回到搜索产品类型页面。
  • 当与子类型关联的产品列表显示在拆分窗格的右侧时,则它应该在单个页面上仅显示10个产品。 这意味着应该可以在屏幕上进行分页和结果排序。
  • 拆分窗格左侧显示的树应该是可扩展/可折叠的,并且不应导致页面刷新,从而增强用户体验。
  • 右键单击树中的任何节点(代表产品子类型),应向用户显示一个弹出菜单,其中包含以下选项:将新产品子类型添加为选定子类型的子级,删除选定产品子类型,刷新子产品子类型的列表所选产品子类型的信息,以及来自数据库等的最新数据
  • 将新产品子类型添加到选定产品子类型后,新产品子类型应立即显示在树中,而无需刷新页面。
  • 图1显示了当用户选择产品类型/子类型时预期屏幕的外观。

    图1.产品子类型详细信息屏幕

    道场

    创建跨浏览器兼容的树结构,选项卡式窗格,拆分窗格,弹出菜单等非常耗时,同时最好由经验丰富的Javascript / DHTML程序员来完成。 有许多工具箱提供了这些UI窗口小部件,并且它们是跨浏览器兼容的,但是没有多少工具箱提供了丰富的事件处理模型。 下面列出了示例应用程序需要响应才能满足用户要求的一些用户操作:

    用户动作 应用响应
    选择一个树节点 显示属于此节点的产品子类型的列表
    右键单击树节点 显示带有用于添加子产品子类型,删除所选产品子类型等的选项的弹出菜单
    在选项卡式窗格中选择“ 添加产品子类型 ”选项卡 显示表单以输入新产品子类型信息
    当用户单击[+]符号以展开树并查看子节点时 从数据库加载子节点信息并显示在树中

    DOJO工具箱是Javascript / DHTML工具箱,它提供了丰富的UI小部件集(包括但不限于树,选项卡式窗格,弹出菜单)以及丰富的事件处理模型,使其适合在示例应用程序中使用。

    DWR

    DWR(直接Web远程处理)是一个AJAX框架,它简化了用Java构建AJAX应用程序的过程。 DWR提供了许多功能,包括但不限于:

    • 从Java类创建Javscript(开发人员创建以处理AJAX请求)
    • 允许JSF托管bean充当处理AJAX请求的Java类
    • 使用转换器将Javascript关联数组转换为Java Bean,反之亦然
    • 使用转换器将Javascript数组转换为Java集合,反之亦然

    DWR中的转换器起着非常重要的作用,并提供了更简洁的编程模型。 例如,如果用户输入新产品子类型信息并请求应用程序将其保存,则有两种方法可以在Web层中检索此信息:

    • 使用HttpServletRequest的getParameter方法检索有关新产品子类型的所有信息。
    • 创建一个DTO ProductSubtype,它具有产品子类型的所有属性的getter和setter方法。 在dwr.xml文件中配置一个转换器,该文件将ProductSubtype指定为Bean转换器。 在Javascript中,只需创建一个关联数组并将其传递给接受ProductSubtype作为参数的Java类(用于处理AJAX请求)。 在这种情况下,DWR将执行从Javascript关联数组到ProductSubtype的转换,因为在DWR中声明了ProductSubtype使用bean转换器。

    后面的选项提供了更简洁的编程模型,您不必处理检索请求参数和创建要在Java程序中使用的DTO的问题。

    处理AJAX请求时,通常需要在Java回调方法中接收状态代码,消息或某些数据,以决定向用户显示还是不显示。 在这种情况下,bean转换器非常方便。

    DOJO的丰富事件模型与DWR的干净方法(用于处理Java应用程序中的AJAX请求)相结合,提供了一种创建高度交互性的Web应用程序(如示例应用程序)的方法,其中DOJO组件生成的事件被传递给DWR进行处理。

    问题描述

    1. 在Portal环境中,开发人员不负责为用户界面生成HTML,该HTML是通过解析与Facelets对应的XHTML文件生成的。 即使JSF托管bean的属性包含HTML字符串作为其值,Portal也不会对其进行解析,并且会在用户界面上按原样显示给用户。 如何生成可以由Web浏览器执行以创建UI小部件的DOJO特定HTML?
    2. DOJO提供了丰富的事件模型,可以用Javascript拦截这些事件。 DWR框架可用于在服务器端接收这些事件,但是在服务器端需要保持会话状态的地方?
    3. 当Tree中的节点数超过数百时,Javascript需要花费时间在IE或Mozilla中创建DOJO树节点。 那是否意味着如果节点数量超过数百个,应用程序就无法在浏览器中使用DOJO树小部件?
    4. 在Web应用程序中使用AJAX时,如何在屏幕上发生用户事件时生成HTML或HTML片段? 应该用Java代码编码还是从外部文件中选取? 应用程序可以响应AJAX请求显示复杂的用户界面吗?
    5. 使用AJAX时,代码可能会因HttpServletRequest的getParameter(“ fieldName”)方法而变得混乱,因此无法轻松维护

    解决方法

    定制JSF组件

    自定义JSF组件用于为DOJO的Tree和Split Container组件生成必要HTML。 JSF组件生成HTML始终由浏览器解析,并且门户网站不将其输出为文本。 XHTML文件的以下部分显示了如何使用定制JSF组件来生成DOJO的树形和选项卡式窗格小部件。

    <div xmlns="http://www.w3.org/1999/xhtml"
    ...
    ...
    xmlns:dojo="http://dojotoolkit.org/"
    xmlns:mytree="http://mytree.com/tree"
    xmlns:mytab="http://mypane.com/tabPane">
    <ui:composition>
    <ui:define name="body">
    <f:view>
    <h:form styleClass="form" id="formId">
    <div dojoType="SplitContainer" orientation="horizontal" sizerWidth="5" activeSizing="false" style="overflow:
    auto; whitespace: nowrap; height: 550px; background: transparent; padding: 5px;" >
    <div dojoType="ContentPane" sizeShare="20"
    style="overflow: auto; whitespace: nowrap;">
    <mytree:treeComponent backingBeanName="treeBackingBean"></mytree:treeComponent>
    </div>
    <div dojoType="ContentPane" sizeShare="80" style="overflow: auto; white-space nowrap;">
    <mytab:tabPaneComponent/>
    </div>
    </div>
    ...
    ...

    如果树节点的数量很大(超过200个),那么定制JSF组件不得为200个以上的节点生成代码。 如果节点数超过200,则表明IE在加载页面时会花费大量时间来创建这些小部件。 该示例应用程序的自定义JSF组件仅创建了100个树节点(在根级别),并在最后显示了“ Show more ...”选项。 当用户选择“显示更多..”选项时,DWR就有责任从数据库中获取有关剩余节点的信息。 然后将此信息传递给Javascript回调方法,以编程方式创建TreeNode小部件。

    MyFaces还提供了生成DOJO树的组件,但是MyFaces组件可以一次性创建所有节点,这不是一个好方法,因为当树形节点数达到数千时,该组件在Web应用程序中变得无用。

    DWR和JSF

    DWR要求您创建Java类并在dwr.xml配置文件中配置该类。 DWR使用在dwr.xml中配置的名称创建一个Javascript文件(.js文件扩展名)。

    dwr.xml中的以下配置信息显示了如何配置Java类:

    <create creator="jsf" javascript="AjaxBean" scope="request">
    <param name="managedBeanName" value="ajaxBean" />
    <param name="class"
    value="com.somebean.AjaxBean" />
    </create>
    creator="jsf"

    这意味着将Java类配置为JSF托管Bean。 该Java类将包含将由Javascript调用的所有AJAX方法。

    <param name="managedBeanName" value="ajaxBean" />

    这意味着,faces-config.xml配置文件中的托管Bean的名称为ajaxBean。

    <param name="class"
    value="com. somebean.AjaxBean" />

    这是指实际的Java类。

    javascript="AjaxBean"

    这是Javascript代码引用Java类的名称。

    要在Javascript代码中使用AjaxBean,需要使用<script>标记导入此Javascript。

    DWR Java类(DWR Java类只不过是普通Java类。这些类未实现任何DWR特定的接口或类。)每当接收到AJAX请求时都会实例化。 这意味着,如果应用程序必须维护AjaxBean类中的状态,则在收到新请求时它将被擦除。 预期AjaxBean中的方法本质上是无状态的,并且会话状态必须保持在其他位置。

    AJAX请求不是PortletRequest,这意味着DWR Java类无法访问PortletSession对象。 AJAX请求是简单的HTTP请求,因此,DWR Java类可以访问HttpSession对象。 根据门户规范,要求HttpSession和PortletSession对象应该同步,即,如果将属性添加到PortletSession对象,则还应该将其添加到HttpSession对象(不一定具有相同的名称)。

    例如,对于JBoss AS,当将具有名称为someManagedBean的托管bean添加到PortalSession时,则可以通过HttpSession使用属性名称为javax.portlet.p。<portletInstanceName>?someManagedBean的相同对象。

    在示例应用程序中,会话状态在someManagedBean中维护。 DWR Java类从HttpSession对象获取someManagedBean的实例,并设置其属性以反映用户当前的对话状态。

    为了访问业务服务(在Spring层中可以说),AjaxBean可以利用Service Locator模式与业务服务进行交互。

    注意 :仅在收到面Kong请求后才实例化JSF托管bean。 因此,请确保您将用于存储会话状态的JSF托管Bean已收到面Kong请求。 此托管bean的范围应为“会话”。

    HTML模板

    使用AJAX面临的问题之一是根据用户操作创建复杂HTML片段。 这通常会导致应用程序维护需求大,有时随着一段时间内对应用程序需求的细化,甚至很难更改用户界面。 HTML没有拼贴的概念,但是可以在示例应用程序中完成与拼贴类似的操作。

    <table style="height: 80%; width: 100%; padding-bottom: 100px; visibility: {0};">
    <tr valign="top">
    <td>
    <table align="left" valign="top">
    <tr>
    <td class="formLabel">Product Category:</td>
    <td class="formField">{1}</td>
    </tr>
    <tr>
    <td class="formLabel"><span class="required">*</span>Description:</td>
    <td class="formField"><textarea rows="2" id="desc_field" cols="80"
    name="desc_field"></textarea></td>
    </tr>
    <table>
    <tr>
    <td>{dataTable}</td>
    </tr>
    <tr>
    <td>{dataScroller}</td>
    </tr>
    </table>
    <tr valign="bottom">
    <td align="right" style="padding-right: 50px;">
    <table>
    <tr>
    <td><input type="button" class="inputButton" onclick="saveDetails('{2}');" value="Save"/></td>
    </tr>
    </table>
    </td>
    </tr>
    ...
    ...

    上面HTML模板文件显示了两种类型的占位符:

    1. 数据占位符
    2. HTML占位符

    placholder {0},{1}和{2}代表数据占位符,可以通过使用如下静态方法轻松填充:

    public static String getStringWithValues(String template, Object[] values) throws IncorrectNumberOfValues {
    for ( int i = 0; i < values.length; i++) {
    int index = template.indexOf("{" + i + "}");
    if (index == -1) {
    throw new IncorrectNumberOfValues("The number of values passed is : " + values.length + "
    which doens't match the number of placeholders in : " + template);
    } else {
    if (values[i] != null ) {
    template = StringUtils.replace(template, "{" + i + "}", values[i].toString());
    } else {
    template = StringUtils.replace(template, "{" + i + "}", "");
    }
    }
    }
    return template;
    }

    其中, template是需要解析的html模板,并使用values数组中的值删除了占位符。 因此,数据占位符{0}被values数组中的第一个元素删除,数据占位符{1}被values数组中的第二个元素删除,依此类推。

    placholders {dataTable}和{dataScroller}表示HTML占位符,应替换为HTML片段。 {dataTable} placholder应该替换为一个数据表,该数据表显示与属于产品类别的每个产品相对应的记录。 与{dataTable}对应HTML在另一个HTML模板中。 有两种方法可以用相应HTML模板替换HTML占位符:

    1. 以编程方式:在Ajax bean中,可以用HTML替换占位符。 这种方法不需要创建任何类型的框架。
    2. 在属性文件或XML文档中的占位符和HTML模板之间创建映射。 例如,可以创建一个属性文件以包含以下映射:{dataTable} = /WEB-INF/classes/templates/dataTableTemplate.html {dataScroller} = /WEB-INF/classes/templates/dataScroller.html

    在运行时,可以将这些占位符替换为相应的模板。 这种方法需要创建一个小的框架,该框架读取属性文件并解析HTML模板,以用相应HTML文件替换HTML占位符。

    DWR bean转换器

    Web应用程序通常使用DTO将信息从Web层传递到服务层。 该示例应用程序使用另一级别的DTO,这些DTO将信息从Javascript传递到Web层。 例如,当搜索产品时,用户可以输入以下信息:产品名称,产品代码,产品ID以及相应的搜索类型(LIKE或EQUALS)。 这些参数使用DTO传递到示例应用程序的Web层。 Javascript中的关联数组(即命名数组)的概念用于设置这些参数,然后DWR执行从这些关联数组到相应DTO的转换。 关联数组中的名称必须与DTO中的属性匹配。

    dwr.xml中的以下配置显示了如何配置DTO:

    <convert match="com.search.product.SearchCriteria" converter="bean"/>

    这种方法的使用使服务器端的Java代码更整洁,因为您不再需要显式获取与AJAX请求随附的每个请求参数相对应的值。

    JSF的呈现属性

    所有JSF HTML标记都有一个rendered属性,该属性的布尔值决定是否将HTML窗口小部件显示给用户。 使用HTML模板时,可以实现相同的功能。 这将需要创建一个表达式框架,该框架可以解析HTML中的表达式并显示/隐藏HTML片段。

    <exp:if value="someManagedBean.permissions.save">
    <td><input type="button" class="inputButton" onclick="removeProduct('{0}');" value="Remove" /></td>
    </exp:if>

    FacesRequest或HttpServletRequest进行导航

    当用户单击产品详细信息页面上的后退按钮时,则需要显示产品搜索页面。 如果单击后退按钮是使用AJAX请求处理的,则该应用程序不会利用Faces-config.xml文件中定义的导航规则。 因此,最好在产品详细信息页面上使用JSFHTML按钮组件,而不是使用向服务器发送HttpServletRequest(或AJAX请求)HTML按钮来导航到另一个页面。

    考虑的替代方案

    Ajax4jsf

    Ajax4jsf提供了让JSF组件使用AJAX的方法,但是Portlet支持随版本1.1.1一起提供。 在创建示例应用程序时,ajax4jsf不支持Portlet。

    基于HTML和CSS的树

    可以结合使用<li> HTML元素和CSS来创建树结构。 但是这些树结构缺少任何类型的事件处理模型,因此无法满足高度交互的树小部件的要求。

    RichFaces

    RichFaces提供具有AJAX功能的丰富JS​​F组件。 RichFaces使用Ajax4jsf实现AJAX功能。

    翻译自: https://www.infoq.com/articles/jsf-dojo-dwr/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

    dwr和jsf的区别

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值