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) 定义的查询选项。

Posted on October 19, 2006 10:49 PM | | Comments (0) | TrackBacks (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 编程的不同方面(冗余且不必要地传递了应用程序的行为)而使应用程序代码变得多么地清晰。

Groovy 之声

在 Bruce 和 Justin 这本书的第一章中,创建了一个简单的自行车商店应用程序,其中包含有四个类。首先,我将向您展示一个简单的名为 Bike 的 JavaBean 类,该类代表了一辆库存的自行车。然后,我会考查自行车商店的类型,名为 RentABike。它包含了一个 Bike 集。还有一个命名为 CommandLineView 的用于显示自行车列表的类,该类依赖于 RentABike 类型。最后,有一个用于集成这些部分以创建工作应用程序的类,该类利用 Spring 来传递完整地配置了 RentABike 类型的 CommandLineView 类 —— 免去了复杂的硬编码。

停用 JavaBean!

清单 1 中一个代表自行车的类在常规 Java 代码中被实现为一个简单的 JavaBean,它是 Java 开发人员可能已经编写好的成百上千的类的一个典型。通常来说,JavaBean 并没有什么特殊之处 —— 其属性被声明为 private,且可通过 public getter 和 setter 对其进行访问。


清单 1. Java 代码中的 Bike JavaBean
    
import java.math.BigDecimal;

public class Bike {
private String manufacturer;
private String model;
private int frame;
private String serialNo;
private double weight;
private String status;
private BigDecimal cost;

public Bike(String manufacturer, String model, int frame,
String serialNo, double weight, String status) {
this.manufacturer = manufacturer;
this.model = model;
this.frame = frame;
this.serialNo = serialNo;
this.weight = weight;
this.status = status;
}

public String toString() {
return "com.springbook.Bike : " +
"manufacturer -- " + manufacturer +
"\n: model -- " + model +
"\n: frame -- " + frame +
"\n: serialNo -- " + serialNo +
"\n: weight -- " + weight +
"\n: status -- " + status +
".\n"; }

public String getManufacturer() { return manufacturer; }

public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}

public String getModel() { return model; }

public void setModel(String model) { this.model = model; }

public int getFrame() { return frame; }

public void setFrame(int frame) { this.frame = frame; }

public String getSerialNo() { return serialNo; }

public void setSerialNo(String serialNo) { this.serialNo = serialNo; }

public double getWeight() { return weight; }

public void setWeight(double weight) { this.weight = weight; }

public String getStatus() { return status; }

public void setStatus(String status) { this.status = status; }

public BigDecimal getCost() { return cost; }

public void setCost(BigDecimal cost) {
this.cost = cost.setScale(3,BigDecimal.ROUND_HALF_UP);
}

}

清单 1 是一个只有一个构造方法和六个属性的小例子,但其代码却填满了浏览器的整个页面!清单 2 显示了在 Groovy 中定义的相同的 JavaBean:


清单 2. Bike GroovyBean
  
class Bike {

String manufacturer
String model
Integer frame
String serialNo
Double weight
String status
BigDecimal cost

public void setCost(BigDecimal newCost) {
cost = newCost.setScale(3, BigDecimal.ROUND_HALF_UP)
}


public String toString() {
return """Bike:
manufacturer -- ${manufacturer}
model -- ${model}
frame -- ${frame}
serialNo -- ${serialNo}
"""
}
}

您认为哪一个没那么多冗余呢?

Groovy 版的代码要少很多很多,这是因为 Groovy 的默认属性语义用 public 访问器和存取器自动定义了 private 域。例如,上述 model 属性现在有了自动定义的 getModel() 方法和 setModel() 方法。可以看到,这项技术的好处是,不必在一种类型中按照属性手工定义两个方法!这也解释了 Groovy 中的一条反复强调的定律:使普通的编码规则变得简单

Groovy 更新了的属性语法
最新版的 Groovy, JSR-06 简化了 Groovy 的属性语法。在此版本之前,属性要在变量声明前跟一个特定的 @Property 符号。但这个符号现在已经不再需要。在 JSR-06 中,只需指定一个类型和一个变量名,就会自动生成一个有着 public getter 和 setter 的 private 属性。也可以使用 def 关键字来代替特定的类型。

另外,在 Groovy 中,类的默认函数表达得更为简洁,而在常规 Java 代码(如 清单 1)中该函数必须显式编码。当需要用构造函数或 getter 或 setter 来完成一些特殊任务时,Groovy 真的很出色,因为只需瞥一眼代码,其精彩的行为就会立即变得十分明显。例如,在 清单 2 中很容易看出,setCost() 方法会将 cost 属性换算为三个十进制的位。

