Wicket啓示錄——理論與實踐(三)完

接下來,我們再看看EditContact類,把新建聯繫人的話和編輯聯繫人也給實現了,開始吧:

 

public class EditContact extends BasePage {

    public EditContact() {
        setModel(new CompoundPropertyModel(new LoadableDetachableModel() {
            protected Object load() {
                return new Contact();
            }
        }));
        init();
    }

    public EditContact(final Long contactId) {
        setModel(new CompoundPropertyModel(new LoadableDetachableModel() {
            protected Object load() {
                return WicketApplication.get().getContactDao().get(contactId);
            }
        }));
        init();
    }

    private void init() {
        add(new FeedbackPanel("feedback"));
        add(new ContactForm("form", getModel()));
    }

    private class ContactForm extends Form {

        public ContactForm(String id, IModel m) {
            super(id, m);

            TextField firstName = new TextField("firstName");
            firstName.setRequired(true);
            firstName.add(StringValidator.maximumLength(15));
            add(firstName);

            TextField lastName = new TextField("lastName");
            lastName.setRequired(true);
            lastName.add(StringValidator.maximumLength(20));
            add(lastName);

            TextField email = new TextField("email");
            email.add(StringValidator.maximumLength(150));
            email.add(EmailAddressValidator.getInstance());
            add(email);

            TextArea notes = new TextArea("notes");
            notes.add(StringValidator.maximumLength(500));
            add(notes);

            DropDownChoice group = new DropDownChoice("group");
            group.setChoices(new AbstractReadOnlyModel() {
                public Object getObject() {
                    List<String> l = new ArrayList<String>(3);
                    l.add("Friend");
                    l.add("Co-Worker");
                    l.add("Nemesis");
                    return l;
                }
            });
            add(group);

            add(new Button("save") {
                public void onSubmit() {
                    Contact c = (Contact) getForm().getModelObject();
                    WicketApplication.get().getContactDao().save(c);
                    setResponsePage(ListContacts.class);
                }
            });
            add(new Button("cancel") {
                public void onSubmit() {
                    setResponsePage(ListContacts.class);
                }
            }.setDefaultFormProcessing(false));
        }
    }
}

 

EditContact類的兩個構造函數就可以搞定編輯功能。第一個構造函數不帶任何參數,目的是用來創建一個新的聯繫人。即使是新建一個新實體,這裏我們仍然可以使用LoadableDetachableModel類來返回一個new Contact。因爲當page存儲在PageMap中時,LoadableDetachableModel會確保CompoundPropertyModel不去serialize (序列化)一個數據庫中不存在的對象。因此,在這裏對要新建的對象設置一些默認值是非常不錯的選擇,比如我們可以對Contact設置一個默認的Group。

 

第二個構造函數將Contact的主鍵id作爲參數,從數據庫讀取該對象後,進行相應的編輯操作。構造函數裏還調用了init()方法。該方法很簡單,加入了一個FeedbackPanel組件,並且將得到的Contact模型綁定到Form上去。FeedbackPanel是Wicket的一個消息反饋組件,比如說如果用戶沒有輸入用戶名,那麼後臺就會將錯誤信息通過它來顯示到前臺頁面上。用法與其它組件一樣,在markup文件標記下:

 

 

<span wicket:id="feedback"></span>

 

 

任何驗證錯誤信息都可以通過HTML的<span>元素顯示出來.你可以反饋你更希望使用什麼風格顯示你的錯誤信息,但那是後話了.

 

看看Contact的firstName屬性所對應的TextField組件設置:

 

TextField firstName = new TextField("firstName");
firstName.setRequired(true);
firstName.add(StringValidator.maximumLength(15));
add(firstName);

 

看到了嗎,我們在這裏設置了Contact的firstName屬性所對應的TextField輸入的字符串長度不能超過15.別的組件也用了類似的驗證,原理是一樣的.最後還有一個需要注意的組件是DropDownChoice.它專門用來顯示HTML的select元素.在我們的例子中,通過使用DropDownChoice的setChoices()方法將我們Contact的group屬性列表值顯示在HTML上了:

 

 

DropDownChoice group = new DropDownChoice("group");
group.setChoices(new AbstractReadOnlyModel() {
    public Object getObject() {
        List<String> l = new ArrayList<String>(3);
        l.add("Friend");
        l.add("Co-Worker");
        l.add("Nemesis");
        return l;
    }
});

 

 

 

上面代碼中用到的AbstractReadOnlyModel也是IModel的實現之一,將返回的String列表填充到select元素的option中去,生成的HTML片斷如下:

 

 

<select>
    <option value="Friend">Friend</option>
    <option value="Co-Worker">Co-Worker</option>
    <option value="Nemesis">Nemesis</option>
</select>

 

 

 

