我们的应用程序使用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)
}
}
答案 0 :(得分:7)
依赖项字段不应标记为transient
,它们应沿页面序列化。 wicket-spring
模块将序列化代理注入@SpringBean
- 组件/页面创建时的注释字段,以便可以安全地序列化它们,而无需担心自己序列化依赖项。