wicket_Wicket模型的干净方法
wicket
Apache Wicket Web框架的核心概念之一是模型和IModel作為其編程接口。 Wicket組件嚴重依賴模型,這使它們成為體系結(jié)構(gòu)的重要組成部分。 Apache Wicket是一個有狀態(tài)框架,將頁面及其組件存儲到通常位于HTTP會話中的頁面存儲中。 組件根據(jù)模型的內(nèi)容創(chuàng)建面向公眾的視圖。 錯誤使用模型可能會導致尷尬的副作用,例如頁面無法更新其內(nèi)容或應用程序占用大量內(nèi)存。 從我所看到的,新的Wicket用戶遇到的大多數(shù)問題是正確使用模型。 在這篇博客文章中,我將嘗試解釋在不同的用例中應如何以及應使用哪種模型。
Wicket IModel實現(xiàn)中最基本的是Model類。 它基本上是模型內(nèi)容的簡單占位符。 這非常適合模型內(nèi)容不占用太多內(nèi)存并且更像是常量的情況。 一個簡單的String可能是Model內(nèi)容的理想選擇。
IModel<String> name = new Model<String>("John");您必須了解,即使創(chuàng)建包含模型的頁面,創(chuàng)建模型對象時其內(nèi)容也將保持不變。 此行為是由于使用靜態(tài)模型引起的。 每次從模型詢問值時,動態(tài)模型都可以更改實際內(nèi)容。 新的Wicket用戶經(jīng)常使用靜態(tài)模型而不是動態(tài)模型。 如果您不清楚靜態(tài)模型和動態(tài)模型的概念,則應閱讀《 Wicket in Action 》一書中的第4章“了解模型” 。
IModel<Date> date = new Model<Date>() {@Overridepublic Date getObject() {return new Date();} };上面的動態(tài)日期模型是通過重寫getObject()方法從Model創(chuàng)建為匿名類的。 模型將始終返回包含當前時間的Date的新副本。
Wicket是有狀態(tài)的Web框架,模型通常存儲在用戶的HTTP會話中。 模型中的數(shù)據(jù)很可能是從數(shù)據(jù)庫或通過某些Web服務獲取的。 如果使用靜態(tài)模型方法,我們將很快吞噬大量內(nèi)存,并且如果重新加載頁面,將無法從數(shù)據(jù)源獲得全新的視圖。 如果我們決定像對Date對象那樣使用動態(tài)模型,則最終可能會在一頁加載內(nèi)進行大量數(shù)據(jù)庫搜索或Web服務調(diào)用。 匿名內(nèi)部類也不是很好看的代碼。 Wicket有一個針對此問題的內(nèi)置解決方案,LoadableDetachableModel可以緩存模型的內(nèi)容,直到可以安全丟棄為止,從而提供了有效但仍動態(tài)的模型。
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);} }上面的示例構(gòu)造了一個可加載和可拆卸的模型,用于通過其唯一標識符加載一個人。 該模型有兩個構(gòu)造函數(shù),這是有原因的。 之一來創(chuàng)建在拆卸狀態(tài)下的延遲加載模式,將加載內(nèi)容當getObject()方法被調(diào)用第一次,和一個以在安裝狀態(tài)的模型,不需要到PersonService呼叫時的getObject()方法是叫。 最好為所有LoadableDetachableModels提供這兩個構(gòu)造函數(shù)。 您可以在已擁有內(nèi)容的情況下以附加狀態(tài)創(chuàng)建模型,或者在只有標識符可用時以分離狀態(tài)創(chuàng)建模型。
可裝載可分離模型的警告是模型的私有字段。 Wicket將模型和組件一起存儲在頁面存儲中,這可能需要對模型進行序列化。 當模型被序列化時,私有字段也被序列化(實際內(nèi)容被分離)。 我們的id字段不是問題,因為它可以序列化,但是PersonService可能是問題。 通常,服務層的接口默認情況下是不可序列化的。 至少有兩種不錯的解決方案:使服務可序列化,或者更好的方法是將服務包裝在可序列化的代理中。 代理行為可以例如通過與不同的依賴項注入框架(例如)集成來實現(xiàn)。 春天(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批注提供了一個可序列化的代理,因此,當我們創(chuàng)建人員模型時,我們不必擔心服務的序列化。 Wicket不允許構(gòu)造函數(shù)注入,因為當我們調(diào)用super()構(gòu)造函數(shù)時,所有注入魔術(shù)實際上都會發(fā)生。 這意味著我們在Component的基本構(gòu)造函數(shù)完成之后初始化注入的值。 只需記住對數(shù)據(jù)使用可序列化的標識符或定位符,對服務使用可序列化的代理。
通常,在MVC Web框架中,視圖層使用某種數(shù)據(jù)傳輸對象來構(gòu)建視圖。 DTO組成并繼承以創(chuàng)建不同類型的視圖。 為這些對象建立工廠或映射器可能容易出錯或令人沮喪。 Wicket針對此問題提供了不同的解決方案。 在Wicket中,您可以認為IModel接口的工作方式類似于關(guān)系數(shù)據(jù)庫視圖,該視圖允許您以不同的方式顯示域的所需部分。
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();}} }在這里,我們構(gòu)建了一個模型,該模型可以構(gòu)成我們先前創(chuàng)建的PersonModel。 我們將其用作來源,以建立該人的好友列表。 我們正在擴展的模型是Wicket提供給我們的AbstractReadOnlyModel。 它基本上是普通模型,但不允許設置模型內(nèi)容。 這非常有道理,因為我們正在構(gòu)建一個連接的String,并且解析一個相似的列表并從該列表中設置該人的朋友會很尷尬。 我們僅將此模型用于只讀目的,以在視圖中顯示朋友列表。 您可以在此處看到類似的視圖,我們?nèi)栽谑褂孟嗤腜erson域模型,但是在模型的幫助下從中公開了一個自定義視圖。 請注意,我們將detach方法委托給了組合模型。 這可以確保,如果我們在任何組件中都沒有直接引用組成的模型,則仍然可以將其與好友模型分離。 多次調(diào)用detach()方法無害,因此即使從多個組件中使用也很安全。
我們僅創(chuàng)建了一個簡單的模型合成示例。 您應該探索Wicket的內(nèi)置模型實現(xiàn),并花一些時間來研究如何使用域模型來創(chuàng)建合理的模型。 只需記住一件事:組成和擴展模型,而不是域?qū)ο蟆?
我最后要談的是屬性模型。 它們在許多Wicket應用程序中得到了廣泛使用,甚至《 Wicket in Action》一書也鼓勵使用它們,但是它們具有一些不需要的功能。 屬性模型的代碼編寫速度快且易于使用,但是它們使您的代碼成為“字符串類型”。 這是我們不希望使用Java這樣的類型安全語言的東西。
PropertyModel<String> nameModel =new PropertyModel<String>(personModel, "name");我們使用PropertyModel從人的名字創(chuàng)建一個模型。 名稱模型可以使用直接的Person對象或為我們提供人物的IModel。 可以通過實現(xiàn)Wicket的IChainingModel接口來實現(xiàn)此功能。 我們這里有兩個問題。 第一個是名稱模型的類型。 我們定義名稱必須為String,但實際上編譯器無法確保該名稱已綁定到String getName() JavaBean屬性。 第二個問題來自重構(gòu),我們使用String值定義屬性名稱。 如果使用IDE重構(gòu)Person對象,并將getName()方法掛接到getLastName() ,則應用程序?qū)p壞 ,編譯器將再次無法注意到這一點。
讓我們在這里停留片刻,看看IChainingModel接口。 其主要目的是允許使用普通對象或鏈接模型作為模型的內(nèi)容。 PropertyModel可以與提供人物的模型或普通人物對象一起使用。 如果查看PropertyModel的源代碼,則會注意到實現(xiàn)IChainingModel需要轉(zhuǎn)換,而我認為還需要樣板代碼。 可以重構(gòu)我們先前創(chuàng)建的PersonFriendsModel,以實現(xiàn)IChainingModel,這樣,與其僅采用模型作為內(nèi)容,它還可以支持直接采用人員。這真的有必要嗎? 并不是的。 如果我們要使用普通人,則可以從該人創(chuàng)建一個新的靜態(tài)模型,從而為我們提供與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"));} }在這里,我們創(chuàng)建一個表單以顯示該人的姓名和年齡的輸入字段。 這兩個文本字段均未附加任何模型,但是我們?nèi)匀荒軌驅(qū)ⅰ懊Q”部分綁定到該人的姓名,并將“年齡”部分綁定到該人的年齡。 我們在構(gòu)造函數(shù)中創(chuàng)建的復合屬性模型是表單的根模型,并通過組件ID將表單組件自動綁定到對象的屬性。 復合屬性模型和屬性模型都存在相同的問題,但我們甚至還要添加一個。 現(xiàn)在,我們將組件ID直接鎖定為屬性名稱。 這意味著我們具有從HTML模板到域?qū)ο髮傩悦Q的依賴關(guān)系。 這聽起來不太合理。
如果要使用屬性模型,則取決于您,但是在我看來,由于前面所述的問題,應避免使用它們。 有諸如bindgen-wicket之類的項目嘗試在不損失類型安全性的情況下實現(xiàn)屬性模型的行為。 但是,即使bindgen在重構(gòu)中也無法很好地起作用。 我們?nèi)绾我砸环N類型實現(xiàn)名稱模型并以安全的方式重構(gòu)呢?
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();} }該模型比屬性模型具有更多的行。 是的,的確如此,但是您是否想失去類型安全性和重構(gòu)功能,并可能很容易破壞應用程序。 該模型位于不同的文件中,因此您仍然可以將其用作一個襯紙,因此,如果使用屬性模型或我們剛剛創(chuàng)建的模型,則沒有任何區(qū)別。 您永遠可以記住Java是非常冗長的語言這一事實??。
Wicket還為我們提供了ResourceModel和StringResourceModel,它們提供了為組件創(chuàng)建本地化內(nèi)容的強大工具。 我不會在本文中討論它們,因為《 Wicket in Action》一書對此有很好的參考。 我試圖提出一些現(xiàn)實生活中的示例,說明如何使用不同類型的模型以及它們的目的是什么。 我希望這能給您更多有關(guān)Wicket模型以及如何正確使用它們的知識。
翻譯自: https://www.javacodegeeks.com/2013/09/a-clean-approach-to-wicket-models.html
wicket
總結(jié)
以上是生活随笔為你收集整理的wicket_Wicket模型的干净方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Azure Blob存储托管Mave
- 下一篇: 电脑放静电怎么放(电脑放静电脑怎么放静电