Hibernate 3.2 终于发布了正式版本。
此次发布的最大亮点就是,Hibernate 3.2 获得了Sun TCK 的JPA(Java Persistence API) 兼容认证。
Hibernate 3.2 新版本中主要提升包括:
Hibernate Core:具备完整功能、以及优秀性能的ORM 持久层映射核心。Hibernate 可以帮助开发者节省持久层编码时间,有助于OO的设计。Hibernate Core 需要JDK1.3 以上或者支持J2EE 1.4、Java EE 5.0 的应用服务器。
Hibernate Annotation:Hibernate Annotation 提供了JDK 5.0 代码标注的功能,从而替代XML 元数据。通过使用Hibernate Annotation ,能够减少描述符,编译期校验,以及减少配置和维护工作等。
Hibernate EntityManager:Hibernate EntityManager 实现了Java 持久化编程接口,对象生命周期法则,以及JSR 220 (EJB 3.0) 定义的查询选项。
发掘 Groovy 如何将您解放出来,得以专注于编码的重要方面
2006 年 10 月 17 日
Groovy 简洁的语法将开发人员从那种需要进行代码编译但却无助于表达 什么 是程序真正想要实现的典型的 Java 结构中解放了出来。在实战 Groovy 系列的这一复兴篇中,Groovy 开发人员兼特约专栏作家 J. Scott Hickey 带您进行一系列对常规 Java 代码和 Groovy 代码的比较,展示这门令人兴奋的语言如何将您解放出来,让您能够专注于编码的重要方面。
通常,程序员们转而选择诸如 Groovy 之类的编程语言,是为了构建快速的实用程序,快速编写测试代码,甚至创建构成大型的 Java 应用程序的组件,而 Groovy 先天具有这样一种能力,它能够减少传统的基于 Java 系统所固有的许多冗余并降低其复杂度。Groovy 简洁而灵活的语法将开发人员从那种需要进行代码编译却无助于表达什么 是程序真正想要实现的典型的 Java 结构中解放出来。不仅如此,Groovy 轻松的类型通过减少一些接口和超类使代码不再复杂,这些接口和超类都是常规 Java 应用程序用以支持不同具体类型间的通用行为所需的。
为了举例说明 Groovy 如何减少 Java 应用程序所涉及的无用数据,我将使用 Bruce Tate 和 Justin Ghetland 的 Spring: A Developer's Notebook(参见 参考资料) 中的样例代码,该书介绍了如何使用 Spring 进行控制反转。每当回顾一个 Java 样例,我都会将其与实现相同功能的相应的 Groovy 源代码进行比较,您将很快发现 Groovy 通过减少 Java 编程的不同方面(冗余且不必要地传递了应用程序的行为)而使应用程序代码变得多么地清晰。
在 Bruce 和 Justin 这本书的第一章中,创建了一个简单的自行车商店应用程序,其中包含有四个类。首先,我将向您展示一个简单的名为 Bike 的 JavaBean 类,该类代表了一辆库存的自行车。然后,我会考查自行车商店的类型,名为 RentABike。它包含了一个 Bike 集。还有一个命名为 CommandLineView 的用于显示自行车列表的类,该类依赖于 RentABike 类型。最后,有一个用于集成这些部分以创建工作应用程序的类,该类利用 Spring 来传递完整地配置了 RentABike 类型的 CommandLineView 类 —— 免去了复杂的硬编码。
清单 1 中一个代表自行车的类在常规 Java 代码中被实现为一个简单的 JavaBean,它是 Java 开发人员可能已经编写好的成百上千的类的一个典型。通常来说,JavaBean 并没有什么特殊之处 —— 其属性被声明为 private,且可通过 public getter 和 setter 对其进行访问。
清单 1. Java 代码中的 Bike JavaBean
|
清单 1 是一个只有一个构造方法和六个属性的小例子,但其代码却填满了浏览器的整个页面!清单 2 显示了在 Groovy 中定义的相同的 JavaBean:
清单 2. Bike GroovyBean
|
您认为哪一个没那么多冗余呢?
Groovy 版的代码要少很多很多,这是因为 Groovy 的默认属性语义用 public 访问器和存取器自动定义了 private 域。例如,上述 model 属性现在有了自动定义的 getModel() 方法和 setModel() 方法。可以看到,这项技术的好处是,不必在一种类型中按照属性手工定义两个方法!这也解释了 Groovy 中的一条反复强调的定律:使普通的编码规则变得简单。
|
另外,在 Groovy 中,类的默认函数表达得更为简洁,而在常规 Java 代码(如 清单 1)中该函数必须显式编码。当需要用构造函数或 getter 或 setter 来完成一些特殊任务时,Groovy 真的很出色,因为只需瞥一眼代码,其精彩的行为就会立即变得十分明显。例如,在 清单 2 中很容易看出,setCost() 方法会将 cost 属性换算为三个十进制的位。
将这段不太显眼的 Groovy 代码同 清单 1 中的 Java 源代码进行比较。第一次阅读这段代码时,您注意到 setCost() 方法中嵌入了特殊的函数了吗?除非仔细观察,否则太容易看漏了!
清单 3 中 Bike 类的测试用例展示了如何使用自动生成的访问器。同时,出于进一步简化通用编程任务的考虑,测试用例也使用了更为简便的 Groovy 点属性名 标记来访问属性。相应地,能够通过 getModel() 方法或更为简洁的 b.model 形式来引用 model 属性。
清单 3. Groovy 中的 Bike 测试用例
|
也注意到在上述 Groovy 例子中,不必定义一个如 清单 1 中定义的 Java 构造函数那样的能够接受全部六个属性的构造函数。同时,也不必要创建另一个 只含两个参数的构造函数来支持测试用例 —— 在对象创建过程中设置对象属性的 Groovy 的语义不需要这种冗余、烦人的构造函数(它们综合有多个参数但其作用却只是初始化变量)。
|
在前面的部分中,Bike GroovyBean 利用了 Groovy 的属性和构造语义以减少源代码中的冗余。在这一部分中,Groovy 版的自行车商店也将受益于额外的冗余减少特性,如针对多态的 duck-typing、集合类的改进及操作符重载。
在 Java 自行车应用程序中,名为 RentABike 的接口是用来定义由自行车商店支持的 public 方法的。正如在清单 4 中说明的那样,RentABike 定义了一些简单的方法,这些方法用来返回商店中单个的 Bike 或所有 Bike 的列表。
清单 4. 由 Java 定义的 RentABike 接口
|
此接口允许多态行为并在下面两种重要情况下提供了灵活性。其一,如果要决定将实现由 ArrayList 转变为数据库形式,余下的应用程序与该变化是隔绝的。其二,使用接口为单元测试提供灵活性。例如,如果要决定为应用程序使用数据库,可以轻易地创建一个该类型的模拟实现,而且它不依赖于实时数据库。
清单 5 是 RentABike 接口的 Java 实现,它使用 ArrayList 来存储多个 Bike 类:
清单 5. RentABike 接口的 Java 实现
|
现在将 清单 4 和 5 中的 Java 代码同 清单 6 中的 Groovy 代码进行比较。Groovy 版的代码很灵巧地避免了对 RentABike 接口的需求。
清单 6. Groovy 的 ArrayListRentABike 实现
|
Groovy 像其他动态语言(如 Smalltalk 或 Ruby)一样支持具有 “duck typing” 的多态 —— 在运行时,如果一个对象表现得像个 duck ,它就会被视为 duck ,从而支持无 接口的多态。有了 Groovy ArrayListRentABike 实现,不但减少了成行的代码,而且由于少创建和维护一个模块,复杂性也降低了。那是非常重要的冗余减少!
除了 duck typing,清单 6 中的默认属性语法还简单地定义了两个普通属性,storeName 和 bikes,如同拥有了 getter 和 setter 一样。这样做的好处和在 清单 1 和 2 中比较 JavaBean-GroovyBean 时所说明的好处是一样的。尤其是,清单 6 还阐明了另一个用以减少代码冗余的 Groovy 特性 —— 操作符重载。请注意如何使用 << 操作符来代替 add() 方法。通过减少一层嵌套的括号使代码的可读性得以改善。这也是 Groovy 众多通过减少冗余而改善代码可读性的特性中的一种。
|
Groovy 中的 duck-typing 和属性语义通过减少代码行数来减少冗余;然而,也可以通过增加透明度来减少冗余。在 清单 6 中,请注意在 ArrayListRentABike 构造函数中创建新 Bike 对象的方式。Groovy 名称和值的初始化语法比 Java 版的略微详细,但这些额外的代码却使整个代码更为透明 —— 将这一点与 清单 5 中 Java 版的进行比较,哪个属性被初始化为哪个值会立即明显 起来。不回过头来看 Bike JavaBean 源代码,您能记起哪个参数是 frame,哪个是 new Bike("Shimano"、 "Roadmaster"、20、 "11111"、15、 "Fair") 的 weight 吗?尽管我刚写过,但我还是记不起来!
|
到目前为止,我将 Bike 和自行车商店类型在 Java 和 Groovy 下进行了比较。现在,到了更近距离地看一下自行车商店的视图 的时候了。在清单 7 中,该视图类具有一个 rentaBike 属性,该属性引用 RentABike 接口并在行动上说明 Java 版的多态。由于 Java 要求所有类属性都必须是声明过的类型,而不是针对某个特定的实现进行编码,我向一个接口编程,该接口使这个类跟 RentABike 实现的改变分隔开来。这是很好的、扎实的 Java 编程实践。
清单 7. Java 版的自行车商店视图
|
将清单 7 中的 Java 视图与清单 8 中的 Groovy 视图进行比较,请注意我声明了带 def 关键字的 rentaBike。这是 duck-typing 的实践,与 Java 版的很像。我正在实践好的软件设计,这是因为我还没有将视图和特定的实现耦合起来。但我也能够不 定义接口就实现解耦。
清单 8. Groovy 的 CommandLineView
|
与 Bike 和自行车商店类型一样,Groovy 的 CommandLineView 没有了为 RentABike 属性所显式编写 的 getter 或 setter 的冗余。同样,在 printAllBikes() 方法中,通过使用 each 来打印在集合里找到的每辆自行车,我再一次利用了 Groovy 强大的集合功能的改进。
|
在前面的部分中,已经介绍了 Groovy 相比 Java 是如何定义自行车、自行车商店和自行车商店视图的。现在该介绍如何将整个应用程序组装起来并在命令行视图中使用 Spring 来显示库存自行车列表了。
在 Java 编程中,一旦定义了一个接口,就可以使用工厂模式将创建真实的实现类的责任委派给一个对象工厂。使用 Spring 作为一个工厂极大地减少了冗余,并在 Groovy 和 Java 中都能够使用,在最终的代码样例中,Spring 负责在 Java 和 Groovy 中创建一个 CommandLineView 类型的实例。
在清单 9 中,配置 Spring 是为了在返回一个 CommandLineView 实例前,创建并将自行车商店的 ArrayList 实现注入 CommandLineView 中。这意味着,不需要引用在 清单 7 和 8 的 Java 或是 Groovy 版的命令行视图中的 ArrayList 实现。在 Java 版中,被注入的类通常都会引用一个接口而不是实现。在 Groovy 中,由于使用 def 关键字,而允许利用 duck-typing。无论在哪个实例中,配置 Spring 的目的都是为了将自行车商店视图的实例和自行车商店类型的实例完整地配置起来!
清单 9. Spring 配置文件
|
在清单 10 和 11 中,自行车商店组装类型用清单 9 中的配置文件创建了一个 Spring 的 ClassPathXmlApplicationContext 实例,然后,请求自行车商店视图的实例:
清单 10. Java 版本下调用 Spring 创建自行车商店视图
|
请注意Java 版的清单 10 中,用以请求一个命令行视图实例的对 Spring 的调用要求向一个支持 printAllBikes() 方法的对象类型强制转换。在本例中,由 Spring 导出的对象将被强制转换为 CommandLineView。
有了 Groovy 及其对 duck-typing 的支持,将不再需要强制转换。只需确保由 Spring 返回的类能够对合适的方法调用(printAllBikes())作出响应。
清单 11. Groovy 版的 Spring 组合件
|
正如在清单 11 中看到的那样,在 Groovy 中,duck-typing 对减少冗余的贡献不仅体现在无需声明接口即可支持由 Spring 自动配置对象,其贡献还体现在简化了对完全配置的 bean 的使用(一旦它从 Spring 容器中返回)。
|
至此,希望我已经阐明了 Groovy 的强大功能及其如何能如此深远地改变源代码的性质。与上述 Java 样例相比,Groovy 代码更简短也更易理解。任何人,无论是经验丰富的 Java 架构师还是非 Java 程序员,都能轻易地掌握 Groovy 代码的意图。Groovy 及其对动态类型的支持减少了要管理的文件。总之,使用 Groovy 减少了在典型的 Java 程序中所常见的大量冗余。这实在是福音啊!
http://www-900.ibm.com/developerWorks/cn/linux/opensource/os-ecshare/index.shtml
摘 要 目前流行的Java企业应用系统框架种类繁多,为了使开发人员正确选择系统架构从而提高Java企业应用的开发效率,首先针对基于EJB和基于POJOs 的较为流行的几种框架分别进行了概述,然后对这些框架从表现层、业务逻辑层和持久层的实现细节进行了对比,总结了Java企业应用系统框架选择需要侧重考 虑因素,得到了基于EJB的框架和基于POJOs的框架分别适用的范围。
关键词 Java企业应用系统框架;EJB3.0;Spring;Hibernate
引言
EJB的体系结构是J2EE的基础和核心,J2EE定义了整个标准的应用开发体系结构和一个部署环境,基于EJB的框架一度成为人们开发Java企业应 用的首选。随着Java开源项目阵营的发展壮大, 一些基于POJOs(Plan Old Java Objects)的开源框架被越来越广泛地引入到Java企业应用的开发中来。根据复杂程度人们习惯把前者称为重量级框架,把后者称为轻量级框架。 Java企业应用框架一般被划分为三个层次:表现层、业务逻辑组件层和持久层。本文主要对目前企业应用对应于这三个层次的两种类型的流行框架进行了细节比 较,最后针对Java企业应用的系统框架选择提出作者的观点。
两种类型框架概述
1、基于EJB的重量级框架
由于 EJB容器能够很好的处理系统性能、事务机制、安全访问权限以及分布式运算等问题,基于EJB框架进行开发能保证企业应用平滑发展,而不是发展到一种规模 就重新更换一套软件系统,且可以保证开发人员将大部份精力集中在业务逻辑的开发上。采用EJB框架开发的企业应用具有必须继承或依赖EJB容器的特点。 EJB充分考虑到了顶级大型项目的需求,使用它几乎能解决企业级应用涉及到的所有问题,相应的基于EJB框架也是一个功能复杂的重量级框架。
J2EE1.4标准规定的EJB 2.1框架缺少设计且实现起来有些过于复杂。当前J2EE5.0的新规范提出的EJB 3.0的目标就是简化开发[1],借鉴了一些基于POJO的思想,它相对于EJB2.1中两个重要的变化分别是:一是使用了Java5中的程序注释工具, 注释取代了过多的XML配置文件并且消除了严格组件模型需求;二是采用了基于Hibernate和TopLink思想的O/R Mapping模型。
J2EE5.0的新规范中定义企业应用三个层次的标准实现为:表现层采用JSF(Java Server Face),JSF的开发流程的核心是事件驱动,组件和标签的封装程度非常高,很多典型应用已经不需要开发者去处理http。整个过程是通过IoC(依赖 注入)[2]来实现的;业务组件层采用EJB3.0的Session Bean。EJB3.0允许开发者使用藕合松散的组件来开发应用。这些组件通过自己发布的商业接口来耦合,不必像EJB 2.1规范定义的那样一个Bean必须遵守的严格的组件模型,每一个EJB类必须从某一种抽象类中继承,并为容器提供了回调的钩子;持久层采用 EJB3.0实体Bean持久化模型,吸收了Hibernate的一些思想采用O/R Mapping模式, EJBQL也有许多重要的改变。
2、基于POJOs的轻量级框架
在基于POJOs轻量级框架上开发的应用程序无需依赖于EJB容器可独立运行,对应于Java企业应用三个层次的轻量级框架技术分别都得到了一定的发展,这三个层次流行的框架如下:
目前比较流行的开源表现层框架主要有Struts和Tapestry。Tapestry与Struts应用框架不同的是,它是基于组件,而不是面向脚本 语言(比如JSP和Velocity)的,组件是由一个定义文件(以XML的格式)、一个HTML模板、一个JAVA类构成的;业务组件层轻量级解决方案 也不少,包括Spring、Hivemind等。但是目前使用最为广泛的还是Spring框架,Spring框架是一个基于IoC和AOP(面向方面编 程)[3]的构架。采用IoC使得它可以很容易的实现bean的装配,提供了简洁的AOP并据此实现事务管理等,但是它不具备处理应用分布式的能力。 Spring的核心要点是:支持不绑定到特定J2EE服务的可重用业务和数据访问对象。这样的对象可以在不同J2EE环境(Web或EJB)、独立应用程 序、测试环境之间重用;持久层框主要有Hibernate和各种JDO产品,以及iBATIS。Hibernate是一个开源的O/R Mapping框架,它对JDBC进行了非常轻量级的对象封装,可以应用在任何使用JDBC的场合,可以在应用EJB的J2EE框架中取代CMP,完成数 据持久化的重任。iBATIS是一个简易的SQL Map工具,它是将手工编写的在xml配置文件中的SQL语句映射成Java对象。
对应于三个层次的框架比较
1、表现层框架比较
MVC设计模式不再是某一种表现层框架的特点而是这几种框架的共性。Struts框架由于出现时间早,所以使用相对广泛,它的社区非常活跃,很容易找到 很多现成的开源功能标签以供使用以及样例程序可供参考。但是它的组件在页面中显示的粗粒度,以及框架类的限制在很多情况下会表现得过于死板,给表示层的开 发会带来一些额外的代码开销。JSF在很大程度上类似Struts,只是JSF的组件概念没有象Struts那样必须继承ActionForm的限制, JSF在事件粒度上要比Struts细腻。JSF有的另外一个优势就是其身后有Sun公司和其他的一些大公司的支持。Tapestry是一个完全组件的框 架,Tapestry的组件可以被套嵌并包裹其它组件,因此可以组合形成一个更大的组件或逻辑页面。组件的行为模式为Web页面编程提供了很大的方便,事 件处理也方便很多。所以,如果做一个对页面要求灵活度相当高的系统就可以考虑选用Tapestry。
表1 三种框架的表现层功能技术细节比较
框架
Struts
Tapestry3.0
JSF
View组件实现模式
标签库+组件,组件必须继承ActionForm
完全组件,分显式调用和隐式调用,组件必须继承BaseComponent
标签库+组件,普通POJO无需继承
组件在View显示粒度
View页面只能显示与表单对应的ActionForm,配置中Action与 ActionForm与 页面一般只能1:1:1关系。
可将组件嵌入页面任何一行,对使用组件数量无限制。
同Tapestry
页面跳转
使用标签库html:link中写明目标URL,URL名称需要对照struts_config.xml配置文件中的path命名,与组件Action耦合。
URL名称是目标的组件名称,不涉及URL和路径等操作,方便稳固。
类似Struts,也需要在配置文件中查找,与组件分离。
事件触发
通过表单提交submit激活,不能细化到表单里字段。
能够给于表单每个字段赋一个事件,事件组件必须实现PageListener接口
同Tapestry,事件组件必须实现ActionListener
2、业务组件层框架比较
EJB 2.1框架有些过于复杂了,有如下缺点:① EJB模型需要建立许多组件接口和实现许多不必要的回滚方法;②EJB的部署描述复杂而容易出错;③开发人员不能脱离EJB容器测试。对于以上缺点JCP (Java Community Process)制订的EJB3.0标准框架做了相应的改进,该框架为所有主要的J2EE厂商支持。EJB3.0和Spring两个框架结构都有一个共同 核心设计理念:将中间件服务传递给耦合松散的POJOs。
EJB3.0框架与应用服务器高 度整合,服务整合代码也包装在一个标准接口后面。EJB框架一方面有成熟的EJB容器支持,基于EJB框架的企业应用性能优良;另一方面EJB容器设计因 为考虑了多方面的功能,所以在其内核上总是会显得臃肿,这也是一种重量表现。不需要的东西存在肯定会影响效率,EJB不能根据项目需求对EJB整体包括 EJB容器进行可配置式的切割。
Spring框架处于应用服务器和服务库的上方,服务整合的代码属于框架,并暴露于应用开发者。它与应用服务器整合的能力相对EJB3.0要弱。但是Spring框架模块的可分离配置体现了它优于EJB3.0的灵活性。
表2 EJB和Spring框架的具体细节比较
框架
EJB2/EJB3
Spring Framework 1.x
灵活性(松耦合)
EJB3比EJB2更具灵活性,EJB3支持应用系统POJO
支持应用系统POJO,框架本身可分离配置
功能完整性
全面,支持异步JMS 分布式事务
较为全面。有自己的表现层和持久层模板,可支持异步
领域范围
支持业务逻辑Session
不支持,需要开发者额外基于ThreadLocal编制代码
IoC/AOP支持
EJB3支持IoC, JBoss等EJB3服务器支持AOP;基于业务组件的较粗粒度
基于JavaBeans类的细粒度支持AOP
单台性能
一般,批量查询等大数据量业务处理须小心,存在本地不透明缺陷。
一般,应用程序可配置cache/Pool以提高性能
可伸缩性
可支持多台服务器分布式计算。
不支持,可依靠EJB实现
开发效率
学习曲线长,导致熟练掌握难。借助商业开发工具可加快熟练者的开发速度。
可挑选只适合自己的功能实现。相对EJB稍简单。
系统规模
EJB2适合大型系统;EJB3适合中大型系统
适合中小型系统,可借助EJB支持中大型系统
3、持久层框架比较
容器管理持久性(CMP)是对EJB中Entity Bean进行持久性管理的方式。EJB2.1 持久性模型过于复杂并且存在基础缺陷[3]。EJB3.0持久层针对EJB2.1的缺陷做了相应改进,采用与Hibernate类似的机制。
Hibernate相对而言其基本优势如下:①Hibernate 使用 Java 反射机制而不是字节码增强程序来实现透明性;②Hibernate的使用简单;③映射的灵活性很出色,它支持各种关系数据库,从一对一到多对多的各种复杂 关系。Hibernate 也有一些缺点,它限制所使用的对象模型 (例如,一个持久性类不能映射到多个表)。
使用iBATIS提供的O/R Mapping机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象,这一层与通过Hibernate 实现O/R Mapping 而言基本一致,而对于具体的数据操作,Hibernate 会自动生成SQL 语句,而iBATIS则要求开发者编写具体的SQL 语句。相对Hibernate等 “全自动”O/R Mapping机制而言,iBATIS以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。作为“全自动”ORM 实现的一种有益补充,iBATIS的出现显得别具意义。
企业应用系统框架选择
设计和性能是实际框架选择的两个基本点,善于平衡才是框架选择的主要宗旨。轻量级框架和重量级框架解决问题的侧重点是不同的。
轻量级框架侧重于减小开发的复杂度,相应的它的处理能力便有所减弱(如事务功能弱、不具备分布式处理能力),比较适用于开发中小型企业应用。采用轻量框 架一方面因为尽可能的采用基于POJOs的方法进行开发,使应用不依赖于任何容器,这可以提高开发调试效率;另一方面轻量级框架多数是开源项目,开源社区 提供了良好的设计和许多快速构建工具以及大量现成可供参考的开源代码,这有利于项目的快速开发。例如目前Tomcat+Spring+Hibernate 已经成为许多开发者开发J2EE中小型企业应用偏爱的一种架构选择。随着可供选择的框架层出不穷,开发者可以根据需要对应于企业应用三个层次的轻量级框架 选择,本文第2节的内容可供选择参考。
而作为重量级框架EJB框架则强调高可伸缩性,适合与开发大型企业应用。在EJB体系结构中, 一切与基础结构服务相关的问题和底层分配问题都由应用程序容器或服务器来处理,且EJB容器通过减少数据库访问次数以及分布式处理等方式提供了专门的系统 性能解决方案,能够充分解决系统性能问题。
轻量级框架的产生并非是对重量级框架的否定,甚至在某种程度上可以说二者是互补的。轻量级 框架在努力发展以开发具有更强大,功能更完备的企业应用;而新的EJB规范EJB3.0则在努力简化J2EE的使用以使得EJB不仅仅是擅长处理大型企业 系统,也利用开发中小型系统,这也是EJB轻量化的一种努力。对于大型企业应用以及将来可能涉及到能力扩展的中小型应用采用结合使用轻量级框架和重量级框 架也不失为一种较好的解决方案。
总结
目前适用Java企业应用的系统框架可谓百花齐放,各种框架都有长短,选择应用系统框架时不可盲目的追求流行,首先需要明确所要实现的应用系统的系统处 理能力需求,然后在熟悉比较各种框架细节的基础上从设计以及开发效率方面进行考虑。本文旨在为系统框架选择提供一个参考,限于篇幅本文只对其中的几种框架 做了比较,开发者可以根据需要对更多其他框架细节进行比较。
1.工作区: (显隐)
项目面板:ctrl + Alt + p (Project)
设计面板: ctrl + Alt + c (content)
结构面板: ctrl + Alt + s (Structure)
信息面板: ctrl + Alt + M (Message)
状态面板: ctrl + Alt + Z
2.主面板:(代码面板和设计面板)
激活代码模块: ctrl + J (@1)
参数提示信息的激活: ctrl + shift + H
打开查询、替换窗口: ctrl + F
类的查询: ctrl + -
3.F 键的用法
F1: 帮助快捷
F4: 运行多行
F5: 加入断点
F7: 当遇到方法时会运行方法内的代码
F8: 逐步运行代码
F12: 代码面板和设计面板切换
4. Shift 键的用法
添加多个相同组件: 按shift键在选项上选取组件,把组件添加到窗口即可
调整组件间间隔和对齐: 假设有组件JPanel 1/2/3;(要达到3个组件宽度相同,组件间隔相等,并且都是依据JPanel1左对齐),按shift键,用鼠标选中需要调整的组件,(第一个选中的组件是其他的基准)然后右键。
5: codeInsight 和 Codetemplates
MemberInsight -- 根据当前的代码提示可用的类成员或方法(说明)
ParameterInsight -- 提示当前的方法需要使用的参数
SymbolInsigh -- 查看当前的变量、方法或者类的愿代码。
MemberInsight: ctrl + space 或 ctrl + H
ParameterInsight: ctrl + shift + space 或 ctrl + shift + H
SymbolInsight: ctrl + Enter 或 Alt + shift + H
ClassInsight : ctrl + alt + space 或 ctrl + alt + H
注: (@1):使用代码功能:(ctrl + J)
1、 在想要输入代码的位置输入代码摸板名,然后按 ctrl + J(开发人员可以用主菜单上的Tools/Editor/Templates命令来查看代码摸板的名字)
2、把光标定位于想要输入代码的位置,然后按ctrl + J
开源网站:
Wiring Your Web Application with Open Source Java http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html
一个开源的RSS浏览器 http://www.rssowl.org/
1、Velocity是什么?
Velocity是一个基于java的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。
当Velocity 应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来,这样为web站点的长期维护提供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。
Velocity的能力远不止web站点开发这个领域,例如,它可以从模板(template)产生SQL和PostScript、XML,它也可以被当作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。 Velocity也可以为Turbine web开发架构提供模板服务(template service)。Velocity+Turbine提供一个模板服务的方式允许一个web应用以一个真正的MVC模型进行开发。
2、Velocity能为我们作什么?
The Mud Store Example
假设你是一家专门出售Mud的在线商店的页面设计人员,让我们暂且称它为“在线MUD商店”。你们的业务很旺,客户下了各种类型和数量的mud订单。他们都是通过输入用户名和密码后才登陆到你的网站,登陆后就允许他们查看订单并购买更多的mud。现在,一种非常流行的mud正在打折销售。另外有一些客户规律性的购买另外一种也在打折但是不是很流行的Bright Red Mud,由于购买的人并不多所以它被安置在页面的边缘。所有用户的信息都是被跟踪并存放于数据库中的,所以某天有一个问题可能会冒出来:为什么不使用 velocity来使用户更好的浏览他们感兴趣的商品呢?
Velocity使得web页面的客户化工作非常容易。作为一个web site的设计人员,你希望每个用户登陆时都拥有自己的页面。
你会见了一些公司内的软件工程师,你发现他们每个人都同意客户应该拥有具有个性化的信息。那让我们把软件工程师应该作的事情发在一边,看一看你应该作些什么吧。
你可能在页面内嵌套如下的VTL声明:
Hello $customer.Name!
#foreach( $mud in $nudsOnSpecial )
#if ( $customer.hasPurchased( $mud ) )
#end
#end
| $flogger.getPromo( $mud ) |
一、Velocity Template Language(VTL):AN introduction
VTL意味着提供最简单、最容易并且最整洁的方式合并页面动态内容。
VTL 使用references来在web site内嵌套动态内容,一个变量就是一种类型的reference。变量是某种类型的refreence,它可以指向java代码中的定义,或者从当前页面内定义的VTL statement得到值。下面是一个VTL statement的例子,它可以被嵌套到HTML代码中:
#set ( $a = “Velocity” )
和所有的VTL statement一样,这个statement以#字符开始并且包含一个directive:set。当一个在线用户请求你的页面时,Velocity Templating Engine将查询整个页面以便发现所有#字符,然后确定哪些是VTL statement,哪些不需要VTL作任何事情。
#字符后紧跟一个directive:set时,这个set directive使用一个表达式(使用括号封闭)――一个方程式分配一个值给变量。变量被列在左边,而它的值被列在右边,最后他们之间使用=号分割。
在上面的例子中,变量是$a,而它的值是Velocity。和其他的references一样以$字符开始,而值总是以双引号封闭。Velocity中仅有String可以被赋值给变量。
记住以下的规则:
使用$字符开始的references用于得到什么;使用#字符开始的directives用于作些什么。
Hello Velocity World!
一旦某个变量被分配了一个值,那么你就可以在HTML文件的任何地方引用它。在下面的例子中,一个值被分配给$foo变量,并在其后被引用。
#set ( $foo = “Velocity” )
Hello $foo World!
上面的实现结果是在页面上打印“Hello Velocity World!”
为了使包含VTL directives的statement更具有可读性,我们鼓励你在新行开始每个VTL statement,尽管你不是必须这么作。Set directive将在后面详细描述。
二、注释
1.单行注释:
## This is a single line comment.
2.多行注释:
#*
Thus begins a multi-line comment. Online visitors won’t
see this text because the Velocity Templating Engine will
ignore it.
*#
3.文档格式:
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@version 5
@author
*#
三、References
在VTL中有三种类型的references:变量(variables)、属性(properties)、方法(methods)。
作为一个使用VTL的页面设计者,你和你的工程师必须就references的名称达成共识,以便你可以在你的template中使用它们。
Everything coming to and from a reference被作为一个String对象处理。如果有一个对象$foo是一个Integer对象,那么Velocity将调用它的toString()方法将这个对象转型为String类型。
1.变量
格式要求同java。
2.属性
例子:
$customer.Address
$purchase.Total
$customer.Address 有两种含义。它可以表示:查找hashtable对象customer中以Address为关键字的值;也可以表示调用customer对象的 getAddress()方法。当你的页面被请求时,Velocity将确定以上两种方式选用那种,然后返回适当的值。
3.方法
一个方法就是被定义在java中的一段代码,并且它有完成某些有用工作的能力,例如一个执行计算和判断条件是否成立、满足等。方法是一个由$开始并跟随VTL标识符组成的References,一般还包括一个VTL方法体。例如:
$customer.getAddress()
$purchase.getTotal()
$page.setTitle( “My Home Page” )
$person.setAttributes( [“Strange”, “Weird”, “Excited”] )
前两个例子$customer.getAddress()和$purchase.getTotal()看起来挺想上面的属性$customer.Address 和 $purchase.Total。如果你觉得他们之间有某种联系的话,那你是正确的。
VTL属性可以作为VTL方法的缩写。$customer.Address属性和使用$customer.getAddress()方法具有相同的效果。如果可能的话使用属性的方式是比较合理的。属性和方法的不同点在于你能够给一个方法指定一个参数列表。
4.正式reference标记
reference的正是格式如下:
${mudSlinger} 变量
${customer.Address} 属性
${purchase.getTotal()} 方法
非正是格式更见常用,但是有时还是使用正是格式比较适合。例如:你希望通过一个变量$vice来动态的组织一个字符串。
Jack is a $vicemaniac.
本来变量是$vice现在却变成了$vicemaniac,这样Veloctiy就不知道您到底要什么了。所以,应该使用正是格式书写
Jack is a ${vice}maniac
现在Velocity知道变量是$vice而不是$vicemaniac。
5.Quiet reference notation
例如:
当页面的form被初始加载时,变量$email还没有值,这时你肯定是希望它能够显示一个blank text来代替输出”$email”这样的字段。那么使用quiet reference notation就比较合适。
这样文本框的初始值就不会是email而是空值了。
正式和quiet格式的reference notation也可一同使用,像下面这样:
Getting literal
Velocity使用特殊字符$和#来帮助它工作,所以如果要在template里使用这些特殊字符要格外小心。本节将讨论$字符。
6.货币字符
在VTL中使用$2.5这样的货币标识是没有问题得的,VTL不会将它错认为是一个reference,因为VTL中的reference总是以一个大写或者小写的字母开始。
Escaping valid VTL reference
VTL中使用“\”作为逃逸符。
例如:
#set( $email = “foo” )
将render为:
foo
\foo
如果email变量没有被定义则
将被render为:
注意:VTL中未被定义的变量将被认为是一个字符串,所以以下例子:
#set( $foo = “gibbous” )
$moon = $foo
的输出结果是:
$moon = gibbous
7.Case substitution
现在你已经对reference比较熟悉了,你可以将他们高效的应用于你的template了。Velocity利用了很多java规范以方便了设计人员的使用。例如:
$foo
$foo.getBar()
## is the same as
$foo.Bar
$data.getUser(“jon”)
## is the same as
$data.User(“jon”)
$data.getRequest().getServerName()
# is the same as
$data.Request.ServerName
## is the same as
${data.Request.ServerName}
但是,注意VTL中不会将reference解释为对象的实例变量。例如:$foo.Name将被解释为Foo对象的getName()方法,而不是Foo对象的Name实例变量。
四、Directives
Reference允许设计者使用动态的内容,而directive使得你可以应用java代码来控制你的显示逻辑,从而达到你所期望的显示效果。
1. #set
#set directive被用于设置一个reference的值。例如:
#set ( $primate = “monkey” )
#set ( $customer.Behavior = $primate )
赋值左侧的(LHS)必须是一个变量或者属性reference。右侧(RHS)可以是以下类型中一种:
a. 变量reference
b. String literal
c. 属性reference
d. 方法reference
e. number literal
f. ArrayList
下面是应用各种类型的RHS的例子:
#set ( $monkey = $bill ) ##变量reference
#set ( $monkey.Friend = “monica” ) ##String literal
#set ( $monkey.Blame = $whitehouse.Leak )##属性reference
#set ( $monkey.Plan = $spindoctor.weave($web) )##方法reference
#set ( $monkey.Number = 123 )##Number literal
#set ( $monkey.Say = [“Not”, $my, “fault”] )##ArrayList
注意:最后一个例子的取值方法为:$monkey.Say.get(0)
RHS也可以是一个简单的算术表达式:
#set ( $value = $foo + 1 )
#set ( $value = $bar -1 )
#set ( $value = $foo * $bar )
#set ( $value = $foo / $bar )
如果你的RHS是一个null,VTL的处理将比较特殊:它将指向一个已经存在的reference,这对初学者来讲可能是比较费解的。例如:
#set ( $resut = $query.criteria(“name”) )
The result of the first query is $result
#set ( $resut = $query.criteria(“address”) )
The result of the second query is $result
如果$query.criteria(“name”)返回一个“bill”,而$query.criteria(“address”)返回的是null,则显示的结果如下:
The result of the first query is bill
The result of the first query is bill
看看下面的例子:
#set( $criteria = ["name", "address"] )
#foreach( $criterion in $criteria )
#set( $result = $query.criteria($crit
#end
#foo ( $bar.rowColor() )
以上代码将导致rowColor()方法两次调用,而不是一次。为了避免这种现象的出现,我们可以按照下面的方式执行:
#set ( $color = $bar.rowColor() )
#foo ( $color )
can I register velocimacros via #parse()?
目前,Velocimacros必须在第一次被模板调用前被定义。这就意味着你的#macro()声明应该出现在使用Velocimacros之前。
如果你试图#parse()一个包含#macro() directive的模板,这一点是需要牢记的。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用 velocimacro.library使得Velocity在启动时加载你的VMs。
What is velocimacro autoreloading?
velocimacro.library.autoreload是专门为开发而非产品使用的一个属性。此属性的默认值是false。
String concatenation
开发人员最常问的问题是我如何作字符拼接?在java中是使用“+”号来完成的。
在VTL里要想实现同样的功能你只需要将需要联合的reference放到一起就行了。例如:
#set ( $size = “Big” )
#set ( $name = “Ben” )
The clock is $size$name.
输出结果将是:The clock is BigBen.。更有趣的情况是:
#set ( $size = “Big” )
#set ( $name = “Ben” )
#set ( $clokc = “$size$name” )
The clock is $clock.
上例也会得到同样的结果。最后一个例子,当你希望混合固定字段到你的reference时,你需要使用标准格式:
#set ( $size = “Big” )
#set ( $name = “Ben” )
#set ( $clock = “${size}Tall$name” )
The clock is $clock.
输出结果是:The clock is BigTallBen.。使用这种格式主要是为了使得$size不被解释为$sizeTall。
| 作者: 来源:赛迪网 发表时间:2006-05-22 浏览次数: 3 字号:大 中 小 | ||||||||||||||||
#end 在上面的例子中Velocimacro被定义为d,然后你就可以在任何VTL directive中以如下方式调用它: #d() 当你的template被调用时,Velocity将用替换为#d()。 每个Velocimacro可以拥有任意数量的参数――甚至0个参数,虽然定义时可以随意设置参数数量,但是调用这个Velocimacro时必须指定正确的参数。下面是一个拥有两个参数的Velocimacro,一个参数是color另一个参数是array: #macro ( tablerows $color $somelist ) #foreach ( $something in $somelist ) #end #end 调用#tablerows Velocimacro: #set ( $greatlakes = [ “Superior”, “Michigan”, “Huron”, “Erie”, “Ontario” ] ) #set ( $color = “blue” )
#tablerows( $color $greatlakes ) 经过以上的调用将产生如下的显示结果:
Velocimacros 可以在Velocity模板内实现行内定义(inline),也就意味着同一个web site内的其他Velocity模板不可以获得Velocimacros的定义。定义一个可以被所有模板共享的Velocimacro显然是有很多好处的:它减少了在一大堆模板中重复定义的数量、节省了工作时间、减少了出错的几率、保证了单点修改。 上面定义的#tablerows( $color $list )Velocimacro被定义在一个Velocimacros模板库(在velocity.properties中定义)里,所以这个macro可以在任何规范的模板中被调用。它可以被多次应用并且可以应用于不同的目的。例如下面的调用: #set ( $parts = [ “volva”, “stipe”, “annulus”, “gills”, “pileus” ] ) #set ( $cellbgcol = “#CC00FF” ) #tablerows( $cellbgcol $parts ) 上面VTL将产生如下的输出:
9.Velocimacro arguments Velocimacro可以使用以下任何元素作为参数: l Reference:任何以$开头的reference l String literal: l Number literal: l IntegerRange:[1….3]或者[$foo….$bar] l 对象数组:[“a”,”b”,”c”] l boolean值:true、false 当将一个reference作为参数传递给Velocimacro时,请注意reference作为参数时是以名字的形式传递的。这就意味着参数的值在每次 Velocimacro内执行时才会被产生。这个特性使得你可以将一个方法调用作为参数传递给Velocimacro,而每次Velocimacro执行时都是通过这个方法调用产生不同的值来执行的。例如: #macro ( callme $a ) $a $a $a #end #callme( $foo.bar() ) 执行的结果是:reference $foo的bar()方法被执行了三次。 如果你不需要这样的特性可以通过以下方法: #set ( $myval = $foo.bar() ) #callme ( $myval ) 10.Velocimacro properties Velocity.properties文件中的某几行能够使Velocimacros的实现更加灵活。注意更多的内容可以看Developer Guide。 Velocity.properties文件中的velocimacro.libraary:一个以逗号分隔的模板库列表。默认情况下,velocity查找唯一的一个库:VM_global_library.vm。你可以通过配置这个属性来指定自己的模板库。 Velocity.properties 文件中的velocimacro.permissions.allow.inline属性:有两个可选的值true或者false,通过它可以确定 Velocimacros是否可以被定义在regular template内。默认值是ture――允许设计者在他们自己的模板中定义Velocimacros。 Velocity.properties文件中的 velocimacro.permissions.allow.inline.replace.global 属性有两个可选值true和false,这个属性允许使用者确定inline的Velocimacro定义是否可以替代全局Velocimacro定义(比如在velocimacro.library属性中指定的文件内定义的Velocimacro)。默认情况下,此值为false。这样就阻止本地 Velocimacro定义覆盖全局定义。 Velocity.properties文件中的 velocimacro.permissions.allow.inline.local.scale 属性也是有true和false两个可选值,默认是false。它的作用是用于确定你inline定义的Velocimacros是否仅仅在被定义的 template内可见。换句话说,如果这个属性设置为true,一个inline定义的Velocimacros只能在定义它的template内使用。你可以使用此设置实现一个奇妙的VM敲门:a template can define a private implementation of the second VM that will be called by the first VM when invoked by that template. All other templates are unaffected。 Velocity.properties文件中的 velocimacro.context.localscope属性有true和false两个可选值,默认值为false。当设置为true时,任何在 Velocimacro内通过#set()对context的修改被认为是针对此velocimacro的本地设置,而不会永久的影响内容。 Velocity.properties 文件中的velocimacro.library.autoreload属性控制Velocimacro库的自动加载。默认是false。当设置为 ture时,对于一个Velocimacro的调用将自动检查原始库是否发生了变化,如果变化将重新加载它。这个属性使得你可以不用重新启动 servlet容器而达到重新加载的效果,就像你使用regular模板一样。这个属性可以使用的前提就是resource loader缓存是off状态(file.resource.loader.cache = false)。注意这个属性实际上是针对开发而非产品的。
|
||||||||||||||||
| Hi | ||||||||||||||||
| There |
#foo ( $bar.rowColor() )
以上代码将导致rowColor()方法两次调用,而不是一次。为了避免这种现象的出现,我们可以按照下面的方式执行:
#set ( $color = $bar.rowColor() )
#foo ( $color )
can I register velocimacros via #parse()?
目前,Velocimacros必须在第一次被模板调用前被定义。这就意味着你的#macro()声明应该出现在使用Velocimacros之前。
如果你试图#parse()一个包含#macro() directive的模板,这一点是需要牢记的。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用 velocimacro.library使得Velocity在启动时加载你的VMs。
What is velocimacro autoreloading?
velocimacro.library.autoreload是专门为开发而非产品使用的一个属性。此属性的默认值是false。
String concatenation
开发人员最常问的问题是我如何作字符拼接?在java中是使用“+”号来完成的。
在VTL里要想实现同样的功能你只需要将需要联合的reference放到一起就行了。例如:
#set ( $size = “Big” )
#set ( $name = “Ben” )
The clock is $size$name.
输出结果将是:The clock is BigBen.。更有趣的情况是:
#set ( $size = “Big” )
#set ( $name = “Ben” )
#set ( $clokc = “$size$name” )
The clock is $clock.
上例也会得到同样的结果。最后一个例子,当你希望混合固定字段到你的reference时,你需要使用标准格式:
#set ( $size = “Big” )
#set ( $name = “Ben” )
#set ( $clock = “${size}Tall$name” )
The clock is $clock.
输出结果是:The clock is BigTallBen.。使用这种格式主要是为了使得$size不被解释为$sizeTall。
|
全局定义。 Velocity.properties文件中的 velocimacro.permissions.allow.inline.local.scale 属性也是有true和false两个可选值,默认是false。它的作用是用于确定你inline定义的Velocimacros是否仅仅在被定义的 template内可见。换句话说,如果这个属性设置为true,一个inline定义的Velocimacros只能在定义它的template内使用。你可以使用此设置实现一个奇妙的VM敲门:a template can define a private implementation of the second VM that will be called by the first VM when invoked by that template. All other templates are unaffected。 Velocity.properties文件中的 velocimacro.context.localscope属性有true和false两个可选值,默认值为false。当设置为true时,任何在 Velocimacro内通过#set()对context的修改被认为是针对此velocimacro的本地设置,而不会永久的影响内容。 Velocity.properties 文件中的velocimacro.library.autoreload属性控制Velocimacro库的自动加载。默认是false。当设置为 ture时,对于一个Velocimacro的调用将自动检查原始库是否发生了变化,如果变化将重新加载它。这个属性使得你可以不用重新启动 servlet容器而达到重新加载的效果,就像你使用regular模板一样。这个属性可以使用的前提就是resource loader缓存是off状态(file.resource.loader.cache = false)。注意这个属性实际上是针对开发而非产品的。
|
| Hi |
| There |