Tapestry 和 Wicket 的比较

渗透测试之哥斯拉实战 可以直接在这里使用meterpreter命令进行对服务端的控制。选择目标 - 添加,配置连接信息,之后测试连接成功!php的shell功能如图。先要进行数据库的配置信息。可以直接在这里打包全站。 阅读详情
  

JSF 和 Struts 是开发人员在进行 Web 开发时使用的传统的组件框架。但还有另外一种选择,Tapestry 和 Wicket,它们是面向组件的 Web 框架,其设计目标专门针对 Web 应用程序创建。本文采用 Tapestry 和 Wicket 技术开发了一个简单的应用程序示例,该程序实现了一个 to-do 列表的工作流。

Tapestry 和 Wicket 被宣扬为流行的基于组件的现代 Web 框架。与 Model 2 架构框架 Struts 或 Spring MVC 不同,Tapestry 和 Wicket 为 Web 开发过程提供了一种全新的方式,即以看待基于 GUI 的独立应用程序相同的方式来考虑 Web 应用程序及其行为和组件交互。

 

典型的基于组件的应用程序表示一个页面集合,它由一套组件组成。而这些组件可能由更小的组件组装而成。用户交互是一种特定的组件事件。这是与基于 MVC 的应用程序的主要区别,后者的交互入口点是一个 servlet 或一个具有一般属性的操作(例如 URLs 及其参数、表单等)。

 

使用基于组件的框架的开发人员通过实现事件驱动模型来关注组件和组件交互。 Servles、HTTP 会话和其他来自 servlet API 的实体被移动到更低的级别并且从来不会被直接使用。然而,通过声明组件及其属性,开发人员需要管理服务器端的状态,这种状态可能是会话持久性的。

 

与 JSF 或使用 JSP 和 Velocity 标记的 WebWorks 不同,Tapestry 和 Wicket 都使用它们自己的模板系统,允许创建完全符合 HTML 标准的 HTML 模板。这使我们可以清晰地实现关注点分离:从事 GUI 的 Web 设计者不用考虑应用程序是在何种平台之上编写;同样,实现组件的应用程序的开发人员不用考虑页面的最终设计是否使用 stub 元素进行调试和测试。 Tapestry 和 Wicket 都支持这种分离。

 

Tapestry 一览

 

目前,Tapestry V4.1 是该项目的正式发行版。V5.0 目前正处于积极开发中,从团队开始从头编写 Tapestry 到撰写本文之际,已有 18 个月有余。尽管 V5.0 还没有公开发布,可以肯定地说它与先前的版本完全不同,因为它不是向后兼容的。由于不能确定 V5.0 的状态,我们主要侧重于 V4.1。

 

Tapestry V4.1 主要基于 HiveMind 微内核,这是控制反转(Inversion-of-Control)容器的一个严格表示。所有的 Tapestry 服务都是使用 HiveMind 注册的。

 

一个典型的 Tapestry 组件由以下部分组装而成:一个组件说明(一个 XML 描述符)、组件逻辑(Java™ 编程语言的一部分)、UI 布局(一个 HTML 模块)。

 

Wicket 一览

 

Wicket 架构的核心是组件 类,所有组件和标记容器对其进行扩展。组件主要负责处理其模型 — IModel 界面的一个实现。模型表示与组件实例相关的任何类型的数据并定义其行为。IModel 中一个著名的实现是 LoadableDetachableModel,它允许传递临时数据、在呈现组件之前加载数据、在不需要时将其移除(撤销),从而减少了 Wicket 会话的大小。

 

Wicket 页面也是组件,如果具有状态,则它们的状态将保存在 Wicket 会话中。页面可以启用版本,因此每当页面状态发生改变(查看页面、修改其组件状态等)时,将连同一个递增的版本编号进行保存。

 

 

 

开发过程

 

本节说明在 Tapestry 和 Wicket 中如何完成典型的任务。注意下面的代码片段大多数取自较大的代码源,比如组件和页面。因此,它们可能包含此处没有描述的一些业务方法的调用。

 

支持的数据类型

 

这两个框架都支持 Java 数据类型。Tapestry 采用对象图导航语言(Object-Graph Navigation Language,OGNL)。它是一种获取和设置 Java 对象属性的表达式语言。Wicket 用它独有的机制进行数据绑定。 有 两 种 方便的实现可以动态检索和更新对象属性:PropertyModel 和 CompoundPropertyModel。

 

我们来查看一个应用 float 类型的示例。在 Tapestry 中,按照以下方式指定一个具有 float 值的文本字段:

 

 

清单 1. Tapestry 代码示例

               

<component id="weight" type="TextField">

        <binding name="value" value="ognl:weight"/>

        <binding name="translator" value="translator:number,pattern=#.#"/>

        <binding name="displayName" value="literal:Weight"/>

    </component>

 

 

 

Wicket 中按照以下方式指定这种文本字段:

 

 

清单 2. Wicket 代码示例

               

FormComponent field = new TextField("weight", Float.class);

field.setLabel(new Model("Weight"));

add(field);

 

 

 

因此,可以自然地使用简单的数据类型,比如 string、integer、 float,甚至是 BigDecimal。

 

验证

 