将这段不太显眼的 Groovy 代码同 清单 1 中的 Java 源代码进行比较。第一次阅读这段代码时,您注意到 setCost() 方法中嵌入了特殊的函数了吗?除非仔细观察,否则太容易看漏了!

Groovy 测试

清单 3 中 Bike 类的测试用例展示了如何使用自动生成的访问器。同时,出于进一步简化通用编程任务的考虑,测试用例也使用了更为简便的 Groovy 点属性名 标记来访问属性。相应地,能够通过 getModel() 方法或更为简洁的 b.model 形式来引用 model 属性。


清单 3. Groovy 中的 Bike 测试用例
  
class BikeTest extends GroovyTestCase {
void testBike() {
// Groovy way to initialize a new object
def b = new Bike(manufacturer:"Shimano", model:"Roadmaster")

// explicitly call the default accessors
assert b.getManufacturer() == "Shimano"
assert b.getModel() == "Roadmaster"

// Groovier way to invoke accessors
assert b.model == "Roadmaster"
assert b.manufacturer == "Shimano"
}
}

也注意到在上述 Groovy 例子中,不必定义一个如 清单 1 中定义的 Java 构造函数那样的能够接受全部六个属性的构造函数。同时,也不必要创建另一个 只含两个参数的构造函数来支持测试用例 —— 在对象创建过程中设置对象属性的 Groovy 的语义不需要这种冗余、烦人的构造函数(它们综合有多个参数但其作用却只是初始化变量)。

Groovy 和 IDE
像 Eclipse 那样的 IDE 使得自动创建 getter 和 setter 变得十分简单。这些工具也便利了从具体类中提取接口以利于对其进行重构。但我敢说,读那段代码的次数要比写它的次数多很多。 不幸的是,开发人员仍需要通过已经生成的代码和源文件来费力地分辨程序真正在实现什么。用这个高质量的 Java 工具究竟能不能节省创建 Groovy 源代码的敲键次数尚有争议,但一看即明的是 Groovy 代码更为简洁、更易于解释,且没那么复杂。在实际的有着数百个类和数千行代码的应用程序,这种优势就更为突出。

降低的复杂性

在前面的部分中,Bike GroovyBean 利用了 Groovy 的属性和构造语义以减少源代码中的冗余。在这一部分中,Groovy 版的自行车商店也将受益于额外的冗余减少特性,如针对多态的 duck-typing、集合类的改进及操作符重载。

Grooving 中使用多态

在 Java 自行车应用程序中,名为 RentABike 的接口是用来定义由自行车商店支持的 public 方法的。正如在清单 4 中说明的那样,RentABike 定义了一些简单的方法,这些方法用来返回商店中单个的 Bike 或所有 Bike 的列表。


清单 4. 由 Java 定义的 RentABike 接口
  
import java.util.List;

public interface RentABike {
List getBikes();
Bike getBike(String serialNo);
void setStoreName(String name);
String getStoreName();
}

此接口允许多态行为并在下面两种重要情况下提供了灵活性。其一,如果要决定将实现由 ArrayList 转变为数据库形式,余下的应用程序与该变化是隔绝的。其二,使用接口为单元测试提供灵活性。例如,如果要决定为应用程序使用数据库,可以轻易地创建一个该类型的模拟实现,而且它不依赖于实时数据库。

清单 5 是 RentABike 接口的 Java 实现,它使用 ArrayList 来存储多个 Bike 类:


清单 5. RentABike 接口的 Java 实现
    
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

public class ArrayListRentABike implements RentABike {
private String storeName;
final List bikes = new ArrayList();

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

public String getStoreName() {
return storeName;
}

public ArrayListRentABike(String storeName) {
this.storeName = storeName;
bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Fair"));
bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222",12, "Excellent"));
bikes.add(new Bike("Trek","6000", 19, "33333", 12.4,"Fair"));
}

public String toString() { return "com.springbook.RentABike: " + storeName; }

public List getBikes() { return bikes; }

public Bike getBike(String serialNo) {
Iterator iter = bikes.iterator();
while(iter.hasNext()) {
Bike bike = (Bike)iter.next();
if(serialNo.equals(bike.getSerialNo())) return bike;

}
return null;
}
}

现在将 清单 45 中的 Java 代码同 清单 6 中的 Groovy 代码进行比较。Groovy 版的代码很灵巧地避免了对 RentABike 接口的需求。


清单 6. Groovy 的 ArrayListRentABike 实现
  
