wicket_Wicket模型的干净方法

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模型以及如何正确使用它们的知识。

参考:来自RAINBOW WORLDS博客的JCG合作伙伴 Tapio Rautonen 对Wicket模型的一种干净方法 。

翻译自: https://www.javacodegeeks.com/2013/09/a-clean-approach-to-wicket-models.html

wicket

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/347748.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机二级web题目(8.2)--基本操作题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1.在考生文件夹下的Web1目录中&#xff0c;存有1.htm文件&#xff0c;该文件不完…

java的选项板_CAD工具选项板的介绍以及新建方法

CAD中的工具选项板是【工具选项板】窗口中选项卡形式的区域&#xff0c;不但能提供组织、共享和放置块及填充图案的很有效的方法&#xff0c;还能够包含由第三方开发人员提供的自定义工具。【工具选项板】窗口包括注释、建筑、机械、电力、图案填充和土木工程等选项板。当需要向…

摆脱“空”检查的盛宴:使用JSON Patch正确执行PATCH

今天&#xff0c;我们将就REST&#xff08;ful&#xff09;服务和API进行一次对话&#xff0c;更准确地说&#xff0c;围绕许多经验丰富的开发人员正在努力解决的一个独特主题。 为了使事情更直观&#xff0c;我们将讨论Web API&#xff0c;其中REST&#xff08;ful&#xff09…

Java面向对象(5)--类的成员构造器(构造方法)

创建对象&#xff1b;给对象进行初始化。 ①隐式无参构造器&#xff08;没有创建时&#xff0c;系统默认提供的&#xff09; ②显式定义一个或多个构造器&#xff08;无参、有参&#xff09; 基本格式 修饰符 类名 (参数列表) {初始化语句&#xff1b; }特征 ①它具有与类相…

java单链表 提供增删改查_java实现单链表增删改查的实例代码详解