上的例子有點簡單,其實DropDownChoice在IChoiceRenderer的幫助下,也可以支持很豐富的自定義對象,那麼我也演示一下吧:

 

 

public class Group {
    private String name;

    public Group(String name) {
        setName(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

 

 

 

好的,我們將原來的代碼改動一下,請注意看下面:

 

DropDownChoice group = new DropDownChoice("group");
group.setChoices(new AbstractReadOnlyModel() {
    public Object getObject() {
        List<Group> l = new ArrayList<Group>(3);
        l.add(new Group("Friend"));
        l.add(new Group("Co-Worker"));
        l.add(new Group("Nemesis"));
        return l;
    }
});
group.setChoiceRenderer(new IChoiceRenderer() {
    public Object getDisplayValue(Object o) {
        Group g = (Group) o;
        return g.getName();
    }
    public String getIdValue(Object o) {
        Group g = (Group) o;
        return g.getName();
    }
});

 

IChoiceRenderer接口允許開發人員決定select元素的option中text,value屬性分別是什麼.如果你先前用過其它web框架的select元素列表,你會發現Wicket做的比其它都要棒。

 

最後是兩個Button組件:

 

 


add(new Button("save") {
    public void onSubmit() {
        Contact c = (Contact) getForm().getModelObject();
        WicketApplication.get().getContactDao().save(c);
        setResponsePage(ListContacts.class);
    }
});
add(new Button("cancel") {
    public void onSubmit() {
        setResponsePage(ListContacts.class);
    }
}.setDefaultFormProcessing(false));

 

 

第一個button是用來保存contact模型後跳轉到ListContacts頁面.第二個button是用來取消對contact模型的編輯,直接跳轉回ListContacts頁面.兩個button的不同之處在於,除了兩個不同的onSubmit()行爲事件外,還對cancel button調用setDefaultFormProcessing(false)方法,這樣當單擊cancel button後,不會執行Form體代碼,即上述那些驗證,更新Contact模型的操作全部跳過,直接返回ListContacts頁面.當單擊submit button後,Wicket會經過以下幾個步驟:

 

l         進行輸入驗證

l         如果輸入有效,就將輸入值更新相應的模型對象.

l         執行onSubmit()方法.

 

 

如果你不想處更新型對象,不想進行什麼驗證.那好,爲你的form加上一個cancel button,非常簡單,不需要什麼複雜的邏輯處理.

 

EditContact類也看完了,最後再看一遍相應的markup文件.這一回,你再看markup文件,應該不吃力了吧:

 

<wicket:extend>
    <span wicket:id="feedback"></span>

    <form wicket:id="form">
        <div id="contacts">
            <div class="contact">
                <table>
                    <tr>
                        <td>
                            First Name
                        </td>
                        <td>
                            <input wicket:id="firstName" type="text"/>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Last Name
                        </td>
                        <td>
                            <input wicket:id="lastName" type="text"/>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Email
                        </td>
                        <td>
                            <input wicket:id="email" type="text" size="40"/>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Notes
                        </td>
                        <td>
                            <textarea wicket:id="notes" rows="4" cols="40"></textarea>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            Group
                        </td>
                        <td>
                            <select wicket:id="group"> </select>
                        </td>
                    </tr>
                    <tr>
                        <td colspan="3" align="center">
                            <input wicket:id="save" type="submit" value="Save"/>
                            <input wicket:id="cancel" type="submit" value="Cancel"/>
                        </td>
                    </tr>
                </table>
            </div>
        </div>
    </form>
</wicket:extend>

 

 

wicket:id屬性加上HTML元素就可完全符號我們的Wicket組件.用戶只要填寫form表單,單擊save button就可以創建或更新他的聯繫人;如果想取消的話,單擊cancel按鈕,就可以放棄所做的修改,回到聯繫人列表.

 

這樣完整的實例爲我們揭示了Apache的Wicket框架.雖然我們談的比較基礎,但所有的一切完全可以應用到你的Wicket web應用程序中去.

 

總結

 

文章已經向你介紹了Wicket的核心概念,並且通過一個完整的實例幫助你鞏固它們.致使Wicket成功的核心概念其實就是組件和模型.

 

組件就是獨立的Java代碼塊和與它配對的markup文件.大多數組件被設計成抽象類,你可以擴展相應的子類,來滿足你的領域特定邏輯和需求,如上面用到的Page, Panel, Link, Form和ListView都是如此.

 

 

模型作爲領域對象與Wicket組件之間的橋樑.模型可以有很多特性,可以最大化功能化.理想情況下,你的組件應該永遠通過模型來訪問你的領域對象.

 

我希望你們會喜歡這篇文章,並且它使得你願意研究Wicket的更多細節,我覺得我已經找到了一個非常具備高效生產力的框架.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章