public class ArrayListRentABike {
String storeName
List bikes = []
public ArrayListRentABike(){
// add new instances of Bike using Groovy's initializer syntax
bikes << new Bike(manufacturer:"Shimano", model:"Roadmaster",
frame: 20, serialNo:"11111", weight:15, status:"Fair")
bikes << new Bike(manufacturer:"Cannondale", model:"F2000",
frame: 18, serialNo:"22222", weight:12, status:"Excellent")
bikes << new Bike(manufacturer:"Trek", model:"6000",
frame: 19, serialNo:"33333", weight:12.4, status:"Fair")
}

// Groovy returns the last value if no return statement is specified
public String toString() { "Store Name:=" + storeName }

// Find a bike by the serial number
def getBike(serialNo) { bikes.find{it.serialNo == serialNo} }

}

Groovy 像其他动态语言(如 Smalltalk 或 Ruby)一样支持具有 “duck typing” 的多态 —— 在运行时,如果一个对象表现得像个 duck ,它就会被视为 duck ,从而支持 接口的多态。有了 Groovy ArrayListRentABike 实现,不但减少了成行的代码,而且由于少创建和维护一个模块,复杂性也降低了。那是非常重要的冗余减少!

除了 duck typing,清单 6 中的默认属性语法还简单地定义了两个普通属性,storeNamebikes,如同拥有了 getter 和 setter 一样。这样做的好处和在 清单 12 中比较 JavaBean-GroovyBean 时所说明的好处是一样的。尤其是,清单 6 还阐明了另一个用以减少代码冗余的 Groovy 特性 —— 操作符重载。请注意如何使用 << 操作符来代替 add() 方法。通过减少一层嵌套的括号使代码的可读性得以改善。这也是 Groovy 众多通过减少冗余而改善代码可读性的特性中的一种。

Groovy 方式下的和谐集合
用诸如 eachfind 的方法来使用闭包简化了最常见的任务集,如循环和查找。将 清单 5 中 Java 版本的 getBike()清单 6 中 Groovy 版的进行比较。在 Groovy 中,很明显是通过其序列号来寻找 Bike。而在 Java 版中,定义了一个 Iterator 并计算列表中下一个条目,这很多余,且不利于理解该应用程序真正要实现的功能,即寻找一辆自行车。

透明的代码

Groovy 中的 duck-typing 和属性语义通过减少代码行数来减少冗余;然而,也可以通过增加透明度来减少冗余。在 清单 6 中,请注意在 ArrayListRentABike 构造函数中创建新 Bike 对象的方式。Groovy 名称和值的初始化语法比 Java 版的略微详细,但这些额外的代码却使整个代码更为透明 —— 将这一点与 清单 5 中 Java 版的进行比较,哪个属性被初始化为哪个值会立即明显 起来。不回过头来看 Bike JavaBean 源代码,您能记起哪个参数是 frame,哪个是 new Bike("Shimano"、 "Roadmaster"、20、 "11111"、15、 "Fair")weight 吗?尽管我刚写过,但我还是记不起来!





回页首


一个更小的、更加 Groovy 化的自行车商店视图

到目前为止,我将 Bike 和自行车商店类型在 Java 和 Groovy 下进行了比较。现在,到了更近距离地看一下自行车商店的视图 的时候了。在清单 7 中,该视图类具有一个 rentaBike 属性,该属性引用 RentABike 接口并在行动上说明 Java 版的多态。由于 Java 要求所有类属性都必须是声明过的类型,而不是针对某个特定的实现进行编码,我向一个接口编程,该接口使这个类跟 RentABike 实现的改变分隔开来。这是很好的、扎实的 Java 编程实践。


清单 7. Java 版的自行车商店视图
  
public class CommandLineView {
private RentABike rentaBike;

public CommandLineView() {}

public void setRentaBike(RentABike rentaBike) {
this.rentaBike = rentaBike;
}

public RentABike getRentaBike() { return this.rentaBike; }

public void printAllBikes() {
System.out.println(rentaBike.toString());
Iterator iter = rentaBike.getBikes().iterator();
while(iter.hasNext()) {
Bike bike = (Bike)iter.next();
System.out.println(bike.toString());
}
}
}

将清单 7 中的 Java 视图与清单 8 中的 Groovy 视图进行比较,请注意我声明了带 def 关键字的 rentaBike。这是 duck-typing 的实践,与 Java 版的很像。我正在实践好的软件设计,这是因为我还没有将视图和特定的实现耦合起来。但我也能够 定义接口就实现解耦。


清单 8. Groovy 的 CommandLineView
  
