1

我们的应用程序使用 Wicket 前端,使用 Spring 注入来加载我们的 DOA 和管理事务。

我们发现我们的几个用户正在双击链接/按钮,这以某种方式破坏了 Spring 注入,因此对whateverDao.doStuff(obj) 的后续调用会抛出 NPE 此应用程序在我们客户端的内部网络上运行,现在,我们礼貌地要求客户在他们的团队中宣传单击即可使用所有功能。但很明显,这对他们来说正成为一个问题。

一个常见的用例涉及一个“搜索”屏幕,显示当前系统中所有 Foo 对象的列表,如果需要,可以通过搜索参数进行过滤,当单击一个项目时,用户将被带到该特定 Foo 的详细信息页面,最初处于只读模式。接下来,用户可以点击角落的“编辑”按钮切换到编辑模式。然后,用户可能会进行一些更改并单击“保存”(或者可能单击“删除”以删除该项目。)

此场景涉及最多三个步骤的 DAO 调用: 1. 在搜索页面上,当单击项目时,加载该项目的基本详细信息。2. 在只读模式的详情页面,点击编辑时,加载该项目的完整详情。3a。在编辑模式下的详细信息页面上,单击“保存”以保留更改。3b。在编辑模式下的详细信息页面上,当单击删除时,进行删除。

在任何这些情况下,如果用户双击一步,下一步就会产生错误。再现性约为 33%,浏览器和操作系统之间存在一些差异。

关于防止这种情况的任何见解?


在下面的示例中,BasePage 是我们对 Wicket WebPage 的自定义扩展,其中包含我们的菜单和其他常见页面元素,而 PageType 是 CREATE、EDIT 和 READ_ONLY 详细信息的枚举。

搜索页面的示例代码(显示的是 Java,HTML 是您所期望的):

import org.apache.wicket.spring.injection.annot.SpringBean;
// and other imports

public class FooManagerPage extends BasePage {

    @SpringBean
    private transient FooDao fooDao;

    public FooManagerPage() {
        SortableDataProvider<Foo> provider = new SortableDataProvider<Foo>(fooDao);

        add(new FeedbackPanel("feedback");

        final Form<Foo> searchFooForm = new Form<Foo>("searchFooForm",
            new CompoundPropertyModel<Foo>(new Foo()));

        // the form's search parameter's go here
        // with a 'search' button that filters table below

        add(searchFooForm)

        List<IColumn<Foo>> columns = new ArrayList<IColumn<Foo>>();
        columns.add(new PropertyColumn<Foo>(Model.of("Name"), "name", "name"));
        // a couple other columns here

        DataTable fooTable = new AjaxFallbackDefaultDataTable<Foo>("fooTable", columns, provider, 10){
            @Override
            protected Item<Foo> newRowItem(String id, int index, final IModel<Foo> model){
                Item<Foo> item = super.newRowItem(id, index, model);
                item.add(new AjaxEventBehavior ("onclick") {
                    @Override
                    protected void onEvent(AjaxRequestTarget target) {
                        Foo foo = fooDao.load(model.getObject().getId());
                        setResponsePage(new FooViewPage(foo, PageType.READ_ONLY));
                    }
                }); 
                return item;
            }
        };

        add(fooTable);
    }
}

查看页面的示例代码(显示 Java,HTML 是您所期望的)::

// several imports, including Spring Bean
public class FooFormPage extends BasePage {

    @SpringBean
    private transient fooDao fooDao;

    public FooFormPage(final Foo foo, PageType type) {
        Form<Foo> fooForm = new Form<Foo>("fooForm",
            new CompoundPropertyModel<Foo>(foo));

        // all of Foo's input elements go here
        // are enabled or disabled and sometimes invisible based on PageType

        add(fooForm);

        SubmitLink submitButton = new SubmitLink("save", fooForm){
            @Override
            public void onSubmit() {
                super.onSubmit();
                //***** A double click on the Edit button can cause fooDao to be N.P.E. here *****
                fooDao.save(createInitiativeForm.getModelObject().getId());
                changePageType(PageType.VIEW, createFooForm.getModelObject());
            }
        };
        add(submitButton);

        AjaxLink<Void> editButton = new AjaxLink<Void>("edit"){
            @Override
            public void onClick(AjaxRequestTarget target) {
                // reload the item from DB
                //***** A double click on Search Page item will cause fooDao to be N.P.E. here *****
                Foo foo = fooDao.load(fooForm.getModelObject().getId());
                setResponsePage(new FooPage(foo, PageType.EDIT));
            }
        };
        add(editButton);

        // some stuff here that makes save button invisible in READ_ONLY, and Edit visible only in READ_ONLY
        // delete button is similar (visible only in CREATE)
    }
}
4

1 回答 1

7

依赖字段不应标记为transient,它们应沿页面序列化。该wicket-spring模块在组件/页面创建时将可序列化代理注入到@SpringBean带注释的字段中,以便可以安全地序列化它们,而不必担心序列化依赖项本身。

于 2012-06-11T19:06:02.577 回答