私たちのアプリケーションは Wicket フロントエンドを使用し、Spring インジェクションを使用して DOA をロードし、トランザクションを管理します。
何人かのユーザーがリンク/ボタンをダブルクリックしており、これが何らかの形で Spring インジェクションを妨害していることを発見しました。そのため、その後のwhateverDao.doStuff(obj) への呼び出しで NPE がスローされます。このアプリケーションは、クライアントの内部ネットワークで実行され、今のところ、ワンクリックですべての機能が機能することをチーム内で広めるよう、クライアントに丁寧に依頼しました。しかし、これが彼らにとって問題になりつつあることは明らかです。
一般的なユースケースには、現在システム内にあるすべての Foo オブジェクトのリストを表示する「検索」画面が含まれます。これは、必要に応じて検索パラメーターを使用してフィルター処理できます。アイテムをクリックすると、ユーザーはその特定の Foo の詳細ページに移動します。 、最初は読み取り専用モードです。次に、ユーザーは隅にある「編集」ボタンをクリックして、編集モードに切り替えることができます。次に、ユーザーはいくつかの変更を加えて [保存] をクリックします (または、[削除] をクリックしてアイテムを削除することもできます)。
このシナリオには、最大 3 つのステップでの DAO 呼び出しが含まれます。 1. 検索ページで、アイテムがクリックされたときに、そのアイテムの基本的な詳細をロードします。2. 読み取り専用モードの詳細ページで、[編集] をクリックすると、そのアイテムの完全な詳細が読み込まれます。3a. 編集モードの詳細ページで、[保存] をクリックすると、変更が保持されます。3b. 編集モードの詳細ページで、削除をクリックすると削除されます。
これらのいずれの場合でも、ユーザーが前のステップをダブルクリックすると、次のステップでエラーが発生します。再現性は、ブラウザや OS によって多少のばらつきがありますが、約 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)
}
}