public class CommandLineView {
def rentaBike // no interface or concrete type required, duck typing in action

def printAllBikes() {
println rentaBike
rentaBike.bikes.each{ println it} // no iterators or casting
}
}

Bike 和自行车商店类型一样,Groovy 的 CommandLineView 没有了为 RentABike 属性所显式编写 的 getter 或 setter 的冗余。同样,在 printAllBikes() 方法中,通过使用 each 来打印在集合里找到的每辆自行车,我再一次利用了 Groovy 强大的集合功能的改进。





回页首


使用 Spring 进行组装

在前面的部分中,已经介绍了 Groovy 相比 Java 是如何定义自行车、自行车商店和自行车商店视图的。现在该介绍如何将整个应用程序组装起来并在命令行视图中使用 Spring 来显示库存自行车列表了。

工厂的工厂

在 Java 编程中,一旦定义了一个接口,就可以使用工厂模式将创建真实的实现类的责任委派给一个对象工厂。使用 Spring 作为一个工厂极大地减少了冗余,并在 Groovy 和 Java 中都能够使用,在最终的代码样例中,Spring 负责在 Java 和 Groovy 中创建一个 CommandLineView 类型的实例。

在清单 9 中,配置 Spring 是为了在返回一个 CommandLineView 实例前,创建并将自行车商店的 ArrayList 实现注入 CommandLineView 中。这意味着,不需要引用在 清单 78 的 Java 或是 Groovy 版的命令行视图中的 ArrayList 实现。在 Java 版中,被注入的类通常都会引用一个接口而不是实现。在 Groovy 中,由于使用 def 关键字,而允许利用 duck-typing。无论在哪个实例中,配置 Spring 的目的都是为了将自行车商店视图的实例和自行车商店类型的实例完整地配置起来


清单 9. Spring 配置文件
        
<beans>
<bean id="rentaBike" class="ArrayListRentABike">
<property name="storeName"><value>"Bruce's Bikes (spring bean)"</value></property>
</bean>
<bean id="commandLineView" class="CommandLineView">
<property name="rentaBike"><ref bean="rentaBike"/></property>
</bean>
</beans>

在清单 10 和 11 中,自行车商店组装类型用清单 9 中的配置文件创建了一个 Spring 的 ClassPathXmlApplicationContext 实例,然后,请求自行车商店视图的实例:


清单 10. Java 版本下调用 Spring 创建自行车商店视图
  
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RentABikeAssembler {
public static final void main(String[] args) {
// Create a Spring application context object
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext("RentABike-context.xml");

// retrieve an object from Spring and cast to a specific type
CommandLineView clv = (CommandLineView)ctx.getBean("commandLineView");

clv.printAllBikes();
}
}

请注意Java 版的清单 10 中,用以请求一个命令行视图实例的对 Spring 的调用要求向一个支持 printAllBikes() 方法的对象类型强制转换。在本例中,由 Spring 导出的对象将被强制转换为 CommandLineView

有了 Groovy 及其对 duck-typing 的支持,将不再需要强制转换。只需确保由 Spring 返回的类能够对合适的方法调用(printAllBikes())作出响应。


清单 11. Groovy 版的 Spring 组合件
  
import org.springframework.context.support.ClassPathXmlApplicationContext

class RentABikeAssembler {
public static final void main(String[] args) {
// Create a Spring application context object
def ctx = new ClassPathXmlApplicationContext("RentABike-context.xml")

//Ask Spring for an instance of CommandLineView, with a
//Bike store implementation set by Spring
def clv = ctx.getBean("commandLineView")

//duck typing again
clv.printAllBikes()
}
}

正如在清单 11 中看到的那样,在 Groovy 中,duck-typing 对减少冗余的贡献不仅体现在无需声明接口即可支持由 Spring 自动配置对象,其贡献还体现在简化了对完全配置的 bean 的使用(一旦它从 Spring 容器中返回)。





回页首


与 Groovy 相协调

至此,希望我已经阐明了 Groovy 的强大功能及其如何能如此深远地改变源代码的性质。与上述 Java 样例相比,Groovy 代码更简短也更易理解。任何人,无论是经验丰富的 Java 架构师还是非 Java 程序员,都能轻易地掌握 Groovy 代码的意图。Groovy 及其对动态类型的支持减少了要管理的文件。总之,使用 Groovy 减少了在典型的 Java 程序中所常见的大量冗余。这实在是福音啊!

Posted on October 19, 2006 10:46 PM | | Comments (0) | TrackBacks (0)

http://www-900.ibm.com/developerWorks/cn/linux/opensource/os-ecshare/index.shtml

