网站内容自动更新(如何自动使用动态元素更新网页(应用程序)?(图))

优采云 发布时间: 2021-11-30 03:01

  网站内容自动更新(如何自动使用动态元素更新网页(应用程序)?(图))

  自动定位网页元素

  有时,您可能需要使用动态元素来自动更新网页。例如,您可能希望投票 网站 在其数据库收到新投票后立即更新投票结果,或者您可能需要定期更新实时证券交易数据的股票 网站。轮询结果和实时交易数据是动态元素,直到运行时才知道,但应该在服务器发送信号时添加或更新元素。那么,您如何在 JSF 应用程序中执行此操作?

  之前的 developerWorks文章“使用 CSS 和 JavaScript 使用 JSF 制作 Ajax 应用程序,第 2 部分:动态 JSF 表单”介绍了如何在不刷新 Web 页面的情况下隐藏和显示可选的 JSF 组件。但是,您不能使用本文章 中描述的方法来解决此问题。此方法要求您标识所有 JSF 组件并将它们写入 JSF 页面。如果直到运行时才能识别动态元素怎么办?

  目前,JSF 没有很好的解决方案。虽然您可能熟悉 Java Swing 应用程序(例如“时钟”),其中数据更改会提示 GUI 更新,或者您可能在一些基本的 Swing 开发指南中阅读了此类应用程序的实现细节,但是这种方法并不适用对我的情况。Swing 提供了一种成熟的方法来仅根据内部数据状态自动更新 GUI,但是 JSF 并没有很好的支持基于服务器端请求刷新 GUI。如果您检查 JSF 的标准生命周期,您会发现用户通常需要在 Web 页面上生成一个事件(例如,通过单击按钮)来调用 GUI 刷新。这意味着即使可以在运行时创建动态元素并将其添加到网页中,

  那么,如何自动更新带有动态元素的网页呢?在本文中,我将描述以下解决方案:

  监控服务器端的数据变化

  为了更好地解释我的解决方案,我将在整个 文章 中使用一个示例。此应用程序用于在线图书销售网站。网页主页显示库存信息,例如书籍类别和每个类别的书籍数量(见图1).

  图1.在线图书销售首页

  

  为了反映准确的信息,您需要将页面上的列表信息与服务器端数据实时同步。由于在库存中添加或删除书籍等操作会导致服务器端数据更改,因此您必须监控这些操作。*敏*感*词*变化的方式是添加一个*敏*感*词*器来发现服务器端数据的变化,并让服务器端在发生任何变化后通知*敏*感*词*器。清单 1 显示了如何注册和取消注册类的侦听器。

  List1. 向列表中添加和删除侦听器

  public class Inventory{

……

private Map listeners =

new HashMap();

……

public void register(String id, InventoryListner listener){

listeners.put(id, listener);

}

public void deregister(String id){

listeners.remove(id);

}

……

}

  有两种 Java 方法可以在清单 1 所示的 Inventory 类中添加和删除库存侦听器。假设任何库存更改都是诸如添加或删除书籍之类的操作的结果,您可以在每次发生这些变化时通知所有注册到 Inventory 类的侦听器动作发生。清单 2 显示了如何将更改通知侦听器。

  List 2. 通知*敏*感*词*器更改

  public class Inventory{

……

public void addBookItem(String bookName,String auther,String price,

String category){

//codes for adding books

categoryChanged();

}

public void removeBookItem(String bookName,String auther,

String price,String category){

//codes for deleting books

categoryChanged();

}

private synchronized void categoryChanged(){

for (InventoryListner listener : listeners.values()) {

listener.categoryChanged();

}

}

}

  接下来,您可以使托管 bean InventoryBean 实现 InventoryListener 并将其注册到库存数据,以便在库存数据更改时可以通知 bean。清单 3 显示了如何将托管 bean 注册到 Inventory 类。

  List3. 将托管 bean 注册到列表

  public interface InventoryListner {

public abstract void categoryChanged();

}

