我们的应用程序使用 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)
}
}