Posted on October 18, 2006 12:16 PM | | Comments (0) | TrackBacks (0)

  摘 要 目前流行的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企业应用的系统框架可谓百花齐放,各种框架都有长短,选择应用系统框架时不可盲目的追求流行,首先需要明确所要实现的应用系统的系统处 理能力需求,然后在熟悉比较各种框架细节的基础上从设计以及开发效率方面进行考虑。本文旨在为系统框架选择提供一个参考,限于篇幅本文只对其中的几种框架 做了比较,开发者可以根据需要对更多其他框架细节进行比较。

Posted on October 15, 2006 4:32 PM | | Comments (0) | TrackBacks (0)

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

Posted on September 10, 2006 2:32 PM | | Comments (0) | TrackBacks (0)

开源网站:

http://www.open-open.com 中文版

http://java-source.net/ 英文版

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/

Posted on July 31, 2006 1:05 AM | | Comments (0) | TrackBacks (0)

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” )
$email
\$email
\\$email
\\\$email
将render为:
foo
$email
\foo
\\$email
如果email变量没有被定义则
$email
\$email
\\$email
\\\$email
将被render为:
$email
\$email
\\$email
\\\$email
注意: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” )
   erion) )
#if( $result )
Query was successful
#end
#end
在上面的例子中,程序将不能智能的根据$result的值决定查询是否成功。在$result被#set后(added to the context),它不能被设置回null(removed from the context)。打印的结果将显示两次查询结果都成功了,但是实际上有一个查询是失败的。
为了解决以上问题我们可以通过预先定义的方式:
#set( $criteria = [“name”, “address”] )
#foreach( $criterion in $criteria )
#set( $result = false )
#set( $result = $query.criteria( $criterion ) )
#if( $result )
Query was successful
#end
#end

String Literals
当你使用#set directive,String literal封闭在一对双引号内。
#set ( $directoryRoot = “www” )
#set ( $templateName = “index.vm” )
#set ( $template = “$directoryRoot/$tempateName” )
$template
上面这段代码的输出结果为:www/index.vm
但是,当string literal被封装在单引号内时,它将不被解析:
#set ( $foo = “bar” )
$foo
#set ( $blargh = ‘$foo’ )
结果:
bar
$foo
上面这个特性可以通过修改velocity.properties文件的stringliterals.interpolate = false的值来改变上面的特性是否有效。

2.条件语句 if/elseif/else

当一个web页面被生成时使用Velocity的#if directrive,如果条件成立的话可以在页面内嵌入文字。例如:
#if ( $foo )
Velocity!
#end

上例中的条件语句将在以下两种条件下成立:
l $foo是一个boolean型的变量,且它的值为true
l $foo变量的值不为null
这里需要注意一点:Velocity context仅仅能够包含对象,所以当我们说“boolean”时实际上代表的时一个Boolean对象。即便某个方法返回的是一个boolean值,Velocity也会利用内省机制将它转换为一个Boolean的相同值。
如果条件成立,那么#if和#end之间的内容将被显示。
#elseif和#else元素可以同#if一同使用。例如:
#if( $foo < 10 )
Go North
#elseif( $foo == 10 )
Go East
#elseif( $foo == 6 )
Go South
#else
Go West
#end
注意这里的Velocity的数字是作为Integer来比较的――其他类型的对象将使得条件为false,但是与java不同它使用“==”来比较两个值,而且velocity要求等号两边的值类型相同。
关系、逻辑运算符
Velocity中使用等号操作符判断两个变量的关系。例如:
#set ( $foo = “deoxyribonucleic acid” )
#set ( $bar = “ribonucleic acid” )
#if ( $foo == $foo )
In this case it’s clear they aren’t equivalent.So…
#else
They are not equivalent and this will be the output.
#end

3.Velocity有AND、OR和NOT逻辑运算符

下面是一些例子:
## logical AND
#if( $foo && $bar )
This AND that
#end

## logical OR
#if ( $foo || $bar )
This OR That
#end

##logical NOT
#if ( !$foo )
NOT that
#end


4.循环
Foreach循环

例子:

    #foreach ( $product in $allProducts )
  • $product

  • #end

每次循环$allProducts中的一个值都会赋给$product变量。
$allProducts 可以是一个Vector、Hashtable或者Array。分配给$product的值是一个java对象,并且可以通过变量被引用。例如:如果$ product是一个java的Product类,并且这个产品的名字可以通过调用他的getName()方法得到。
现在我们假设$allProducts是一个Hashtable,如果你希望得到它的key应该像下面这样:

    #foreach ( $key in $allProducts.keySet() )
  • Key: $key -> Value: $allProducts.get($key)

  • #end