作为一条经验法则,应该针对业务规则验证所有的用户输入。Tapestry 和 Wicket 都能够对表单输入字段执行服务器端或客户机端(使用 DHTML)的验证。思考一下在服务器端如何完成这个任务。在框架中将按照以下方式通过特定的验证程序进行字段输入验证:

 

 

清单 3. Tapestry 验证程序

               

<component id="weight" type="TextField">

        ...

        <binding name="validators" value="validators:min=1,max=500"/>

    </component>

 

 

 

清单 4. Wicket 验证程序

               

...

field.add(NumberValidator.range(1, 500));

 

 

 

如果没有符合要求的验证程序,也可以定义一个自定义字段验证程序。如果产生任何验证错误,都应该向用户显示以表明输入无效。

 

在 Tapestry 中,我们应当在字段之上定义一个循环,跟踪默认的 ValidationDelegate 表单 bean,从而显示所有的表单错误。

 

 

清单 5. ValidationDelegate 表单 bean

               

    <property name="currentFieldTracking"/>

    <component id="errors" type="For">

        <binding name="source" value="beans.delegate.fieldTracking"/>

        <binding name="value" value="currentFieldTracking"/>

    </component>

    <component id="isInError" type="If">

        <binding name="condition" value="currentFieldTracking.inError"/>

    </component>

    <component id="error" type="Delegator">

        <binding name="delegate" value="currentFieldTracking.errorRenderer"/>

    </component>

 

 

 

相应的 HTML 标记如下所示:

 

 

清单 6. Wicket 验证程序

               

     <ul jwcid="errors">

         <li jwcid="isInError">

             <span jwcid="error">Form validation error </span>

         </li>

     </ul>

 

 

 

在 Wicket 中,FeedbackPanel 实现了显示多种错误的功能:add(new FeedbackPanel("feedback"));。HTML 标记如下: <span wicket:id="feedback" /></div>。

 

要启用客户端验证,需要将 clientValidationEnabled 参数添加到 Tapestry 的一个表单中,如下所示:

 

 

清单 7. Tapestry 中的客户端验证

               

<component id="actionForm" type="Form">

        <binding name="delegate" value="beans.delegate"/>

        <binding name="clientValidationEnabled" value="true"/>

    </component>

 

 

 

基于相同的目的,Wicket 中采用AjaxFormValidatingBehavior 类。

 

 

清单 8. Wicket 中的客户端验证

               

    AjaxFormValidatingBehavior.addToAllFormComponents(form, "onkeydown");

    // Add the button to submit the form using AJAX

    form.add(new AjaxButton("ajax-button", form) {

        protected void onSubmit(AjaxRequestTarget target, Form form) {

            target.addComponent(feedback);

        }

        protected void onError(AjaxRequestTarget target, Form form) {

            target.addComponent(feedback);

        }

    });

 

 

 

控制结构

 

我们假设有一个分配给许多人的任务列表,并希望将它显示到一个 HTML 表中。 Tapestry 采用 For 标准组件来遍历集合,如清单 9、10、11 所示:

 

 

清单 9. Tapestry 页面说明

               

    <component id="receivedItems" type="For">

        <binding name="source" value="ognl:receivedItems"/>

        <binding name="value" value="ognl:currentItem"/>

    </component>

    <component id="itemId" type="Insert">

        <binding name="value" value="ognl:currentItem.itemId"/>

    </component>

    <component id="subject" type="Insert">

        <binding name="value" value="ognl:currentItem.subject"/>

    </component>

    <component id="creator" type="Insert">

        <binding name="value" value="ognl:currentItem.creator"/>

    </component>

    <component id="recipient" type="Insert">

        <binding name="value" value="ognl:currentItem.recipient"/>

    </component>

 

 

 

清单 10. Tapestry Java 类

               

    public abstract List getReceivedItems();

    public abstract void setReceivedItems(List items);

    public abstract ActionItem getCurrentItem();

 

 

 

清单 11. Tapestry HTML 标记

               

    <tr jwcid="receivedItems">

        <td><span jwcid="itemId">ID</span></td>

        <td><span jwcid="subject">Subject</span></td>

        <td><span jwcid="creator">Creator</span></td>

        <td><span jwcid="recipient">Recipient</span></td>

    </tr>

 

 

 

在 Wicket 中,我们采用 ListView 类并匿名地实现其 populateItem() 方法,如清单 12、13 所示:

 

 

