双击似乎扰乱了Wicket-Spring注入

时间:2012-06-11 17:57:44

标签: spring dependency-injection wicket user-input double-click

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

我们发现我们的一些用户双击链接/按钮就是这样 以某种方式破坏Spring注入,以便后续调用whateverDao.doStuff(obj)抛出N.P.E.这个 应用程序在我们客户的内部网络上运行,目前,我们礼貌地请求了 客户在他们的团队中宣传单击即可处理所有功能。但很明显 这对他们来说是一个问题。

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

此方案涉及最多三个步骤的DAO调用: 1.在搜索页面上,单击项目时,加载该项目的基本详细信息。 2.在只读模式的详细信息页面上,单击编辑时,加载该项目的完整详细信息。 3A。在编辑模式下的详细信息页面上,单击“保存”时,将保留更改。 3B。在编辑模式下的详细信息页面上,单击删除时,删除。

在任何一种情况下,如果用户双击上一个步骤, next 步骤将生成 错误。重现性约为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)
    }
}

1 个答案:

答案 0 :(得分:7)

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