Velocity还特别提供了得到循环次数的方法,以便你可以像下面这样作:


#foreach ( $customer in $customerList )

#end
$velocityCount $customer.Name

$velocityCount 变量的名字是Velocity默认的名字,你也可以通过修改velocity.properties文件来改变它。默认情况下,计数从“1”开始,但是你可以在velocity.properties设置它是从“1”还是从“0”开始。下面就是文件中的配置:
# Default name of loop counter
# variable reference
directive.foreach.counter.name = velocityCount

# Default starting value of the loop
# counter variable reference
directive.foreach.counter.initial.value = 1

5.include

#include script element允许模板设计者引入本地文件。被引入文件的内容将不会通过模板引擎被render。为了安全的原因,被引入的本地文件只能在TEMPLATE_ROOT目录下。
#inclued ( “one.txt” )
如果您需要引入多个文件,可以用逗号分隔就行:
#include ( “one.gif”, “two.txt”, “three.htm” )
在括号内可以是文件名,但是更多的时候是使用变量的:
#inclue ( “greetings.txt”, $seasonalstock )

6.parse

#parse script element允许模板设计者一个包含VTL的本地文件。Velocity将解析其中的VTL并render模板。
#parse( “me.vm” )
就像#include,#parse接受一个变量而不是一个模板。任何由#parse指向的模板都必须包含在TEMPLATE_ROOT目录下。与#include不同的是,#parse只能指定单个对象。
你可以通过修改velocity.properties文件的parse_direcive.maxdepth的值来控制一个template可以包含的最多#parse的个数――默认值是10。#parse是可以递归调用的,例如:如果dofoo.vm包含如下行:
Count down.
#set ( $count = 8 )
#parse ( “parsefoo.vm” )
All done with dofoo.vm!
那么在parsefoo.vm模板中,你可以包含如下VTL:
$count
#set ( $count = $count – 1 )
#if ( $count > 0 )
#parse( “parsefoo.vm” )
#else
All done with parsefoo.vm!
#end
的显示结果为:
Count down.
8
7
6
5
4
3
2
1
0
All done with parsefoo.vm!
All done with dofoo.vm!

7.Stop

#stop script element允许模板设计者停止执行模板引擎并返回。把它应用于debug是很有帮助的。
#stop

8.Velocimacros

#macro script element允许模板设计者定义一段可重用的VTL template。例如:
#macro ( d )
 
 
$something

#tablerows( $color $greatlakes )

经过以上的调用将产生如下的显示结果:






Superior
Michigan
Huron
Erie
Ontario


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将产生如下的输出:






volva
stipe
annulus
gills
pileus


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)。注意这个属性实际上是针对开发而非产品的。


Velocimacro Trivia
Velocimacro必须被定义在他们被使用之前。也就是说,你的#macro()声明应该出现在使用Velocimacros之前。
特别要注意的是,如果你试图#parse()一个包含#macro()的模板。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用 velocimacro.library使得Velocity在启动时加载你的VMs。

11.Escaping VTL directives

VTL directives can be escaped with “\”号,使用方式跟VTL的reference使用逃逸符的格式差不多。
## #include( “a.txt” ) renders as (注释行)
#include( “a.txt” )

## \#include( “a.txt” ) renders as \#include( “a.txt” )
\#include( “a.txt” )

## \\#include ( “a.txt” ) renders as \
\\#include( “a.txt” )
在对在一个directive内包含多个script元素的VTL directives使用逃逸符时要特别小心(比如在一个if-else-end statement内)。下面是VTL的if-statement的典型应用:
#if ( $jazz )
Vyacheslav Ganelin
#end
如果$jazz是ture,输出将是:
Vyacheslav Ganelin
如果$jazz是false,将没有输出。使用逃逸符将改变输出。考虑一下下面的情况:
\#if ( $jazz )
Vyacheslav Ganelin
\#end
现在无论$jazz是true还是false,输出结果都是:
#if ( $jazz )
Vyacheslav Ganelin
#end
事实上,由于你使用了逃逸符,$jazz根本就没有被解析为boolean型值。在逃逸符前使用逃逸符是合法的,例如:
\\#if ( $jazz )
Vyacheslav Ganelin
\\#end
以上程序的显示结果为:
\ Vyacheslav Ganelin
\
但是如果$jazz为false,那么将没有输出。(书上说会没有输出,但是我觉得应该还有有“\”字符被输出。)
VTL:Formatting issues
尽管在此用户手册中VTL通常都开始一个新行,如下所示:
#set ( $imperial = [ “Munetaka”, “Koreyasu”, “Hisakira”, “Morikune” ] )
#foreach ( $shogun in $imperial )
$shogun
#end
但是像下面这种写法也是可以的:
Send me #set($foo = [“$10 and”,”a cake”])#foreach($a in $foo)$a #end please.
上面的代码可以被改写为:
Send me
#set ( $foo = [“$10 and “,”a cake”] )
#foreach ( $a in $foo )
$a
#end
please.
或者
Send me
#set($foo = [“$10 and “,”a cake”])
#foreach ($a in $foo )$a
#end please.
这两种的输出结构将一样。
其他特性和杂项
math 在模板中可以使用Velocity内建的算术函数,如:加、减、乘、除
#set ( $foo = $bar + 3 )
#set ( $foo = $bar - 4 )
#set ( $foo = $bar * 6 )
#set ( $foo = $bar / 2 )
当执行除法时将返回一个Integer类型的结果。而余数你可以使用%来得到:
#set ( $foo = $bar % 5 )
在Velocity内使用数学计算公式时,只能使用像-n,-2,-1,0,1,2,n这样的整数,而不能使用其它类型数据。当一个非整型的对象被使用时它将被logged并且将以null作为输出结果。