清单 12. Wicket Java 类

               

    add(new ListView("receivedItems", items) {

        protected void populateItem(final ListItem item) {

            ActionItem todo = (ActionItem) item.getModelObject();

 

            item.add(new Label("itemId", String.valueOf(todo.getItemId()));

            item.add(new Label("subject", todo.getSubject()));

            item.add(new Label("creator", todo.getCreator()));

            item.add(new Label("recipient", todo.getRecipient()));

        }

    });

 

 

 

清单 13. Wicket HTML 标记

               

    <tr wicket:id="receivedItems">

        <td><span wicket:id="itemId">ID</span></a></td>

        <td><span wicket:id="subject">Subject</span></td>

        <td><span wicket:id="creator">Creator</span></td>

        <td><span wicket:id="recipient">Recipient</span></td>

    </tr>

 

 

 

现在让我们实现更复杂的目标并添加一些有条件的文本呈现 — 例如,命名偶数和奇数表行的 CSS 类。因此添加以下内容。关于 Tapestry 页面说明,请参看清单 14、15:

 

 

清单 14. Tapestry 中的页面说明

               

    <component id="receivedItems" type="For">

        ...

        <binding name="index" value="ognl:currentIndex"/>

        <binding name="class" value="ognl:currentStyleClass"/>

    </component>

 

 

 

清单 15. Tapestry Java 类

               

    ...

    public abstract int getCurrentIndex();

    public String getCurrentStyleClass() {

        return (getCurrentIndex() % 2 == 0) ? "list-row-even" : "list-row-odd";

    }

 

 

 

清单 16. Wicket Java 类

               

    add(new ListView("receivedItems", items) {

        protected void populateItem(final ListItem item) {

            ...

            item.add(new AttributeModifier("class", true, new AbstractReadOnlyModel() {

                public Object getObject() {

                    return (item.getIndex() % 2 == 0) ? "list-row-even" : "list-row-odd";

                }

            }));

        }

    });

 

 

 

分页

 

目前页面展现了所有的用户任务。然而,随着时间的推移会出现更多的任务,单个表中很快就会出现大量任务。这种情形下非常适合使用多页面表。

 

Tapestry 提供方便的 Table 组件及其低级别的支持,比如来自 Contrib Library 模块的 TableView,如清单 17、18 所示:

 

 

清单 17. Tapestry 页面说明

               

    <component id="receivedItemsView" type="contrib:TableView">

        <binding name="source" value="ognl:itemsTableModel"/>

        <binding name="columns" value="itemId, subject, creator, recipient"/>

        <binding name="pageSize" value="10"/>

    </component>

    <component id="receivedItemsColumns" type="contrib:TableColumns" />

    <component id="receivedItemsRows" type="contrib:TableRows" />

    <component id="receivedItemsValues" type="contrib:TableValues" />

    <component id="receivedItemsPages" type="contrib:TablePages">

        <binding name="pagesDisplayed" value="10"/>

    </component>

 

 

 

清单 18. Tapestry 中的 Java 类

               

    public IBasicTableModel getItemsTableModel() {

        return new IBasicTableModel() {

            public int getRowCount() {

                return getActionItemManager().getActionItemsCountByRecipient(uid);

            }

            public Iterator getCurrentPageRows(int nFirst, int nPageSize,

                    ITableColumn objSortColumn, boolean bSortOrder) {

                return getActionItemManager()

                    .getActionItemsListByRecipient(uid, nFirst, nPageSize);

            }

        };

    }

 

 

 

清单 19. Tapestry HTML 标记

               

<span jwcid="table">

    <table>

        <tr><span jwcid="receivedItemsColumns" class="title"/></tr>

        <tr jwcid="receivedItemsRows">

            <td jwcid="receivedItemsValues"/>

        </tr>

    </table>

    <span jwcid="receivedItemsPages"/>

</span>

 

 

 

Wicket 一同提供了一个 DataView 类和一个 IDataProvider 实现,如下所示:

 

 

清单 20. Wicket 的 DataView 类

               

public class ItemsDataProvider implements IdataProvider {

 

    public Iterator iterator(int first, int count) {

        return getActionItemManager().getActionItemsListByRecipient(uid, first, count);

    }

 

    public int size() {

        return getActionItemManager().getActionItemsCountByRecipient(uid);

    }

 

    public IModel model(Object object) {

        return new LoadableDetachableModel(object);

    }

}

 

public ListActionItems extends WebPage {

    public ListActionItems() {

        DataView dataView = new DataView("receivedItemsView", new ItemsDataProvider()) {

            protected void populateItem(final Item item) {

                ActionItem todo = (ActionItem) item.getModelObject();

                item.add(new Label("itemId", String.valueOf(todo.getItemId()));

                item.add(new Label("subject", todo.getSubject()));

                item.add(new Label("creator", todo.getCreator()));

                item.add(new Label("recipient", todo.getRecipient()));

            }

        };

        dataView.setItemsPerPage(10);

        add(dataView);

        add(new PagingNavigator("receivedItemsPages", dataView));

    }

}

 

 

 

清单 21. Wicket 的 DataView HTML 标记

               

    <table>

        <tr>

            <th>ID</th>

            <th>Subject</th>

            <th>Creator</th>

            <th>Recipient</th>

        </tr>

        <tr wicket:id="receivedItemsView">

            <td><span wicket:id="itemId">ID</span></td>

            <td><span wicket:id="subject">Subject</span></td>

            <td><span wicket:id="creator">Creator</span></td>

            <td><span wicket:id="creationDate">Creation Date</span></td>

            <td><span wicket:id="deadline">Deadline</span></td>

        </tr>

    </table>

    <span wicket:id="receivedItemsPages">Paging navigator links</span>

 

 

 

国际化

 

开发一个多语言应用程序时,国际化支持在制定决策时起着至关重要的作用。 Tapestry 和 Wicket 能够提供几乎无限的本地化功能。你可以本地化组件文本(标签、消息 — 常见内容)以及像图片这样的静态资源,甚至可以本地化整个标记模板,只要将具有本地标识符的后缀添加到本地化资源名称中,如下所示:

 

 

清单 22. Tapestry 和 Wicket 中的本地化

               

ListActionItems.html

ListActionItems.properties

ListActionItems_ru_RU.html

ListActionItems_ru_RU.properties

 

 

 

当访问一个来自页面说明或模板的本地化消息时,在 Tapestry 组件参数中采用 message: 前缀。Wicket 中有一种功能强大的协助完成本地化任务的 StringResourceModel 类。

 

书签、breadcrumbs 和 Back 按钮

 

Tapestry 和 Wicket 使用自己的格式生成 URLs,这看起来似乎不能使用书签功能。这导致很难引用页面。但是这个框架也提供了这种情况的解决方案。

 

在 Tapestry 中,从外部引用的页面应该实现 IExternalPage 接口,如下所示:

 

 

清单 23. Tapestry 实现 IExternalPage

               

public abstract class ViewActionItem extends BasePage implements IExternalPage {

 

    public abstract Integer getItemId();

    public abstract void setItemId(Integer itemId);

 

    public void activateExternalPage(Object[] params, IRequestCycle cycle) {

        setItemId((Integer) params[0]);

    }

 

    public void pageBeginRender(PageEvent pageEvent) {

        ActionItem todo = getActionItemManager().getActionItemByItemId(getItemId());

    }

}

 

 

 

此外,页面可以通过以下网址引用 http://host/webapp/tapestryapp?page=ViewActionItem&service=external&sp=123。 然而这不是直接访问 Tapestry 页面的惟一方法。我们可以采用 HiveMind 服务编码器 — 页面服务编码器 — 这个编码器能够把页面名字编码成一些在 URL 中可读的内容。

 

 

清单 24. HiveMind 配置:hivemodule.xml

               

<module id="com.ibm.cit.tvw" version="1.1.0">

    <contribution configuration-id="tapestry.url.ServiceEncoders">

        <page-service-encoder id="page" extension="html" service="page"/>

    </contribution>

</module>

 

 

 

不要忘记将扩展名 .html 的 servlet 映射添加到 web.xml 中,如下所示:

 

 

清单 25. 在 hivemodule.xml 中添加 servlet 映射

               

    <servlet-mapping>

        <servlet-name>TodolistApplication</servlet-name>

        <url-pattern>*.html</url-pattern>

    </servlet-mapping>

 

 

 

从现在开始,每个应用程序页面都可以被访问,比如, http://host/webapp/ListActionItems.html。可以对它添加书签。注意,不能以这种方式提供请求参数 — 页面可以在没有参数的情况下调用(或使用默认参数)。

 

在 Wicket 中,应该只将具有 PageParameters 的页面构造函数定义为参数,如下所示:

 

 

清单 26. Wicket 和 PageParameters

               

public class ListActionItems extends WebPage {

    public ListActionItems(PageParameters parameters) {

        int id = parameters.getInt("id");

        // do something

    }

}

 

 

 

稍后,这个页面可以引用为 http://host/webapp/wicketapp/?wicket:bookmarkablePage=%3Acom.ibm.cit.tvw.wicket.page.ViewActionItem&id=123。你也可以将页面挂载到理想的路径,如下所示:

 

 

清单 27. 在 Wicket 中将页面挂载到理想路径

               

public class ToDoListApplication extends WebApplication {

    protected void init() {

        mountBookmarkablePage("/apath/login.html", Login.class);

    }

}

 

 

 

当操作页面 URL 时,上述方法能实现最大的灵活性。

 

现在我们开始讨论 breadcrumbs。breadcrumbs 是客户机的操作历史。Wicket 有两个接口针对 breadcrumbs: IBreadCrumbModel 和 IBreadCrumbParticipant,其中模型使用一个活动的 breadcrumbs 将参与者表示为一个列表。模型接口 BreadCrumbBar 的一个有用的实现包含一个 breadcrumbs 参与者堆栈。如果还没有开始一个新的参与者,则它将被放入堆栈的顶部 — 在本例中,对新参与者关闭了堆栈。

 

另一方面,Tapestry 并没有为 breadcrumbs 提供任何现成的解决方案。

 

接下来,我们开始讨论 Back 按钮。Web 浏览器的 Back 按钮一直以来都是 Web 应用程序开发人员想要消除的东西,希望以此避免使用它带来的意想不到的影响。但它仍然存在,因此应用程序应该对任何相关事件正确响应。

 

在这种上下文中,Wicket 因为使用页面版本管理(page-version management)而大放异彩,如果启用了页面版本化,可以很轻松地将页面状态恢复到以前的版本。页面状态由 VersionManager 管理,状态改变保存在用户的会话中。但是要慎用这些特性。

 

那么 Tapestry 能提供什么呢?Tapestry 中没有什么简单的方法实现上述功能,应用客户端持久性是一种选择,但这是一个很难处理的问题,需要进行一些特殊的考虑。

 

定制组件

 

在基于组件的框架中,重用自定义组件是最主要、最强大的功能之一。你可以描述自己的组件,这些组件可以是整个页面,也可以是较小的面板,甚至是单独的一个 HTML 元素。通过组件继承,可以很自然地设计组件模板,并且不会产生什么问题。一旦创建了这些模块,你可以根据需要将其多次插入应用程序中的任何位置。Tapestry 和 Wicket 对管理组件的重用没有任何限制,但它们的方式各有不同。

 

当自定义组件可以应用到各种应用程序时,将变得真正可重用。Wicket 仅仅通过创建一个包含组件类和标记模板的 JAR 归档就可以进行打包。把归档自动放入应用程序的类路径中将使组件变得可用。Tapestry 需要另外一些步骤来定义一个自定义组件库 — JAR 归档应该包含一个带有库规范元素的 XML 描述符。使用这个库的应用程序应该在该应用程序的配置文件中指定这个库。

 

可重用组件的一个最棒的应用是提供了普通导航面板、页眉和页脚、说明栏等内容的页面模板。接下来的模块示例是一个显示主页链接、当前登录用户的名称和 Logout 按钮的组件。

 

在 Tapestry 中,模板组件规范如清单 28, 29,和 30 所示:

 

 

清单 28. Tapestry 的组件模板规范

               

<component-specification allow-body="yes"

  allow-informal-parameters="no"

  class="com.ibm.cit.tvw.tapestry.component.Template">

 

    <!--HTML head -->

    <asset name="stylesheet" path="/style.css" />

    <parameter name="pageTitle" default-value="literal:Todolist Application" />

    <component id="shell" type="Shell">

        <binding name="stylesheet" value="assets.stylesheet" />

        <binding name="title" value="ognl:pageTitle" />

    </component>

 

    <!-- HTML body -->

    <component id="body" type="Body" />

 

    <!-- The name of the currently logged user -->

    <component id="user" type="Insert">

        <binding name="value" value="ognl:currentUser"/>

    </component>

 

    <!-- The home page -->

    <component id="homeLink" type="PageLink">

        <binding name="page" value="literal:ListActionItems" />

    </component>

 

    <!-- User Profile page -->

    <component id="profileLink" type="DirectLink">

        <binding name="listener" value="listener:onEditUserProfile"/>

    </component>

 

    <!-- Logout link -->

    <component id="logoutLink" type="ServiceLink">

        <binding name="service"

                value="ognl:@org.apache.tapestry.Tapestry@RESTART_SERVICE"/>

    </component>

 

    <!-- Page content -->

    <component id="pageContent" type="RenderBody"/>

</component-specification>

 

 

 

清单 29. Tapestry 的组件模板规范 Java 类

               

public abstract class Template extends BaseComponent {

 

    public String getCurrentUser() {

        return getPage().getRequestCycle().getInfrastructure()

                .getRequest().getUserPrincipal();

    }

 

}

 

 

 

清单 30. Tapestry 的组件模板规范 HTML 标记

               

<html jwcid="shell">

<body jwcid="body">

<div id="top">

<div id="header">

    <a jwcid="homeLink" class="homelink">Action Items Sample Application</a>

    Current user:   <span jwcid="user">Davy Jones</span>

    <a jwcid="logoutLink">Logout</a></span>

</div>

<div id="page-content">

<span jwcid="pageContent">This is a page content.</span>

</div>

</div>

</body>

</html>

 

 

 

使用模板的其他页面如清单 31 所示,这是 ViewActionItem 页面的一个例子。

 

 

清单 31. ViewActionItem 示例

               

<page-specification>

    <component id="template" type="Template">

        <binding name="pageTitle" value="literal:View Action Item"/>

    </component>

    ...

</page-specification>

 

 

 

清单 32. HTML 标记中的 ViewActionItem

               

<span jwcid="template">

    <!-- Page content -->

    ...

</span>

 

 

 

在 Wicket 中,模板被表示为一个基本页面,如清单 33 和 34 所示:

 

 

清单 33. Wicket 模板

               

public abstract class TemplatePage extends WebPage {

 

    private String title;

 

    public TemplatePage() {

        add(new Label("title", new PropertyModel(this, "title")));

        add(new BookmarkablePageLink("homeLink", getApplication().getHomePage()));

        add(new Label("user", ((WebRequest) getRequest()).getHttpServletRequest()

                .getUserPrincipal().getName()));

        add(new Link("logoutLink") {

            public void onClick() {

                getSession().invalidate();

                getRequestCycle().setResponsePage(getHomePage());

                getRequestCycle().setRedirect(true);

            }

        });

    }

 

    public String getTitle() {

        return title;

    }

 

    public void setTitle(String title) {

        this.title = title;

    }

}

 

 

 

清单 34. 作为 HTML 标记的 Wicket 模板

               

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns:wicket="http://wicket.apache.org/">

<head>

<meta http-equiv="Pragma" content="no-cache" />

<meta http-equiv="Expires" content="0" />

<link rel="stylesheet" type="text/css" href="style.css" />

<title wicket:id="title">Sample Page Title</title>

</head>

<body>

<div id="top">

<div id="header">

    <a wicket:id="homeLink" class="homelink">Action Items Sample Application</a>

    Current user: <span wicket:id="user">Davy Jones</span>

    <input type="button" class="button" wicket:id="logoutLink" value="Logout" /></span>

</div>

<div id="page-content">

<wicket:child />

</div>

</div>

</body>

</html>

 

 

 

应用这个模板的子页面应该继承模板页面,如清单 35 和 36 所示:

 

 

清单 35. 继承模板页面

               

public class ViewActionItem extends TemplatePage {

 

    public ViewActionItem() {

        setTitle("View Action Item");

        ...

    }

}

 

 

 

清单 36. 继承作为 HTML 标记的 Wicket 模板

               

<html xmlns:wicket="http://wicket.apache.org/">

<head></head>

<body>

<wicket:extend>

    <!-- Page content -->

    ...

</wicket:extend>

</body>

</html>

 

 

 

Ajax 支持

 

我们开始讨论框架对比中最有趣的地方:Asynchronous JavaScript + XML (Ajax) 的使用。

 

您还记得您的第一个使用 Ajax 的 Web 应用程序以及在实现时付出的艰辛吗? 没错,为了实现多浏览器的支持,所有 JavaScript 通信和数据解析代码都包含了大量技巧。客户端的实现是最麻烦的工作,与之相比,Servlet 工作更加轻松。

 

然而,现在随着诸如 Tapestry 和 Wicket 这类框架的使用,在一个应用程序中增加一个 Ajax 操作只需要几行代码和几分钟的时间。这种操作非常简单。以下的示例描述了一种简单的场景:单击 to-dos 列表中的某一项将使用相应的数据更新(以 Ajax 模式)预览面板。

 

Tapestry 将链接的 async 参数设置为 true,并且,如果必要的话,定义链接应该更新的组件的列表,如清单 37、38 和 39 所示:

 

 

清单 37. Tapestry 页面说明片段

               

    <component id="previewReceivedItem" type="DirectLink">

        <binding name="listener" value="listener:onPreviewItem"/>

        <binding name="parameters" value="ognl:currentItem.itemId"/>

        <binding name="async" value="true"/>

        <binding name="updateComponents" value="ognl:{'preview'}"/>

    </component>

    <component id="preview" type="Any"/>

    <component id="previewSubject" type="Insert">

        <binding name="value" value="ognl:previewSubject"/>

        <binding name="renderTag" value="true"/>

    </component>

    <component id="previewState" type="Insert">

        <binding name="value" value="ognl:previewState"/>

        <binding name="renderTag" value="true"/>

    </component>

 

 

 

清单 38. Tapestry 页面说明片段 Java 类

               

public abstract class ListPreviewActionItems extends BasePage {

 

    public abstract String getPreviewSubject();

    public abstract void setPreviewSubject(String previewSubject);

 

    public abstract String getPreviewState();

    public abstract void setPreviewState(String PreviewState);

 

    public void onPreviewItem(Integer itemId) {

        if (itemId != null) {

            ActionItem pitem = getActionItemManager().getActionItemByItemId(itemId);

            setPreviewSubject(pitem.getSubject());

            setPreviewState(pitem.getCurrentState());

        }

    }

}

 

 

 

清单 39. Tapestry 页面说明片段 HTML 标记

               

<h3>Preview Action Item</h3>

<div jwcid="preview">

    Subject: <span id="previewSubject" jwcid="previewSubject">subject</span><br/>

    State: <span id="previewState" jwcid="previewState">current state</span>

</div>

 

 

 

Wicket 中只使用具有已实现的 onClick() 方法的 AjaxLink,如清单 40 和 41 所示:

 

 

清单 40. Wicket 中的 AjaxLink

               

public class ListPreviewActionItems extends WebPage {

 

 public ListPreviewActionItems() {

   final LoadableActionItemModel previewItem = new LoadableActionItemModel(null);

 

   WebMarkupContainer preview = new WebMarkupContainer("preview");

   preview.setOutputMarkupPlaceholderTag(true);

   preview.add(new Label("previewSubject", new PropertyModel(previewItem, "subject")));

   preview.add(new Label("previewState", new PropertyModel(previewItem, "currentState")));

   add(preview);

 

   AjaxLink previewReceivedItem = new AjaxLink("previewReceivedItem") {

       public void onClick(AjaxRequestTarget target) {

           previewItem.setItemId(currentItem.getItemId());

           target.addComponent(previewContainer);

       }

   };

   add(previewReceivedItem);

 }

}

 

 

 

清单 41. Wicket 的 AjaxLink HTML 标记

               

<h3>Preview Action Item</h3>

<div wicket:id="preview">

    Subject: <span wicket:id="previewSubject">subject</span><br/>

    State: <span wicket:id="previewState">current state</span>

</div>

 

 

 

就这么简单。框架在幕后执行了通信、数据处理及所有其他棘手的工作。

 

 

 

开发工具

 

关于 Tapestry 和 Wicket 框架开发过程之间的区别,没有太多可介绍的。使用支持 Web 应用程序开发的大多数 Java IDE 实现 Tapestry 组件非常简单。Wicket 需要的更少 — 任何 Java IDE 加上 HTML 编辑器都能满足开发需要。

 

对于 Java 和标记中的组件模型树,偶尔会遇到同步问题,但是每次调用组件时您都会收到通知。这与其他框架相反,比如 Google Web Toolkit,后者可以在编译时处理这些问题。

 

 

供 IBM WebSphere Application Server CE 使用

 

Tapestry 和 Wicket 是与 Java Web 应用程序兼容的框架,所以可以像往常一样构建和打包 Web 应用程序。要把这个应用程序部署到 IBM® WebSphere® Application Server Community Edition,提供了一个嵌入式或单独的应用程序开发计划,该计划也是具有代表性的。

 

结束语

 

Tapestry 和 Wicket 是基于组件的 Web 框架的典型代表,并且可能是这类框架中最杰出的。借助它们的帮助,可以构建各种复杂的应用程序。当然,CMS 可以更好地管理具有静态信息的页面集合,然而当论及一个应用程序的多用户交互时,框架展示了其优势。

 

尽管框架架构之间有许多相似之处(二者都面向组件并可以实现清晰的关注点分离),它们的实现仍然有很大的区别。Tapestry 在组件规范中提供一个声明式方法,而 Wicket 提供了没有 XML 和注解的纯粹的 Java 编程。Wicket 在页面版本化和多窗口支持方面具有一些优势。Wicket 还提供一些有帮助的工具,包括 breadcrumbs、反馈面板和一些在动态 HTML 中应用的独特特性,比如选项卡式面板和对话框。

 

如果想要尽量避免使用 XML,或者只喜欢面向对象编程,日常使用时可以选择 Wicket。 Wicket 也提供了一个更丰富的扩展库。

 

最后,Tapestry 正处于过渡时期。Tapestry V5 在 V4.1 的基础上承诺了很多增强,但是没有规划向后兼容。因此,用 V4.1 编写的应用程序可能还会继续使用,但那些从使用当前 Tapestry 获益的专业开发人员可能不会长期受益。

 

01-诊断开发流程概述 传送门 ==>> AutoSAR入门和实战系列总目录。 阅读详情

相关推荐

Visual Studio 2022调试Godot 4 C#项目全攻略:从环境配置到断点调试

本文详细介绍了如何配置Visual Studio 2022以高效调试Godot 4 C#项目。从环境搭建、外部编辑器设置到两种核心调试模式(附加到进程与启动配置)的实战指南,帮助开发者构建无缝的工业级工作流,解决编码乱码、断点失效等常见问题,大幅提升开发与问题排查效率。

bush的博客 391

《wicket学习十六》&ListViewExample

现在我们来学习有关wicket中定义的listview,具体的实现结果如下所示。 我们来看一下homepage.java public class HomePage extends WebPage { public HomePage() { List<Person> persons = Arrays.asList(new Person("John", ...

yGIS 338

别再手动跑定时任务了!Spring Boot项目5分钟集成xxl-job保姆级教程(含Docker部署调度中心)

本文提供Spring Boot项目快速集成xxl-job的保姆级教程,包括Docker部署调度中心的详细步骤。通过实战案例展示如何构建企业级分布式任务调度系统,解决传统定时任务的资源竞争、单点故障等问题,提升开发效率与系统可靠性。

weixin_30315905的博客 291

Tapestry学习5

jwcid属性:在页面模板中指定组件,指定了jwcid属性标签表示会被程序动态解析,  studyName@TextField" value="ognl:info.studyName"/> @标记:在jwcid属性中表示定义组件标记符号,@之前表示组件的名称,@之后表示组件对象,而在ognl表示访问类的方法(仅对静态方法),如:  studyName@TextField" value="og

mianhuatangQi的专栏 1221

基于单片机直流电机调速控制系统设计

*单片机设计介绍,基于单片机直流电机调速控制系统设计。

2201_75940997的博客 2780

Windows下的Geant4安装教程

本教程将从0开始展示在Windows下如何安装Geant4,包括各种辅助工具(QT、Cmake、Visual Studio)的下载安装,环境变量的配置,以及example的生成等。

weixin_49065278的博客 4105

Wicket & Tapestry

      最近要做一个类CMS的系统,在选型的时候,由于之前用的Tapestry 4,所以,一开始打算用他的,但是4的pretty url做的不好,而且需要有个xml来写那些循环,binding之类的逻辑。所以,直接就pass,想看看5,虽然5的feature list里面列出了一大堆的新功能,而且号称速度提高不少,但他的view层居然又走回了之前jsp的老路,允许在页面里面写表达式,所以,也直

技术源于生活 2263

华为od 面试八股文_测试/测试开发_01_含答案

华为od面试八股文_测试/测试开发_01_含答案

MISAYAONE的博客 3815

【ProjectT】Tapestry • Quick Start • Forms

本教程中,我們會涉及到 Tapestry forms 的一些基礎知識,然後再通過一個 Tapestry 應用來加深理解。我們會看看如何在頁面之間傳遞信息。 這份教程的主題是一個用於追蹤 Tapestry 的第三方程序庫的應用程序。每個項目都有這些屬性: name release ID short and long description category supported Tap...

weixin_30291791的博客 132

基于Simulink与MATLAB的七轴OpenArm机械臂逆运动学仿真与轨迹规划完整指南

本文详细介绍了七自由度OpenArm机械臂在MATLAB/Simulink环境下的运动学仿真与轨迹规划实现方法。首先建立了机械臂的DH参数模型,验证了正运动学计算;随后提出了两种逆运动学求解算法(数值迭代法和臂型角参数化解析法)的MATLAB实现方案;最后在Simulink中搭建了完整的轨迹规划与控制系统。研究解决了七自由度冗余机械臂特有的多解性、奇异性和关节限位约束等核心问题,为OpenArm机械臂的运动控制提供了完整的技术方案和可运行代码实现。

AI的内部世界的博客 681

从工具选型到落地实践:吃透 SAP Fiori Launchpad 配置工具体系

摘要: SAP Fiori Launchpad配置远非简单添加应用和分配角色,涉及技术目录、业务目录、Spaces/Pages等多层管理。官方推荐新工具分工:技术目录用FLPAM维护应用定义,业务目录用FLPCM编排应用组合,Spaces/Pages优化用户体验布局,而传统Groups模式已被标记弃用。这种分层治理模式(定义层-编排层-展示层)能有效解决传输混乱、升级兼容性问题,尤其适合大规模项目实施。关键在于区分技术配置与业务呈现,避免将所有功能堆砌在单一旧工具中。(149字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 103

Java Web层框架比较—— 比较JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket

<br /> <br />【译者按】这是Matt Raible在今年6月24-27号召开的JA-SIG夏季会议上所作的主题演讲,Matt从众多方面对Java Web层框架做了一个全面、深入的比较。笔者认为这是一份及时的文档,它对开发者如何判定一个Web层框架的好坏、如何选择适合自己项目的框架有极大的指导作用。本文是对Matt Raible演讲稿的整理归纳。 <br />【作者介绍】Matt Raible,开源框架AppFuse的发起者、主要开发者;《Professional JSP 2.0》、《Spring

forever8tf的专栏 1万+

13、使用 Mathematica 撰写文本

本文详细介绍了如何使用 Mathematica 进行文本撰写与处理。内容涵盖文本输入、格式设置、结构化排版、超链接插入、翻译与拼写检查工具的使用,以及将笔记本导出为多种格式(如 PDF、HTML、LATEX 和 RTF)的方法。通过实例演示了创建专业文档的完整流程,包括样式设置、公式推导、标题编号、页眉页脚配置等操作。适合希望利用 Mathematica 编写学术论文、技术报告或教学资料的用户参考。

sony5的博客 208

Wicket 1.5和Tapestry 5比较

Struts框架一度很流行,现在还有很多开发者使用Struts,因为处理遗留代码和投资方面的原因,有更多的开发者已经开始转向使用基于组件的 框架。JSF是最受欢迎的组件框架之一,因为JSF是JCP的一部分,而且得到很多厂商支持。JSF 2.0即将发布,不过本文要讨论的是另外两个基于组件框架:Wicket 1.5和Tapestry 5。   很快,Apache基金会将会发布两个有趣的框架新...

最爱树袋熊 207

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

比较JSF、Spring MVC、Stripes、Struts 2、 Tapestry、Wicket

比较JSF、Spring MVC、Stripes、Struts 2、 Tapestry、Wicket Java Web层框架——JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket他们各自的优点和缺点: JSF 优点: ◆Java EE标准,这意味着有很大的市场需求和更多的工作机会 ◆上手快速并且相对容易 ◆有

flyinglzd2013的专栏 1195

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

比较JSF、Spring MVC、Stripes、Struts 2、Tapestry、Wicket

Java Web层框架——JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket他们各自的优、缺点: JSF 优点: Java EE标准,这意味着有很大的市场需求和更多的工作机会 上手快速并且相对容易 有大量可用的组件库 缺点: 大量的JSP标签 对REST和安全支持不好 没有一个统一的实现。既有SUN的实现,又有Apache的实现——My...

(搬家到)fys-summer.blog.163.com 119

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

比较JSF、Spring MVC、Stripes、Struts 2、Tapestry、Wicket 框架

Java Web层框架——JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket他们各自的优点和缺点: JSF 优点: ◆Java EE标准,这意味着有很大的市场需求和更多的工作机会 ◆上手快速并且相对容易 ◆有大量可用的组件库 缺点: ◆大量的JSP标签 ◆对REST和安全支持不好 ◆没有一个统一的实现。既有SUN的实现,又有Apache的实现——MyFa...

北京堵车王的专栏 200

Java Web框架比较——JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket

<br />Java Web层框架——JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket他们各自的优点和缺点:<br />JSF<br />优点:<br />◆Java EE标准,这意味着有很大的市场需求和更多的工作机会<br />◆上手快速并且相对容易<br />◆有大量可用的组件库<br />缺点:<br />◆大量的JSP标签<br />◆对REST和安全支持不好<br />◆没有一个统一的实现。既有SUN的实现,又有Apache的实现——MyFaces。<

yuanxuegui2008的专栏 2404

比较JSF、Spring MVC、Stripes、Struts2、Tapestry、Wicket

Matt通过采访这些框架的作者,与他们讨论各种开源的Java Web框架,并且突出各个框架的长处、听取框架作者对其他框架的看法,希望借此了解这些框架的未来发展方向。  下列是一些被采访者:  JSF:Jacob Hookom  RIFE:Geert Bevin  Seam:Gavin King  Spring MVC:Rob Harrop  Spring Web Flow:Rob Harrop a

流言簿 - Addyou 1425

Java Web层框架之比较—比较JSF、Spring MVC、Stripes、Struts 2、Tapestry和Wicket

     【译者按】这是Matt Raible在今年6月24-27号召开的JA-SIG夏季会议上所作的主题演讲,Matt从众多方面对Java Web层框架做了一个全面、深入的比较。笔者认为这是一份及时的文档,它对开发者如何判定一个Web层框架的好坏、如何选择适合自己项目的框架有极大的指 导作用。本文是对Matt Raible演讲稿的整理归纳。       【作者介绍】Matt Raible,开源框

Java Coffee Bar 1593
上一篇: UML 设计
下一篇: Velocity 与 FreeMarker
halemyan
博客等级 码龄20年 5粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值