package 数据结构算法.链表;/**定义节点* 链表由节点构成*/public class node {private e e; //数据dataprivate node next; //指向下一个节点public node() {}public node(e e) {this.e e;}public node getnext() {return next;}public void setnext(node next) {this.next …

Java面向对象(6)--this关键字使用

this可理解为:当前对象或当前正在创建的对象 ①在类的方法中&#xff0c; 我们可以使用"this.属性"或"this.方法"的方式&#xff0c;调用当前对象属性或方法。通常情况下&#xff0c;我们都选择省略"this."。特殊情况下&#xff0c;如果方法的形…

spring 4.3.x_如何在Spring 3.x中使用事件

spring 4.3.x创建松耦合应用程序的概念和技术很多&#xff0c;Event是其中之一。 事件可以消除代码中的许多依赖关系。 有时没有事件&#xff0c;很难实施SRP *。 Java中的Observable接口可以帮助我们实现事件&#xff08;通过Observer Pattern&#xff09;。 但是&#xff0c…

java接口安全怎么处理_Restful API 接口安全性设计

1.API接口设计规范2.安全性设计a.白名单限制仅接受特定系统的请求响应&#xff0c;调用方的IP地址需要在本系统中报备&#xff0c;否则无法调用b.合法身份合法性验证Basic Authentication :这种方式是直接将用户名和密码放到Header中&#xff0c;使用 Authorization: Basic Zm9…

使用Spring开发Java RESTful Web服务的7个理由

REST现在已成为开发Web服务的标准方法&#xff0c;涉及Java时&#xff0c;可以使用许多框架和库&#xff0c;例如JAX-RS&#xff0c;Restlet&#xff0c;Jersey&#xff0c;RESTEasy&#xff0c;Apache CFX等&#xff0c;但是我鼓励Java开发人员使用Spring框架来开发Java。开发…

Java面向对象(7)--package和import关键字

package关键字 ①为了更好的实现项目中类的管理&#xff0c;提供包的概念 ②使用package声明类或接口所属的包&#xff0c;声明在源文件的首行 ③包&#xff0c;属于标识符&#xff0c;遵循标识符的命名规则、规范( xxxyyyzzz) ④每"."一次&#xff0c;就代表一层文…

java圆形排列_位图排序java版

1、《编程珠玑》第一章第一题就相当的精彩&#xff0c;做个笔记。题目如下&#xff1a;输入: 一个包含n个正整数的文件&#xff0c;每个正整数小于n,n等于10的7次方(一千万)。并且文件内的正整数没有重复和关联数据。输出: 输入整数的升序排列约束&#xff1a; 限制在1M左右…

(3.1)HarmonyOS鸿蒙单击事件4种写法

第二种和第四种常用 实现步骤: 1.通过id找到组件。 2.给需要的组件设置单击事件。 3.实现ClickedListener接口。 4.重写onClicked方法。 第一种&#xff0c;自定义实现类&#xff08;在当前类外面写实现类&#xff09; ①MainAbilitySlice.java文件 package com.example.yem…

JSON指针:JSON-P 1.1概述系列

Java EE 8包括对JSON处理API的更新&#xff0c;并使其与JSON的最新IEFT标准保持同步。 他们是&#xff1a; JSON指针 &#xff08;RFC 6901&#xff09; JSON修补程序&#xff08;RFC 6902&#xff09; JSON合并补丁&#xff08;RFC 7396&#xff09; 我将在这个迷你系列中…

Java获取oracle字段注释_java读取ORACLE数据库表字段信息以及注释信息

最近在做编程工具&#xff0c;便于快速开发程序&#xff0c;用过太多框架&#xff0c;但是发觉只有自己制作代码工具才开发起来痛快。这个类是用来读取oracle数据库表结构的&#xff0c;也包括列的注释&#xff0c;对于生成代码有很好的帮助。1.[文件] OracleTable.java ~ 3KB …

(3.2)HarmonyOS鸿蒙双击事件

跟单击事件类似&#xff0c;双击事件也有4种写法&#xff0c;这里采用当前类作为实现类这种写法&#xff0c;其他写法可以参见《单击事件的4种写法》。不同的是双击事件需要的是Component.DoubleClickedListener。 实现步骤: 1.通过id找到组件。 2.给需要的组件设置双击事件。…

java文件和xml文件_用Java分割大型XML文件

java文件和xml文件上周&#xff0c;我被要求用Java编写一些东西&#xff0c;该东西能够将一个30GB的XML文件拆分为可配置文件大小的较小部分。 文件的使用者将是一个中间件应用程序&#xff0c;该应用程序在XML的大尺寸方面存在问题。 在幕后&#xff0c;它使用某种DOM解析技术…

oracle java 并发_【转】JAVA并发教程(ORACLE官网资料)

本文是Oracle官方的Java并发相关的教程&#xff0c;感谢并发编程网的翻译和投递。计算机的使用者一直以为他们的计算机可以同时做很多事情。他们认为当其他的应用程序在下载文件&#xff0c;管理打印队列或者缓冲音频的时候他们可以继续在文字处理程序上工作。甚至对于单个应用…

(3.3)HarmonyOS鸿蒙长按事件

跟单击事件类似&#xff0c;长按事件也有4种写法&#xff0c;这里采用当前类作为实现类这种写法&#xff0c;其他写法可以参见《单击事件的4种写法》。 实现步骤: 1.通过id找到组件。 2.给需要的组件设置长按事件。 3.本类实现LongClickedListener接口。 4.重写onLongClicked方…

部署Spring Boot Angular App(Maven和Tomcat)的4种方法

在上一篇有关Spring Boot angular 5的文章中 &#xff0c;我们使用Spring Boot angular 5实现了一个完整的堆栈端到端Web应用程序。在本文中&#xff0c;我们将讨论在tomcat上部署Spring Boot和Angle App的不同方法。 我们将创建一个具有后端&#xff08;服务器&#xff09;和前…

java中true转换为int_在Java中将字节转换为int的最优雅的方式

示例代码&#xff1a;int a 255;byte b (byte) a;int c b & 0xff; // Here be dragonsSystem.out.println(a);System.out.println(b);System.out.println(c);所以我们从一个整数值255开始&#xff0c;将它转换成一个字节(变为-1)&#xff0c;然后使用魔术公式将其转换成…