12.Range Operator

Range operator可以被用于与#set和#foreach statement联合使用。对于处理一个整型数组它是很有用的,Range operator具有以下构造形式:
[n..m]
m和n都必须是整型,而m是否大于n则无关紧要。例子:
First example:
#foreach ( $foo in [1..5] )
$foo
#end

Second example:
#foreach ( $bar in [2..-2] )
$bar
#end

Third example:
#set ( $arr = [0..1] )
#foreach ( $i in $arr )
$i
#end

Fourth example:
[1..3]
上面四个例子的输出结果为:
First example:
1 2 3 4 5

Second example:
2 1 0 -1 -2

Third example:
0 1

Fourth example:
[1..3]
注意:range operator只在#set和#foreach中有效。
Advanced Issue:Escaping and!
当一个reference被“!”分隔时,并且在它之前有逃逸符时,reference将以特殊的方式处理。注意这种方式与标准的逃逸方式时不同的。对照如下:
#set ( $foo = “bar” )
特殊形式 标准格式
Render前 Render后 Render前 Render后
$\!foo $!foo \$foo \$foo
$\!{foo} $!{foo} \$!foo \$!foo
$\\!foo $\!foo \$!{foo} \$!{foo}
$\\\!foo $\\!foo \\$!{foo} \bar


13.Velocimacro杂记

Can I user a directive or another VM as an argument to a VM?
例如:#center ( #bold( “hello” ) )
不可以。一个directive的参数使用另外一个directive是不合法的。
但是,还是有些事情你可以作的。最简单的方式就是使用双引号:
#set ( $stuff = “#bold( ‘hello’ )” )
#center ( $stuff )
上面的格式也可以缩写为一行:
#center ( “#bold( ‘hello’ ) )
请注意在下面的例子中参数被evaluated在Velocimacro内部,而不是在calling level。例子:
#macro ( inner $foo )
inner : $foo
#end

#macro ( outer $foo )
#set ( $bar = “outerlala” )
outer : $foo
#end

#set ( $bar = ‘calltimelala’ )
#outer( “#inner($bar)” )
输出结果为:
outer : inner : outerlala
记住Veloctiy的特性:参数的传递是By Name的。例如:
#macro ( foo $color )

Hi
There

#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。
   全局定义。
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)。注意这个属性实际上是针对开发而非产品的。


Velocimacro Trivia
Velocimacro必须被定义在他们被使用之前。也就是说,你的#macro()声明应该出现在使用Velocimacros之前。
特别要注意的是,如果你试图#parse()一个包含#macro()的模板。因为#parse()发生在运行期,但是解析器在parsetiem决定一个看似VM元素的元素是否是一个VM元素,这样#parse()-ing一组VM声明将不按照预期的样子工作。为了得到预期的结果,只需要你简单的使用 velocimacro.library使得Velocity在启动时加载你的VMs。

11.Escaping VTL directives

VTL directives can be escaped with “\”号,使用方式跟VTL的reference使用逃逸符的格式差不多。
## #include( “a.txt” ) renders as (注释行)
#include( “a.txt” )

## \#include( “a.txt” ) renders as \#include( “a.txt” )
\#include( “a.txt” )