public class InventoryBean implements InventoryListner{

……

private String m_clientId ;

private InventoryNotifier m_notifier;

public InventoryBean(){

m_notifier = InventoryNotifier.getInstance();

if(m_clientId == null) {

m_clientId = "bookstore";

m_notifier.register(m_clientId, this);

}

}

public void categoryChanged() {

refresh();

//code for refresh dynamic part via ajax

}

……

}

  使用清单 1 到清单 3 中概述的方法,您可以为托管 bean 构建一个框架来监视服务器端数据更改。工作流程是当托管 bean 收到服务器端数据发生变化的通知时,它会调用 InventoryBean 的 categoryChanged() 方法并更新数据模型。图 2 显示该框架在数据库和“Bean 组件”之间建立了一座桥梁。任何想要在服务器端监控数据变化或从服务器端接收事件的应用程序都可以使用这个框架作为模板。

  图2.业务流程模型

  

  更新数据模型并创建动态 GUI 元素

  在服务器端搭建好监控数据变化的框架后,如果要通知Bean有任何变化,就需要想办法更新数据模型,创建动态GUI元素。此过程在托管 Bean(参见图 2 中的 Bean 层)内执行,可分为两个子过程:更新数据模型和创建 GUI 元素。

  更新数据模型

  该子例程由前面清单 3 中所示的 refresh() 方法调用。清单 4 显示了如何更新数据模型。refresh() 方法用于重新组织库存以确保将书籍分配到正确的类别。因此,更新数据模型后,您可以保证删除任何没有书籍的类别并添加任何新类别。

  通过简要解释我使用的自定义数据结构,您将更好地理解 refresh() 方法。我使用 Category 类来存储库存信息。Category 类以ArrayList.BookItem 类的形式收录书籍的类别名称和元数据,其中收录书籍的名称、作者、价格和类别。清单 4 显示了如何更新数据模型。

  List4. 更新数据模型

  public class InventoryBean implements InventoryListner{

...

private Inventory m_notifier;

private Category[] m_category;

public InventoryBean(){

m_notifier = Inventory.getInstance();

}

private void refresh(){

//reorganize the data model

ArrayList categoryList = m_notifier.reorgnizeCategory();

// code for converting data to the type used in this bean,

// ArrayList to Category[]

}

...

}

  创建动态 GUI 元素

  接下来,我将讨论另一个子过程,即动态 GUI 元素的创建。在这种情况下,动态 GUI 元素是类别链接(见图 1)。如果用户单击主页上的特定类别,他将被重定向到收录该类别中所有书籍的新页面详细信息:图 3 显示了一个示例,其中所有书籍都属于侦探类别。

  图3. 侦探类详情

  

  要使分类链接起作用,您需要删除旧链接,将新链接插入网页的正确位置,并将不同分类详细信息绑定到不同分类链接。

  插入和删除链接

  有两种方法可以删除或插入链接。一种方法是在 JSF 组件树中搜索动态元素的父组件,然后删除或插入该元素。如果动态元素的父组件发生变化,则应使用此方法。另一种方法是将动态元素直接绑定到 Web 页面。这种方法比第一种方法更容易,因为不需要在 JSF 组件树中查找父节点。但是,该方法由于其易用性而存在局限性:仅当要删除或插入的元素具有在运行时之前已知的固定父元素时才能使用它。我选择这种方法(参见列表5),因为类别链接的父级在示例中是固定和预定义的。

  Listing 5. 创建/更新 GUI 组件并将不同的组件绑定到不同的动作处理程序

  category.jsp

……

……

……

public class InventoryBean implements InventoryListner {

……

private Category[] m_category;

public HtmlAjaxOutputPanel getCategorygrid() {

updateGUI();

return categorygrid;

}

public void setCategorygrid(HtmlAjaxOutputPanel categorygrid) {

this.categorygrid = categorygrid;

}

private void updateGUI(){

categorygrid.getChildren().clear();

if (m_category != null) {

int num = m_category.length;

for (int index = 0; index < num; index++) {

HtmlPanelGrid categorySubgrid =

JSFUtil.getLinkgrid("Bookstore_sublink" + index,

"#{InventoryBean.category[" +index+ "].categoryLabel}",

"#{InventoryBean.category[" +index+ "].onClickAction}");

categorygrid.getChildren().add(categorySubgrid);

}

}

}

……

}

  如您所见,category.jsp 文件的 updateGUI() 行用于绑定托管 bean 中的动态元素。它将清除所有以前创建的动态元素,基于新的数据模型创建新的动态元素,并将它们添加到预定义的父元素中。

  将不同的行为绑定到不同的链接

  现在让我们讨论如何将不同的类别详细信息绑定到不同的类别链接。我想迭代一个数组,将每个元素传输到一个 GUI 组件,然后将其插入到 JSF 组件树中。我的机制是将所有类别放入一个Array中,并将每个类别作为一个元素。每个元素都有一个返回其类别标签的方法和一个绑定点击动作的方法。通过让每个元素保留自己的类别信息以将其与其他元素区分开来,我可以确保每个元素都具有绑定到“onclick”操作的唯一行为。

  在updateGUI()中,“Bookstore_sublink”+index是分类链接的ID。"#{InventoryBean.category[" + index+ "].categoryLabel}" 是分类链接的标签。"#{InventoryBean.category[" + index+ "].onClickAction}" 是绑定到类别链接的操作。getCategoryLabel()方法用于返回链接标签,onClickAction()绑定点击操作。(参见清单 6。)

  列出6.值和动作绑定方法

<p>public class Category {

……

private String category;

private ArrayList bookitems;

public String getCategoryLabel(){

if(bookitems.size()

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线