Wicket模型的干净方法
Apache Wicket Web框架的核心概念之一是模型和IModel作為其編程接口。 Wicket組件嚴重依賴模型,這使它們成為體系結構的重要組成部分。 Apache Wicket是一個有狀態框架,將頁面及其組件存儲到通常位于HTTP會話中的頁面存儲中。 組件根據模型的內容創建面向公眾的視圖。 錯誤使用模型可能會導致尷尬的副作用,例如頁面無法更新其內容或應用程序占用大量內存。 從我所看到的情況來看,新的Wicket用戶遇到的最多問題是正確使用模型。 在這篇博客文章中,我將嘗試解釋在不同的用例中應該如何以及使用哪種模型。
Wicket IModel實現中最基本的是Model類。 它基本上是模型內容的簡單占位符。 這非常適合模型內容不占用太多內存且更像是常量的情況。 一個簡單的String可能是Model內容的理想選擇。
IModel<String> name = new Model<String>("John");您必須了解,即使創建包含模型的頁面,創建模型對象時其內容也將保持不變。 此行為是由于使用靜態模型引起的。 每次從模型詢問值時,動態模型都可以更改實際內容。 新的Wicket用戶經常使用靜態模型而不是動態模型。 如果您不清楚靜態模型和動態模型的概念,則應閱讀《 Wicket in Action 》一書中的第4章“了解模型” 。
IModel<Date> date = new Model<Date>() {@Overridepublic Date getObject() {return new Date();} };通過覆蓋getObject()方法,可以從Model創建上述動態日期模型為匿名類。 模型將始終返回包含當前時間的Date的新副本。
Wicket是有狀態的Web框架,模型通常存儲在用戶的HTTP會話中。 模型中的數據很可能是從數據庫或通過某些Web服務獲取的。 如果使用靜態模型方法,則很快將消耗大量內存,并且如果重新加載頁面,將無法從數據源獲得全新視圖。 如果我們決定像對Date對象那樣使用動態模型,則最終可能會在一頁加載中進行大量數據庫搜索或Web服務調用。 匿名內部類也不是很好看的代碼。 Wicket有一個針對此問題的內置解決方案,LoadableDetachableModel可以緩存模型的內容,直到可以安全丟棄為止,從而提供了有效但仍動態的模型。
public class PersonModel extends LoadableDetachableModel<Person> {private Long id;private PersonService personService;public PersonModel(final Long id, final PersonService personService) {super();this.id = id;this.personService = personService;}public PersonModel(final Person person, final PersonService personService) {super(person);this.id = person.getId();this.personService = personService;}@Overrideprotected Person load() {return personService.findById(id);} }上面的示例構造了一個可加載和可拆卸的模型,用于通過其唯一標識符加載一個人。 該模型有兩個構造函數,這是有原因的。 之一來創建在拆卸狀態下的延遲加載模式,將加載內容當getObject()方法被調用第一次,和一個以在安裝狀態的模型,不需要到PersonService呼叫時的getObject()方法是叫。 最好為所有LoadableDetachableModels提供這兩個構造函數。 當您已經擁有內容時,可以在附加狀態下創建模型,或者在只有標識符可用時以分離狀態創建模型。
可裝載可分離模型的警告是模型的私有字段。 Wicket將模型以及組件存儲在頁面存儲中,這可能需要對模型進行序列化。 當模型被序列化時,私有字段也被序列化(實際內容被分離)。 我們的id字段不是問題,因為它是可序列化的,但是PersonService可能是一個問題。 通常,服務層的接口默認情況下是不可序列化的。 至少有兩個不錯的解決方案:使服務可序列化,或者更好的方法是將服務包裝在可序列化的代理中。 代理行為可以例如通過與不同的依賴項注入框架(例如)集成來實現。 春天(wicker-spring)或Guice(wicket-guice)。 集成模塊確保在注入服務代理時將它們可序列化。
public class ProfilePage extends WebPage {@SpringBeanprivate PersonService personService;public ProfilePage(final PageParameters parameters) {super(parameters);Long id = parameters.get("id").toLongObject();IModel<Person> personModel =new PersonModel(id, personService);add(new ProfilePanel("profilePanel", personModel));} }上面的示例使用了wicket-spring集成,將人員服務注入到所需的頁面。 @SpringBean批注提供了一個可序列化的代理,因此,當我們創建人員模型時,我們不必擔心服務的序列化。 Wicket不允許構造函數注入,因為當我們調用super()構造函數時,所有注入魔術實際上都會發生。 這意味著我們在Component的基本構造函數完成之后初始化注入的值。 只需記住對數據使用可序列化的標識符或定位符,對服務使用可序列化的代理。
通常,在MVC Web框架中,視圖層使用某種數據傳輸對象來構建視圖。 DTO組成并繼承以創建不同類型的視圖。 為這些對象建立工廠或映射器可能容易出錯或令人沮喪。 Wicket針對此問題提供了不同的解決方案。 在Wicket中,您可以認為IModel接口的工作方式類似于關系數據庫視圖,允許您以不同方式顯示域的所需部分。
public class PersonFriendsModel extends AbstractReadOnlyModel<String> {private IModel<Person> personModel;public PersonFriendsModel(final IModel<Person> personModel) {super();this.personModel = personModel;}@Overridepublic String getObject() {Person person = personModel.getObject();Iterable<String> friendNames =Iterables.transform(person.getFriends(),new PersonNameFunction());return person.getName()+ "'s friends are "+ Joiner.on(", ").join(friendNames);}@Overridepublic void detach() {personModel.detach();}private class PersonNameFunction implements Function<Person, String> {public String apply(final Person input) {return input.getName();}} }在這里,我們建立一個模型,該模型可以構成我們先前創建的PersonModel。 我們將其用作來源,以建立該人的好友列表。 我們正在擴展的模型是Wicket提供給我們的AbstractReadOnlyModel。 它基本上是普通模型,但不允許設置模型內容。 這非常有道理,因為我們正在構建一個聯接的String,并且解析一個相似的列表并從該列表中設置該人的朋友會很尷尬。 我們僅將此模型用于只讀目的,以在視圖中顯示朋友列表。 您可以在此處看到視圖的類比,我們仍在使用相同的Person域模型,但是在模型的幫助下公開了自定義視圖。 請注意,我們將detach方法委托給了組合模型。 這可以確保,如果我們在任何組件中都沒有直接引用組成的模型,則仍然可以將其與好友模型分離。 多次調用detach()方法無害,因此即使從多個組件中使用也很安全。
我們僅創建了一個簡單的模型合成示例。 您應該探索Wicket的內置模型實現,并花一些時間來研究如何使用它們從領域模型中創建合理的模型。 只需記住一件事:組成和擴展模型,而不是域對象。
我最后要談的是屬性模型。 它們在許多Wicket應用程序中得到了廣泛使用,甚至《 Wicket in Action》一書也鼓勵使用它們,但是它們具有一些不需要的功能。 屬性模型的代碼編寫速度快且易于使用,但是它們使您的代碼成為“字符串類型”。 這是我們不希望使用Java這樣的類型安全語言的東西。
PropertyModel<String> nameModel =new PropertyModel<String>(personModel, "name");我們使用PropertyModel從人的名字創建一個模型。 名稱模型可以使用直接的Person對象或為我們提供人物的IModel。 可以通過實現Wicket的IChainingModel接口來實現此功能。 我們這里有兩個問題。 第一個是名稱模型的類型。 我們定義名稱必須為String,但是實際上編譯器無法確保該名稱已綁定到String getName() JavaBean屬性。 第二個問題來自重構,我們使用String值定義屬性名稱。 如果使用IDE重構Person對象,并將getName()方法掛接到getLastName() ,則應用程序將損壞 ,編譯器將再次無法注意到這一點。
讓我們在這里停留片刻,看看IChainingModel接口。 其主要目的是允許使用普通對象或鏈接模型作為模型的內容。 PropertyModel可以與提供人物的模型或普通人物對象一起使用。 如果查看PropertyModel的源代碼,則會注意到實現IChainingModel需要轉換,而我認為還需要樣板代碼。 可以重構我們先前創建的PersonFriendsModel,以實現IChainingModel,這樣,與其僅采用模型作為內容,還可以直接采用人員。這真的必要嗎? 并不是的。 如果我們要使用普通人,則可以從該人創建一個新的靜態模型,從而為我們提供與IChainingModel提供的功能相同的功能。
CompoundPropertyModel為模型處理增加了更多的魔力。 它是許多組件的根模型,可以通過將屬性名稱與組件ID匹配來自動綁定到該組件。
public class PersonForm extends Form<Person> {public PersonForm(final String id, final IModel<Person> personModel) {super(id, new CompoundPropertyModel<Person>(personModel));add(new TextField<String>("name"));add(new TextField<Integer>("age"));} }在這里,我們創建一個表單以顯示該人的姓名和年齡的輸入字段。 這兩個文本字段均未附加任何模型,但是我們仍然能夠將“名稱”部分綁定到該人的姓名,并將“年齡”部分綁定到該人的年齡。 我們在構造函數中創建的復合屬性模型是表單的根模型,并通過組件ID將表單組件自動綁定到對象的屬性。 復合屬性模型和屬性模型都存在相同的問題,但我們甚至還要添加一個。 現在,我們將組件ID直接鎖定為屬性名稱。 這意味著我們具有從HTML模板到域對象屬性名稱的直接依賴關系。 這聽起來不太合理。
如果要使用屬性模型,則取決于您,但是在我看來,由于前面所述的問題,應避免使用它們。 有諸如bindgen-wicket之類的項目嘗試在不損失類型安全性的情況下實現屬性模型的行為。 但是,即使bindgen在重構中也不能很好地起作用。 我們如何以類型實現名稱模型并以安全的方式重構呢?
public class NameModel implements IModel<String> {private IModel<Person> personModel;public NameModel(final IModel<Person> personModel) {this.personModel = personModel;}@Overridepublic String getObject() {return personModel.getObject().getName();}@Overridepublic void setObject(String object) {personModel.getObject().setName(object);}@Overridepublic void detach() {personModel.detach();} }該模型比屬性模型具有更多的行。 是的,的確如此,但是您是否想失去類型安全性和重構功能,并可能很容易破壞應用程序。 該模型位于不同的文件中,因此您仍然可以將其用作一個襯紙,因此,如果使用屬性模型或我們剛剛創建的模型,則沒有任何區別。 您永遠可以記住Java是非常冗長的語言這一事實??。
Wicket還為我們提供了ResourceModel和StringResourceModel,它們為創建組件的本地化內容提供了強大的工具。 我不會在本文中討論它們,因為《 Wicket in Action》一書對此有很好的參考。 我試圖提出一些現實生活中的示例,說明如何使用不同類型的模型及其目的。 我希望這能給您更多有關Wicket模型以及如何正確使用它們的知識。
翻譯自: https://www.javacodegeeks.com/2013/09/a-clean-approach-to-wicket-models.html
總結
以上是生活随笔為你收集整理的Wicket模型的干净方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国寿周周盈收益怎么算?
- 下一篇: 平安富盈360是不是日复利?