## \\#include ( “a.txt” ) renders as \
\\#include( “a.txt” )
在对在一个directive内包含多个script元素的VTL directives使用逃逸符时要特别小心(比如在一个if-else-end statement内)。下面是VTL的if-statement的典型应用:
#if ( $jazz )
Vyacheslav Ganelin
#end
如果$jazz是ture,输出将是:
Vyacheslav Ganelin
如果$jazz是false,将没有输出。使用逃逸符将改变输出。考虑一下下面的情况:
\#if ( $jazz )
Vyacheslav Ganelin
\#end
现在无论$jazz是true还是false,输出结果都是:
#if ( $jazz )
Vyacheslav Ganelin
#end
事实上,由于你使用了逃逸符,$jazz根本就没有被解析为boolean型值。在逃逸符前使用逃逸符是合法的,例如:
\\#if ( $jazz )
Vyacheslav Ganelin
\\#end
以上程序的显示结果为:
\ Vyacheslav Ganelin
\
但是如果$jazz为false,那么将没有输出。(书上说会没有输出,但是我觉得应该还有有“\”字符被输出。)
VTL:Formatting issues
尽管在此用户手册中VTL通常都开始一个新行,如下所示:
#set ( $imperial = [ “Munetaka”, “Koreyasu”, “Hisakira”, “Morikune” ] )
#foreach ( $shogun in $imperial )
$shogun
#end
但是像下面这种写法也是可以的:
Send me #set($foo = [“$10 and”,”a cake”])#foreach($a in $foo)$a #end please.
上面的代码可以被改写为:
Send me
#set ( $foo = [“$10 and “,”a cake”] )
#foreach ( $a in $foo )
$a
#end
please.
或者
Send me
#set($foo = [“$10 and “,”a cake”])
#foreach ($a in $foo )$a
#end please.
这两种的输出结构将一样。
其他特性和杂项
math 在模板中可以使用Velocity内建的算术函数,如:加、减、乘、除
#set ( $foo = $bar + 3 )
#set ( $foo = $bar - 4 )
#set ( $foo = $bar * 6 )
#set ( $foo = $bar / 2 )
当执行除法时将返回一个Integer类型的结果。而余数你可以使用%来得到:
#set ( $foo = $bar % 5 )
在Velocity内使用数学计算公式时,只能使用像-n,-2,-1,0,1,2,n这样的整数,而不能使用其它类型数据。当一个非整型的对象被使用时它将被logged并且将以null作为输出结果。

12.Range Operator

Range operator可以被用于与#set和#foreach statement联合使用。对于处理一个整型数组它是很有用的,Range operator具有以下构造形式:
[n..m]
m和n都必须是整型,而m是否大于n则无关紧要。例子:
First example:
#foreach ( $foo in [1..5] )
$foo
#end

Second example:
#foreach ( $bar in [2..-2] )
$bar
#end

Third example:
#set ( $arr = [0..1] )
#foreach ( $i in $arr )
$i
#end

Fourth example:
[1..3]
上面四个例子的输出结果为:
First example:
1 2 3 4 5

Second example:
2 1 0 -1 -2

Third example:
0 1

Fourth example:
[1..3]
注意:range operator只在#set和#foreach中有效。
Advanced Issue:Escaping and!
当一个reference被“!”分隔时,并且在它之前有逃逸符时,reference将以特殊的方式处理。注意这种方式与标准的逃逸方式时不同的。对照如下:
#set ( $foo = “bar” )
特殊形式 标准格式
Render前 Render后 Render前 Render后
$\!foo $!foo \$foo \$foo
$\!{foo} $!{foo} \$!foo \$!foo
$\\!foo $\!foo \$!{foo} \$!{foo}
$\\\!foo $\\!foo \\$!{foo} \bar


13.Velocimacro杂记

Can I user a directive or another VM as an argument to a VM?
例如:#center ( #bold( “hello” ) )
不可以。一个directive的参数使用另外一个directive是不合法的。
但是,还是有些事情你可以作的。最简单的方式就是使用双引号:
#set ( $stuff = “#bold( ‘hello’ )” )
#center ( $stuff )
上面的格式也可以缩写为一行:
#center ( “#bold( ‘hello’ ) )
请注意在下面的例子中参数被evaluated在Velocimacro内部,而不是在calling level。例子:
#macro ( inner $foo )
inner : $foo
#end

#macro ( outer $foo )
#set ( $bar = “outerlala” )
outer : $foo
#end

#set ( $bar = ‘calltimelala’ )
#outer( “#inner($bar)” )
输出结果为:
outer : inner : outerlala
记住Veloctiy的特性:参数的传递是By Name的。例如:
#macro ( foo $color )

Hi
There
Posted on July 27, 2006 5:58 PM | | Comments (0) | TrackBacks (0)