﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-helloworld</title><link>http://www.blogjava.net/over1988/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 30 Apr 2026 06:25:46 GMT</lastBuildDate><pubDate>Thu, 30 Apr 2026 06:25:46 GMT</pubDate><ttl>60</ttl><item><title>严重: IOException while loading persisted sessions: java.io.EOFException</title><link>http://www.blogjava.net/over1988/archive/2008/11/04/238606.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Tue, 04 Nov 2008 07:17:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/11/04/238606.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/over1988/archive/2008/11/04/238606.html'>阅读全文</a><img src ="http://www.blogjava.net/over1988/aggbug/238606.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-11-04 15:17 <a href="http://www.blogjava.net/over1988/archive/2008/11/04/238606.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习JPA——Hibernate Annotation使用实例(转自CSDN)</title><link>http://www.blogjava.net/over1988/archive/2008/10/02/232072.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Thu, 02 Oct 2008 03:01:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/10/02/232072.html</guid><wfw:comment>http://www.blogjava.net/over1988/comments/232072.html</wfw:comment><comments>http://www.blogjava.net/over1988/archive/2008/10/02/232072.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/over1988/comments/commentRss/232072.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/over1988/services/trackbacks/232072.html</trackback:ping><description><![CDATA[<span  style="font-family: Tahoma; font-size: 14px; line-height: 20px; ">目前，JPA（Java Persistence API）的使用范围越来越广，作为Java EE 5.0平台标准的ORM规范，得到了诸如：Hibernate、TopLink、OpenJpa等ORM框架的支持，同时还是EJB 3.0的重要组成部分。JPA的宗旨是为POJO提供持久化标准规范。它能够脱离容器独立运行，方便开发和测试。本文将通过一个小实例来说明如何在Hibernate中使用JPA，来达到简化编程的目的。<br />
开发环境 Eclipse 3.3.1 MyEclipse 6.0.1GA Tomcat 6.10 SQL Server 2000&#160;<br />
hibernate-3.2.5.GA hibernate-annotations-3.3.0.GA<br />
ejb3-persistence hibernate-commons-annotations-3.0.0.GA<br />
本文是为后续的多种Ajax技术框架应用系列作一个前期准备，让大家先了解一下相比与以前的Hibernate ORM映射的不同之处，以及采用JPA所带来的好处。<br />
为了保证程序能顺序运行，避免不同的Eclipse版本之间产生错误，大象强烈建议，下载源码后，按源码中的工程名，自己单独新建同一个工程，再将src和WEB-INF/lib目录下的所有文件COPY至对应的目录下。<br />
1、创建Web Project<br />
点击"File"->"New"，选择"Web Project"，在"Project Name"中输入ajax，点击"Finish"。下载本文后面需要用到的JAR包，加入到WEB-INF/lib目录下，在ajax工程中，文本采用的是UTF-8编码。<br />
2、创建HibernateSessionFactory<br />
传统的方法就是在工程名上点右键，选择&#8221;MyEclipse&#8221;->&#8221;Add Hibernate Capabilities&#8221;，然后就是按照提示一步一步做，不过在MyEclipse 6.0.1中添加Hibernate还是只能支持3.1，除非你选择&#8221; Add Spring Capabilities&#8221;，里面才有Hibernate 3.2的类库，要想完全兼容JPA，必须采用3.2以上版本。<br />
<br />
这里大家直接使用源码中的HibernateSessionFactory，注意请先建包：com.ajax.core,HibernateSessionFactory中有一个地方需要改动，原来的写法是：<br />
private static Configuration configuration = new Configuration(); 修改后为：<br />
private static AnnotationConfiguration configuration = new AnnotationConfiguration(); 因为我们采用的是JPA注释方式来映射实体，另外AnnotationConfiguration这个类在hibernate-annotations.jar这个包中。<br />
3、创建BaseDao<br />
在com.ajax.core包下面新建BaseDao抽象类，里面定义的是持久化操作方法，有一点特别要注意，一定要在增加、删除、修改这几个方法中加入事务控制，不管是在BaseDao基类方法中加，还是在业务方法中加，一定要加事务控制，大象觉得在基类中加会比较好一点，这样做代码显得更少更简洁。如果不加事务控制，那么增、删、改这些操作都不会产生效果，因为默认情况下，它不会进行自动提交。在做这个例子的时候，这个问题曾经困扰了我好长时间。因此，请大家记住不要再犯和大象一样的错误！贴出部分代码，详情请看源码，里面有很全面的注释。<br />
/**<br />
* 抽象Dao类，用于持久化操作<br />
* @author 菠萝大象<br />
* @version 1.0<br />
*/<br />
public abstract class BaseDao<t>&#160;{<br />
<br />
private static Log log = LogFactory.getLog(BaseDao.class);&#160;<br />
<br />
/**<br />
* 获取Hibernate的Session对象<br />
*/<br />
public Session getSession(){<br />
return HibernateSessionFactory.getSession();&#160;<br />
}<br />
<br />
/**<br />
* 根据主键得到对象<br />
*/<br />
public T getObject(Class clazz, Serializable id){<br />
return (T)getSession().get(clazz, id);&#160;<br />
}<br />
<br />
/**<br />
* 保存对象<br />
*/<br />
public void saveObject(T t) {<br />
Session session = getSession();&#160;<br />
Transaction tx = beginTransaction(session);&#160;<br />
try{<br />
session.saveOrUpdate(t);&#160;<br />
tx.commit();&#160;<br />
}catch(Exception e){<br />
tx.rollback();&#160;<br />
log.error("保存对象失败");&#160;<br />
}<br />
}<br />
<br />
/**<br />
* 创建事务<br />
*/<br />
private Transaction beginTransaction(Session session){<br />
return session.beginTransaction();&#160;<br />
}<br />
} 4、创建Employee<br />
在com.ajax.employee.mode包下新建Employee类，这个就是POJO类，下面来详细说明里面的含义。<br />
@Entity<br />
@Table(name = "EMPLOYEE")<br />
public class Employee implements java.io.Serializable{<br />
<br />
private Integer employee_id; //人员ID（主键）<br />
private String employee_name; //人员姓名<br />
private String sex; //性别<br />
private String birthday; //出生日期<br />
private String address; //地址<br />
<br />
@Id<br />
@Column(name = "EMPLOYEE_ID")<br />
@TableGenerator(<br />
name="tab-store",<br />
table="GENERATOR_TABLE",<br />
pkColumnName = "G_KEY",<br />
pkColumnValue="EMPLOYEE_PK",<br />
valueColumnName = "G_VALUE",<br />
allocationSize=1<br />
)<br />
@GeneratedValue(strategy = GenerationType.TABLE,generator="tab-store")<br />
public Integer getEmployee_id() {<br />
return employee_id;&#160;<br />
}<br />
public void setEmployee_id(Integer employee_id) {<br />
this.employee_id = employee_id;&#160;<br />
}<br />
} 其它几个属性的getter和setter省略，这里我们要用到ejb3-persistence.jar，JPA的注解类就在这个包中，下面详细说明上面使用到的注解。<br />
@Entity：通过@Entity注解将一个类声明为一个实体bean<br />
@Table：通过 @Table注解可以为实体bean映射指定表，name属性表示实体所对应表的名称，如果没有定义 @Table，那么系统自动使用默认值：实体的类名（不带包名）<br />
@Id：用于标记属性的主键<br />
@Column：表示持久化属性所映射表中的字段，如果属性名与表中的字段名相同，则可以省略@Column注解，另外有两种方式标记，一是放在属性前，另一种是放在getter方法前，例如：<br />
@Column(name = "EMPLOYEE_NAME")<br />
private String employee_name; 或者<br />
@Column(name = "EMPLOYEE_NAME")<br />
public String getEmployee_name() {<br />
return employee_name;&#160;<br />
} 这两种方式都是正解的，根据个人喜好来选择。大象偏向于第二种，并且喜欢将属性名与字段名设成一样的，这样可以省掉@Column注解，使代码更简洁。<br />
@TableGenerator：表生成器，将当前主键的值单独保存到一个数据库表中，主键的值每次都是从指定的表中查询来获得，这种生成主键的方式是很常用的。这种方法生成主键的策略可以适用于任何数据库，不必担心不同数据库不兼容造成的问题。大象推荐这种方式管理主键，很方便，集中式管理表的主键，而且更换数据库不会造成很大的问题。各属性含义如下：<br />
name：表示该表主键生成策略的名称，这个名字可以自定义，它被引用在@GeneratedValue中设置的"generator"值中<br />
table：表示表生成策略所持久化的表名，说简单点就是一个管理其它表主键的表，本例中，这个表名为GENERATOR_TABLE<br />
pkColumnName：表生成器中的列名，用来存放其它表的主键键名，这个列名是与表中的字段对应的<br />
pkColumnValue：实体表所对应到生成器表中的主键名，这个键名是可以自定义滴<br />
valueColumnName：表生成器中的列名，实体表主键的下一个值，假设EMPLOYEE表中的EMPLOYEE_ID最大为2，那么此时，生成器表中与实体表主键对应的键名值则为3<br />
allocationSize：表示每次主键值增加的大小，例如设置成1，则表示每次创建新记录后自动加1，默认为50<br />
<br />
@GeneratedValue：定义主键生成策略，这里因为使用的是TableGenerator，所以，主键的生成策略为GenerationType.TABLE，生成主键策略的名称则为前面定义的&#8221;tab-store&#8221;。<br />
这里大象想说下，网上有很多文章写的是strategy = GenerationType.AUTO或是strategy = GenerationType.SEQUENCE，采用SEQUENCE序列是因为Oracle数据中不支持identity自动增长，要想使用它，还得在数据库中创建一个序列，如果要更换数据库，那将是一个非常麻烦的事情。SEQUENCE生成方式我们暂且不谈，这里说下采用AUTO和IDENTITY的生成方式，本例采用的是SQL Server 2000作为数据库，所以如果想使用AUTO或是IDENTITY生成策略，则一定要对主键加上identity标识，如identity(1,1)。不过对于AUTO来说，是根据不同的数据库选择最合适的自增主键生成策略。如果使用MySQL，则主键要定义AUTO_INCREMENT，如果是Oracle，则要创建Sequence来实现自增。不管采用何种生成策略，增、删、改这些方法中一定要加入事务，否则数据是不会添加到数据库中滴~~~这是大象反复测试过的结果！<br />
5、创建数据库及表<br />
接下来，我们需要为本例创建一个数据库及必要的表。数据库名为ajax，表只有两个EMPLOYEE和GENERATOR_TABLE，下面是SQL脚本：<br />
CREATE TABLE EMPLOYEE(<br />
EMPLOYEE_ID int not null,<br />
EMPLOYEE_NAME varchar (20) null,<br />
SEX char (2) null,<br />
BIRTHDAY varchar(10) null,<br />
ADDRESS varchar(50) null,<br />
CONSTRAINT PK_EMPLOYEE PRIMARY KEY (EMPLOYEE_ID)<br />
)&#160;<br />
<br />
CREATE TABLE GENERATOR_TABLE(<br />
ID int not null,<br />
G_KEY varchar(20) null,<br />
G_VALUE int null,<br />
CONSTRAINT PK_GENERATOR_TABLE PRIMARY KEY (ID)&#160;<br />
)<br />
<br />
INSERT INTO GENERATOR_TABLE VALUES(1,EMPLOYEE_PK,1) 如果你觉得麻烦，不想建库及表，可以将后面的数据库下载下来，然后还原数据库就可以了。<br />
6、修改hibernate.cfg.xml<br />
本例中，采用的是JTDS连接驱动，我们要对配置文件作一些设置，另外还要加入POJO类。<br />
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<br />
<property name="connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
<br />
<property name="connection.url">jdbc:jtds:sqlserver://localhost:1433/ajax</property>
<br />
<property name="connection.username">sa</property>
<br />
<property name="connection.password">自己密码(无密码就空着)</property>
<br />
<br />
<mapping class="com.ajax.employee.model.Employee">以前没有使用JPA注解的时候，我们这里加入的都是hbm.xml文件，现在我们则加入的是类。<br />
7、创建EmployeeManager<br />
在com.ajax.employee.service下新建EmployeeManager类，这里面就是写业务方法，另外在这个类中添加一个main方法用于测试，将log4j的日志级别调整为DEBUG，这样我们就可以看到很详细的程序运行信息，源码中的注释很详细，这里就不贴出来了。<br />
本例没有提供MySQL和Oracle数据库的脚本，不过这些应该很简单，按照最基本的方式建一个数据库和两张表就行了，这里附上两种数据库的hibernate配置。<br />
MySQL：<br />
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<br />
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<br />
<property name="connection.url">jdbc:mysql://localhost:3306/ajax</property>
<br />
<property name="connection.username">root</property>
<br />
<property name="connection.password">自己的密码(无密码就空着)</property>
&#160;Oracle：<br />
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<br />
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<br />
<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:自己的SID</property>
<br />
<property name="connection.username">system</property>
<br />
<property name="connection.password">自己的密码(无密码就空着)</property>
&#160;本文主要是从实用的角度来说明如何在Hibernate中使用JPA注释来简化开发，以及为后面的多种Ajax技术框架应用系列作一个前期准备。从这里可以看出，我们不需要再编写繁琐的hbm.xml文件。另外，JPA的功能很强大，这里只展示了其中的冰山一角，如果想深入学习JPA的话，请单独查找资料或购买相关书籍。<br />
下面是本例中必须的JAR包<br />
点击下载：antlr-2.7.6 asm-1.5.3 cglib-2.1.3 commons-collections-2.1.1 commons-lang-2.1<br />
commons-logging-1.0.4 log4j-1.2.14 ehcache-1.2.3 ejb3-persistence-3.0&#160;<br />
hibernate3-3.2.5 hibernate-annotations-3.3.0 hibernate-commons-annotations-3.0.0&#160;<br />
mysql-connector.jar jtds.jar classes12.jar<br />
点击下载：ajax_project db_ajax</mapping></t></span>
<img src ="http://www.blogjava.net/over1988/aggbug/232072.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-10-02 11:01 <a href="http://www.blogjava.net/over1988/archive/2008/10/02/232072.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>精通 Grails: 构建您的第一个 Grails 应用程序(转自developmentwork 中国)</title><link>http://www.blogjava.net/over1988/archive/2008/10/01/232003.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Wed, 01 Oct 2008 08:27:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/10/01/232003.html</guid><wfw:comment>http://www.blogjava.net/over1988/comments/232003.html</wfw:comment><comments>http://www.blogjava.net/over1988/archive/2008/10/01/232003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/over1988/comments/commentRss/232003.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/over1988/services/trackbacks/232003.html</trackback:ping><description><![CDATA[<span style="font-family: verdana; font-size: 12px; line-height: 19px; "><blockquote>Java&#8482; 程序员不需要放弃自己喜爱的语言和已有的开发基础设施就可以采纳一种新型的 Web 开发框架。在这个新推出的每月一期的&#160;<em>精通 Grails</em>&#160;系列的第一期中，Java 专家 Scott Davis 介绍了 Grails，并演示了如何构建您的第一个 Grails 应用程序。</blockquote>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">请允许我借助另一种开源 Web 开发框架 —— Ruby on Rails —— 来介绍 Grails。Rails 一发布就迷住了开发人员。Rails 的脚手架功能使您可以用以前所需时间的一小部分完成一个新的项目。支持 Rails 的<em>约定优于配置（convention over configuration）</em>思想意味着，应用程序可以根据常识性的命名模式自动进行组装（auto-wire），而不必借助繁杂的、容易出错的 XML 配置文件。Ruby 的元编程功能使对象可以神奇地在运行时继承所需的方法和字段，而不会扰乱源代码。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">Rails 配得上它所受到的赞美和推崇（现在仍然如此），但是它使 Java 开发人员面临困难的选择。您会因为一个新平台的承诺而放弃自己熟悉的 Java 平台吗？如何处理已有的 Java 代码、已有的生产服务器和经验丰富的 Java 开发人员？</p>
<table align="right" border="0" cellspacing="0" cellpadding="0" width="40%">
    <tbody>
        <tr>
            <td width="10" style="line-height: 19px; "><img alt="" height="1" width="10" src="http://www.ibm.com/i/c.gif" /></td>
            <td style="line-height: 19px; ">
            <table border="1" cellspacing="0" cellpadding="5" width="100%">
                <tbody>
                    <tr>
                        <td bgcolor="#eeeeee" style="line-height: 19px; "><a name="N10081"><strong>关于本系列</strong></a><br />
                        <p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">Grails 是一种新型 Web 开发框架，它将常见的 Spring 和 Hibernate 等 Java 技术与当前流行的约定优于配置等实践相结合。Grails 是用 Groovy 编写的，它可以提供与遗留 Java 代码的无缝集成，同时还可以加入脚本编制语言的灵活性和动态性。学习完 Grails 之后，您将彻底改变看待 Web 开发的方式。</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">Grails 为您提供 Rails 风格的开发体验，同时以可靠的 Java 技术作为坚强后盾。但是 Grails 不仅仅是 Rails 通往 Java 平台的简单入口。Grails 吸取了 Rails 的经验，并将它们与现代 Java 开发的意识相结合。可以认为 Grails 是受 Rails&#160;<em>启发</em>，而不是由 Rails&#160;<em>转化而来</em>。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">作为&#160;<em>Grails 入门</em>&#160;系列的开篇，本文介绍 Grails 框架，展示它的安装方法，遍览如何构建第一个 Grails 应用程序：介绍本系列后续文章的内容。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="N1009A"><span class="atitle" style="font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; ">Groovy 的威力</span></a></p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">就像 Rails 与 Ruby 编程语言联系非常紧密一样，Grails 也离不开 Groovy（请参阅&#160;<a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#resources" style="color: #5c81a7; ">参考资料</a>）。Groovy 是一种动态语言，它在 JVM 上运行，并且与 Java 语言无缝集成。如果阅读了 developerWorks 上的大型&#160;<a href="http://www.ibm.com/developerworks/cn/views/java/articles.jsp?view_by=search&amp;search_by=%E5%AE%9E%E6%88%98+Groovy%3A" style="color: #996699; "><em>实战 Groovy</em>&#160;</a>系列，那么您已经了解了这种语言的威力。如果没有，也不必担心 — 在学习 Grails 的过程中，您将了解到很多关于 Groovy 的知识。Groovy 应该不难学，因为它是特意为 Java 开发人员而设计的。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">例如，Groovy 可以大大减少 Java 代码的数量。在 Groovy 中，不再需要为字段编写 getter 和 setter 方法，因为 Groovy 会自动提供它们。不再需要编写&#160;<code>for Iterator i = list.iterator()</code>&#160;来循环遍历一系列的项；<code>list.each</code>&#160;可以做相同的事情，而且看上去更简洁，表达更清晰。简言之，Groovy 就是 21 世纪的 Java 语言。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">如果 Java 开发人员只有重新编写整个应用程序才能利用 Groovy，那么 Groovy 对他们就没有多大的吸引力了。令人高兴的是，Groovy 可以无缝地与已有的代码库集成。Groovy 不会替代 Java 语言 — 它只是提供了增强。您可以很快地掌握 Groovy，因为说到底，Groovy 代码<em>就是</em>&#160;Java 代码。这两种语言是如此兼容，甚至可以将一个 .java 文件重命名为一个 .groovy 文件 — 例如，将 Person.java 改为 Person.groovy — 从而得到一个有效的（可执行的）Groovy 文件（虽然这个 Groovy 文件并没有用到 Groovy 提供的任何语法）。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">Groovy 与 Java 语言的深度兼容意味着 Grails 不需要重新创造内部使用的关键技术。相反，您可以以 Groovy 的方式查看熟悉的 Java 库。Groovy 封装了 JUnit&#160;<code>TestCase</code>&#160;并以&#160;<code>GroovyTestCase</code>&#160;形式提供。Grails 通过 GANT 对 Ant 构建进行了调整，GANT 是 Ant 的一个纯 Groovy 实现。Grails 将 Hibernate 包装在一个小小的 Groovy facade 中，并称之为 GORM — Grails Object/Relational Mapper。Grails 使您在利用已有的 Java 经验的同时，还可以利用最新的 Web 开发实践，以上只是其中的三个例子。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">不过，要想全面地鉴赏 Grails，还需要亲身体验一下。现在，让我们来安装 Grails，并创建第一个 Web 应用程序。</p>
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td style="line-height: 19px; "><img width="100%" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" /><br />
            <img alt="" width="8" height="6" border="0" src="http://www.ibm.com/i/c.gif" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td style="line-height: 19px; "><img width="100%" height="4" src="http://www.ibm.com/i/c.gif" alt="" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle" style="line-height: 19px; "><img width="16" src="http://www.ibm.com/i/v14/icons/u_bold.gif" height="16" border="0" alt="" /><br />
                        </td>
                        <td valign="top" align="right" style="line-height: 19px; "><a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#main" class="fbox" style="text-decoration: none; color: #5c81a7; font-family: verdana, nsimSun, arial, sans-serif; font-size: 12px; line-height: 13px; "><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="N100D7"><span class="atitle" style="font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; ">安装 Grails</span></a></p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">运行 Grails 应用程序所需的一切都在一个 ZIP 文件中。所有的依赖库 — 例如 Groovy、Spring 和 Hibernate — 都已经在那里，随时可以使用。要安装 Grails：</p>
<ol style="margin-top: 2px; margin-bottom: 2px; padding-top: 2px; padding-bottom: 2px; ">
    <li>从 Grails 站点（见&#160;<a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#resources" style="color: #5c81a7; ">参考资料</a>）下载并解压 grails.zip。</li>
    <li>创建一个&#160;<code>GRAILS_HOME</code>&#160;环境变量。</li>
    <li>将 $GRAILS_HOME/bin 添加到&#160;<code>PATH</code>&#160;中。</li>
</ol>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">您<em>的确</em>&#160;需要安装一个 JDK（Grails 是不错，但是还没有好到&#160;<em>那种程度</em>）。Grails 1.0 可在 Java 1.4、1.5 和 1.6 上运行。如果不知道已经安装了哪个版本，可以在命令行提示符下输入&#160;<code>java -version</code>。必要时，下载并安装一个与 Grails 兼容的 JDK（见&#160;<a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#resources" style="color: #5c81a7; ">参考资料</a>）。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">完成安装步骤后，输入&#160;<code>grails -version</code>&#160;以进行检查。如果看到以下友好信息，则说明一切都得到正确配置：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">Welcome to Grails 1.0 - http://grails.org/
            Licensed under Apache Standard License 2.0
            Grails home is set to: /opt/grails
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="N10119"><span class="smalltitle" style="font-family: arial, nsimsun, sans-serif; font-weight: bold; font-size: 15px; ">附带的 Web 服务器和数据库</span></a></p>
<table align="right" border="0" cellspacing="0" cellpadding="0" width="40%">
    <tbody>
        <tr>
            <td width="10" style="line-height: 19px; "><img alt="" height="1" width="10" src="http://www.ibm.com/i/c.gif" /></td>
            <td style="line-height: 19px; ">
            <table border="1" cellspacing="0" cellpadding="5" width="100%">
                <tbody>
                    <tr>
                        <td bgcolor="#eeeeee" style="line-height: 19px; "><a name="N10122"><strong>使用免费附带品</strong></a><br />
                        <p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">对于本文的应用程序，您将使用 Grails 免费提供的 Web 服务器和数据库。在将来的文章中，我将详细说明如何在您自己的服务器上运行 Grails。在此期间，请经常访问 grails.org 并浏览优秀的在线文档（见&#160;<a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#resources" style="color: #5c81a7; ">参考资料</a>）。</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">有趣的是，不需要单独安装 Web 服务器就可以运行 Grails 应用程序。 Grails 内置了 Jetty servlet 容器。只需输入&#160;<code>grails run-app</code>，就可以使应用程序在 Jetty 容器（见&#160;<a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#resources" style="color: #5c81a7; ">参考资料</a>）中运行，而不必执行常见的部署过程。在已有的生产服务器上运行 Grails 应用程序也没有问题。通过输入&#160;<code>grails war</code>&#160;创建一个标准文件，然后可以将其部署到 Tomcat、JBoss、Geronimo、WebSphere&#174;，或者任何其他遵从 Java EE 2.4 的 servlet 容器。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">您也不需要单独安装数据库。Grails 附带了 HSQLDB（见&#160;<a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#resources" style="color: #5c81a7; ">参考资料</a>），它是一个纯 Java 数据库。通过提供一个随时可用的数据库可以立即提高生产率。由于有了 Hibernate 和 GORM，使用其他数据库（例如 MySQL、PostgreSQL、Oracle Database 或 DB2）也很简单。如果有一个 JDBC driver JAR 再加上通常的连接设置，只需改变一下 DataSource.groovy，就可以立即使用您自己的数据库。</p>
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td style="line-height: 19px; "><img width="100%" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" /><br />
            <img alt="" width="8" height="6" border="0" src="http://www.ibm.com/i/c.gif" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td style="line-height: 19px; "><img width="100%" height="4" src="http://www.ibm.com/i/c.gif" alt="" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle" style="line-height: 19px; "><img width="16" src="http://www.ibm.com/i/v14/icons/u_bold.gif" height="16" border="0" alt="" /><br />
                        </td>
                        <td valign="top" align="right" style="line-height: 19px; "><a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#main" class="fbox" style="text-decoration: none; color: #5c81a7; font-family: verdana, nsimSun, arial, sans-serif; font-size: 12px; line-height: 13px; "><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="N10148"><span class="atitle" style="font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; ">编写第一个 Grails 应用程序</span></a></p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">我经常旅行 — 一年至少 40 趟。我发现，日程表可以很好地告诉我<em>何时</em>&#160;需要达到某个地方，但是不能显示那个地方在<em>哪里</em>。而在线地图刚好相反：它们可以解决地点问题，但不能解决时间问题。所以，在本文和本系列接下来的两篇文章中，您将构建一个定制的 Grails 应用程序，在计划旅程时，这个应用程序既可以用于解决时间问题，又可以用于解决地点问题。</p>
<table align="right" border="0" cellspacing="0" cellpadding="0" width="40%">
    <tbody>
        <tr>
            <td width="10" style="line-height: 19px; "><img alt="" height="1" width="10" src="http://www.ibm.com/i/c.gif" /></td>
            <td style="line-height: 19px; ">
            <table border="1" cellspacing="0" cellpadding="5" width="100%">
                <tbody>
                    <tr>
                        <td bgcolor="#eeeeee" style="line-height: 19px; "><a name="N1015C"><strong>后续介绍</strong></a><br />
                        <p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">本系列后面的文章将讨论如何将 Google Calendar 和 Google Maps 与 Grails 相结合。</p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">首先，在一个空白目录下，输入&#160;<code>grails create-app trip-planner</code>。稍后，可以看到一个名为 trip-planner 的目录。同 Maven、Rails 和 AppFuse 一样，Grails 会建立一个标准的目录结构。如果您觉得这个目录结构限制了您，并且只有精心设计自己的定制目录树才能使用一个框架，那么这样使用 Grails 不会有多大的乐趣。约定优于配置中的<em>约定</em>&#160;部分使您可以拥有任何 Grails 应用程序，并立即知道各个部分之间的联系。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">进入 trip-planner 目录，并输入&#160;<code>grails create-domain-class Trip</code>。如果一切顺利，将得到两个新的文件：grails-app/domain/Trip.groovy 和 grails-app/test/integration/TripTests.groovy。在后面的文章中，我将谈到测试。目前，我们主要关注域类。一开始，域类看上去如清单 1 所示：</p>
<br />
<a name="listing1"><strong>清单 1. Grails 生成的域类</strong></a><br />
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">            class Trip{
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">看上去没什么内容，对吗？接下来让我们来完善它。为&#160;<code>Trip</code>&#160;添加一些字段，如清单 2 所示：</p>
<br />
<a name="listing2"><strong>清单 2. 添加字段后的&#160;<code>Trip</code>&#160;类</strong></a><br />
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">            class Trip {
            String name
            String city
            Date startDate
            Date endDate
            String purpose
            String notes
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">如前所述，这里不需要创建 getter 和 setter 方法：Groovy 会动态地生成它们。<code>Trip</code>&#160;还有很多新的、有用的动态方法，这些方法的名称非常易用理解：</p>
<ul style="margin-top: 2px; margin-bottom: 2px; padding-top: 2px; padding-bottom: 2px; ">
    <li><code>Trip.save()</code>&#160;将数据<em>保存</em>&#160;到 HSQLDB 数据库中的&#160;<code>Trip</code>&#160;表中。</li>
    <li><code>Trip.delete()</code>&#160;从&#160;<code>Trip</code>&#160;表中<em>删除</em>&#160;数据。</li>
    <li><code>Trip.list()</code>&#160;返回一个&#160;<code>Trip</code>&#160;列表。</li>
    <li><code>Trip.get()</code>&#160;返回一个&#160;<code>Trip</code>。</li>
</ul>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">所有这些方法都已经存在，您在需要的时候就可以使用它们。注意，<code>Trip</code>&#160;并没有扩展某个父类或者实现某个接口。由于 Groovy 的元编程功能，那些方法只是出现在适当类中的适当位置（只有 grails-app/domain 目录中的类才拥有这些与持久性相关的方法）。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="N101D9"><span class="smalltitle" style="font-family: arial, nsimsun, sans-serif; font-weight: bold; font-size: 15px; ">构建控制器和视图</span></a></p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">创建域类只是成功的一半。每个模型都还需要一个良好的控制器和一些视图（我假设您熟悉 Model-View-Controller 模式；请参阅&#160;<a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#resources" style="color: #5c81a7; ">参考资料</a>）。输入&#160;<code>grails generate-all Trip</code>，以构建一个 grails-app/controllers/TripController.groovy 类，并在 grails-app/views/Trip 中生成一组匹配的 Groovy Server Page（GSP）。对于控制器中的每个&#160;<code>list</code>&#160;动作，都有一个相应的 list.gsp 文件。<code>create</code>&#160;动作则对应于一个 create.gsp 文件。从这里可以看出约定优于配置的优点：无需 XML 文件就可以匹配这些元素。每个域类根据名称与一个控制器配对。控制器中的每个动作也是根据名称与一个视图配对。如果您愿意，也可以绕开这种基于名称的配置，但是大多数时候只需遵循约定，应用程序自然就可以运行。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">看看清单 3 所示的 grails-app/controller/TripController.groovy：</p>
<br />
<a name="listing3"><strong>清单 3.&#160;<code>TripController</code>&#160;</strong></a><br />
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">            class TripController {
            ...
            def list = {
            if(!params.max) params.max = 10
            [ tripList: Trip.list( params ) ]
            }
            ...
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">Java 开发人员首先会注意到的是，这么少的代码可以实现多少功能。以&#160;<code>list</code>&#160;动作为例。起重要作用的是最后一行。Grails 将返回一个 hashmap，其中只有一个名为&#160;<code>tripList</code>&#160;的元素。（Groovy 方法的最后一行是一个隐式的 return 语句。如果您愿意，也可以手动地输入单词&#160;<code>return</code>）。<code>tripList</code>&#160;元素是&#160;<code>Trip</code>&#160;对象的一个&#160;<code>ArrayList</code>，<code>Trip</code>&#160;对象是通过&#160;<code>Trip.list()</code>&#160;方法从数据库中拉出的。通常该方法将返回表中的全部记录。它上面的一行代码表示 &#8220;如果 URL 中提供了一个 max 参数，那么使用它来限制返回的&#160;<code>Trip</code>&#160;的数量。否则，将&#160;<code>Trip</code>&#160;的数量限制为 10&#8221;。URL http://localhost:8080/trip-planner/trip/list 将调用这个动作。例如，http://localhost:8080/trip-planner/trip/list?max=3 显示 3 个 trip，而不是通常的 10 个。如果有更多的 trip 要显示，Grails 会自动创建上一页和下一页的分页链接。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">那么，如何使用这个 hashmap？看看 grails-app/views/list.gsp，如清单 4 所示：</p>
<br />
<a name="listing4"><strong>清单 4. list.gsp</strong></a><br />
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">            &lt;g:each in="${tripList}" status="i" var="trip">
            &lt;tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
            &lt;td>
            &lt;g:link action="show" id="${trip.id}">${trip.id?.encodeAsHTML()}&lt;/g:link>
            &lt;/td>
            &lt;/tr>
            &lt;/g:each>
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">list.gsp 主要是一些老式 HTML 加上少量 GroovyTagLib。以&#160;<code>g:</code>&#160;为前缀的就是 GroovyTag。在清单 4 中，<code>g:each</code>&#160;遍历&#160;<code>tripList ArrayList</code>&#160;中的每个&#160;<code>Trip</code>，并构建一个格式良好的 HTML 表格。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">对控制器的理解可以归结为三个&#160;<em>R</em>：<em>return</em>、<em>redirect</em>&#160;和&#160;<em>render</em>。有些动作利用隐式的 return 语句将数据返回到具有相同名称的 GSP 页面。有些动作进行重定向。例如，如果 URL 中未指定动作，则将调用&#160;<code>index</code>：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">def index = { redirect(action:list,params:params) }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">在此，<code>TripController</code>&#160;重定向到&#160;<code>list</code>&#160;动作，同时传递&#160;<code>params</code>&#160;hashmap 中的所有的参数（或&#160;<code>QueryString</code>）。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">最后，<code>save</code>&#160;动作（见清单 5）并没有相应的 save.gsp 页面。如果记录被成功地保存到数据库中，那么该动作会重定向到&#160;<code>show</code>&#160;动作页面。否则，它呈现 create.gsp 页面，以便显示错误，并让您重试。</p>
<br />
<a name="listing5"><strong>清单 5.&#160;<code>save</code>&#160;动作</strong></a><br />
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">            def save = {
            def trip = new Trip(params)
            if(!trip.hasErrors() &amp;&amp; trip.save()) {
            flash.message = "Trip ${trip.id} created"
            redirect(action:show,id:trip.id)
            }
            else {
            render(view:'create',model:[trip:trip])
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">在此，我们不详细讨论 Grails 是如何工作的，而是看看它的实际效果。</p>
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td style="line-height: 19px; "><img width="100%" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" /><br />
            <img alt="" width="8" height="6" border="0" src="http://www.ibm.com/i/c.gif" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td style="line-height: 19px; "><img width="100%" height="4" src="http://www.ibm.com/i/c.gif" alt="" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle" style="line-height: 19px; "><img width="16" src="http://www.ibm.com/i/v14/icons/u_bold.gif" height="16" border="0" alt="" /><br />
                        </td>
                        <td valign="top" align="right" style="line-height: 19px; "><a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#main" class="fbox" style="text-decoration: none; color: #5c81a7; font-family: verdana, nsimSun, arial, sans-serif; font-size: 12px; line-height: 13px; "><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="N10295"><span class="atitle" style="font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; ">应用程序的实际效果</span></a></p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">在命令行输入&#160;<code>grails run-app</code>。控制台在快速显示一批 Log4j 消息之后，将显示如下所示的消息：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">Server running. Browse to http://localhost:8080/trip-planner
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">如果端口 8080 上已经有一个服务器在运行，那么将显示一条核心转储信息：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">Server failed to start: java.net.BindException: Address already in use
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">可以通过两种方法轻松更改 Jetty 所使用的端口。可以通过输入&#160;<code>grails -Dserver.port=9090 run-app</code>&#160;临时进行更改。如果要使更改持久，可以从 $GRAILS_HOME/scripts/Init.groovy 中找出以&#160;<code>serverPort</code>开头的那一行，并更改值：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">serverPort = System.getProperty('server.port') ?
            System.getProperty('server.port').toInteger() : 9090
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">使 Grails 在您选择的端口上运行之后，在 Web 浏览器中输入 URL。应该可以看到一个欢迎屏幕，其中列出所有的控制器，如图 1 所示：</p>
<br />
<a name="fig1"><strong>图 1. Grails 应用程序的欢迎屏幕</strong></a><br />
<img alt="Grails 应用程序的欢迎屏幕" height="303" src="http://www.ibm.com/developerworks/cn/java/j-grails01158/welcome.jpg" width="568" />&#160;<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">单击&#160;<strong>TripController</strong>&#160;链接。您有一个完整的 CRUD（创建、读取、更新、删除）应用程序可以使用。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">使用图 2 所示的页面创建新的 trip：</p>
<br />
<a name="fig2"><strong>图 2. Create Trip 页面</strong></a><br />
<img alt="创建 Trip" height="439" src="http://www.ibm.com/developerworks/cn/java/j-grails01158/create.jpg" width="572" />&#160;<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">使用图 3 所示的页面编辑 trip：</p>
<br />
<a name="fig3"><strong>图 3. Trip List 页面</strong></a><br />
<img alt="编辑 Trip" height="311" src="http://www.ibm.com/developerworks/cn/java/j-grails01158/list.jpg" width="572" />&#160;<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">准备和运行这个应用程序要花多长时间？需要多少代码？下面就是答案：</p>
<ol style="margin-top: 2px; margin-bottom: 2px; padding-top: 2px; padding-bottom: 2px; ">
    <li>按下 Ctrl-C，关闭 Grails。</li>
    <li>输入&#160;<code>grails stats</code>。</li>
</ol>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">屏幕上将显示输出：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">  +----------------------+-------+-------+
            | Name                 | Files |  LOC  |
            +----------------------+-------+-------+
            | Controllers          |     1 |    66 |
            | Domain Classes       |     1 |     8 |
            | Integration Tests    |     1 |     4 |
            +----------------------+-------+-------+
            | Totals               |     3 |    78 |
            +----------------------+-------+-------+
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">只需不到 100 行代码，就可以实现应用程序的所有功能。看起来还不错。不过，最后我还要再展示一个窍门。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">生成控制器和视图是一项很好的学习体验，而磁盘上的物理文件则有助于说明各个部分是如何连接在一起的。不过在此需要做一件事：删除&#160;<code>TripController</code>&#160;类中的内容，并用下面的内容替代：</p>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
        <tr>
            <td class="code-outline" style="line-height: 19px; background-color: #eeeeee; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; ">
            <pre class="displaycode" style="margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, fixed, monospace; font-size: 11px; ">  class TripController{
            def scaffold = Trip
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">这行代码告诉 Grails 像对待前一个控制器一样，在运行时在内存中动态地生成所有那些&#160;<code>list</code>、<code>save</code>&#160;和&#160;<code>edit</code>&#160;动作。仅仅 3 行代码就可以产生和 66 行代码一样的行为。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">再次输入&#160;<code>grails run-app</code>。是的 — 所有数据都没有了。不必担心。按下 Ctrl-C 关闭 Grails。这一次，输入&#160;<code>grails prod run-app</code>。现在处于生产模式下，这意味着在服务器重新启动之前，数据已被保存。通过一连串的单击进入&#160;<code>TripController</code>，保存一些记录。应用程序的行为应该没有什么不同。您已经知道，在浏览器中看到的一切，是由 15 行代码驱动的，可知 Grails 的威力有多大。</p>
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td style="line-height: 19px; "><img width="100%" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" alt="" /><br />
            <img alt="" width="8" height="6" border="0" src="http://www.ibm.com/i/c.gif" /></td>
        </tr>
    </tbody>
</table>
<table class="no-print" cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td style="line-height: 19px; "><img width="100%" height="4" src="http://www.ibm.com/i/c.gif" alt="" /><br />
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle" style="line-height: 19px; "><img width="16" src="http://www.ibm.com/i/v14/icons/u_bold.gif" height="16" border="0" alt="" /><br />
                        </td>
                        <td valign="top" align="right" style="line-height: 19px; "><a href="http://www.ibm.com/developerworks/cn/java/j-grails01158/index.html#main" class="fbox" style="text-decoration: none; color: #5c81a7; font-family: verdana, nsimSun, arial, sans-serif; font-size: 12px; line-height: 13px; "><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="N10342"><span class="atitle" style="font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; ">结束语</span></a></p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">希望您对 Grails 的初次体验感到满意。小小一个包中，竟包含了令人惊讶的威力，而您只是看到冰山一角。这个框架的安装非常简单，只需解压一个文件。通过输入几行命令，就可以从头创建一个应用程序。希望这次简单的介绍能勾起您对 Grails 的更大兴趣。当然，本文也为您打好了一个基础，您可以扩展这个例子，尝试各种新的、有趣的方面。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">在下个月的文章中，您将专门花一些时间来关注 GORM。您将把日期保存到一个 MySQL 数据库中，进行某些数据验证，并设置一个一对多的关系。不必添加很多代码，就可以明显增强 trip-planner 应用程序的功能。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">到那时，好好享受使用 Groovy 和 Grails 的乐趣吧。您对 Web 开发的看法将彻底改变。</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><br />
</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><br />
</p>
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">
<p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><a name="author"><span class="atitle" style="font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; ">关于作者</span></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td colspan="3" style="line-height: 19px; "><img alt="" width="100%" height="5" src="http://www.ibm.com/i/c.gif" /></td>
        </tr>
        <tr align="left" valign="top">
            <td style="line-height: 19px; ">
            <p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; "><img align="left" alt="Scott Davis" src="http://www.ibm.com/developerworks/i/p-scdavis.jpg" valign="top" /></p>
            </td>
            <td style="line-height: 19px; "><img alt="" width="4" height="5" src="http://www.ibm.com/i/c.gif" /></td>
            <td width="100%" style="line-height: 19px; ">
            <p style="padding-bottom: 8px; padding-top: 5px; margin-top: 0px; margin-bottom: 0px; ">Scott Davis 是国际知名作家、演讲家、软件开发人员。他出版的书籍有&#160;<em>Groovy Recipes: Greasing the Wheels of Java</em>、<em>GIS for Web Developers: Adding Where to Your Application</em>、<em>The Google Maps API</em>&#160;和&#160;<em>JBoss At Work</em>。</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<br />
</span>
<img src ="http://www.blogjava.net/over1988/aggbug/232003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-10-01 16:27 <a href="http://www.blogjava.net/over1988/archive/2008/10/01/232003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ant 基础使用</title><link>http://www.blogjava.net/over1988/archive/2008/09/11/228280.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Thu, 11 Sep 2008 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/09/11/228280.html</guid><wfw:comment>http://www.blogjava.net/over1988/comments/228280.html</wfw:comment><comments>http://www.blogjava.net/over1988/archive/2008/09/11/228280.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/over1988/comments/commentRss/228280.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/over1988/services/trackbacks/228280.html</trackback:ping><description><![CDATA[还不是很全，只有基本的内容：<br />
1 Ant是什么？ <br />
Apache Ant 是一个基于 Java的生成工具。<br />
生成工具在软件开发中用来将源代码和其他输入文件转换为可执行文件的形式（也有可能转换为可安装的产品映像形式）。随着应用程序的生成过程变得更加复杂，确保在每次生成期间都使用精确相同的生成步骤，同时实现尽可能多的自动化，以便及时产生一致的生成版本<br />
2 下载、安装Ant <br />
安装Ant<br />
下载.zip文件，解压缩到c:\ant1.3(后面引用为%ANT_HOME%)<br />
<br />
2.1 在你运行Ant之前需要做一些配置工作。<br />
? 将bin目录加入PATH环境变量。 <br />
? 设定ANT_HOME环境变量，指向你安装Ant的目录。在一些OS上，Ant的脚本可以猜测ANT_HOME（Unix和Windos NT/2000）－但最好不要依赖这一特性。 <br />
? 可选地，设定JAVA_HOME环境变量（参考下面的高级小节），该变量应该指向你安装JDK的目录。<br />
注意：不要将Ant的ant.jar文件放到JDK/JRE的lib/ext目录下。Ant是个应用程序，而lib/ext目录是为JDK扩展使用的（如JCE，JSSE扩展）。而且通过扩展装入的类会有安全方面的限制。<br />
2.2 运行Ant <br />
<br />
运行Ant非常简单，当你正确地安装Ant后，只要输入ant就可以了。<br />
<br />
? 没有指定任何参数时，Ant会在当前目录下查询build.xml文件。如果找到了就用该文件作为buildfile。如果你用 -find 选项。Ant就会在上级目录中寻找buildfile，直至到达文件系统的根。要想让Ant使用其他的buildfile，可以用参数 -buildfile file，这里file指定了你想使用的buildfile。<br />
<br />
? 可以指定执行一个或多个target。当省略target时，Ant使用标签&lt;project&gt;的default属性所指定的target。<br />
<br />
<br />
命令行选项总结：<br />
ant [options] [target [target2 [target3] ...]]<br />
Options:<br />
-help print this message<br />
-projecthelp print project help information<br />
-version print the version information and exit<br />
-quiet be extra quiet<br />
-verbose be extra verbose<br />
-debug print debugging information<br />
-emacs produce logging information without adornments<br />
-logfile file use given file for log output<br />
-logger classname the class that is to perform logging<br />
-listener classname add an instance of class as a project listener<br />
-buildfile file use specified buildfile<br />
-find file search for buildfile towards the root of the filesystem and use the first one found<br />
-Dproperty=value set property to value <br />
例子<br />
ant<br />
使用当前目录下的build.xml运行Ant，执行缺省的target。<br />
ant -buildfile test.xml<br />
使用当前目录下的test.xml运行Ant，执行缺省的target。<br />
ant -buildfile test.xml dist<br />
使用当前目录下的test.xml运行Ant，执行一个叫做dist的target。<br />
ant -buildfile test.xml -Dbuild=build/classes dist<br />
使用当前目录下的test.xml运行Ant，执行一个叫做dist的target，并设定build属性的值为build/classes。<br />
<br />
3 编写build.xml <br />
<br />
Ant的buildfile是用XML写的。每个buildfile含有一个project。<br />
<br />
buildfile中每个task元素可以有一个id属性，可以用这个id值引用指定的任务。这个值必须是唯一的。（详情请参考下面的Task小节）<br />
<br />
3.1 Projects<br />
<br />
project有下面的属性：<br />
Attribute Description Required<br />
name 项目名称. No<br />
default 当没有指定target时使用的缺省target Yes<br />
basedir 用于计算所有其他路径的基路径。该属性可以被basedir property覆盖。当覆盖时，该属性被忽略。如果属性和basedir property都没有设定，就使用buildfile文件的父目录。 No<br />
项目的描述以一个顶级的&lt;description&gt;元素的形式出现（参看description小节）。<br />
<br />
一个项目可以定义一个或多个target。一个target是一系列你想要执行的。执行Ant时，你可以选择执行那个target。当没有给定target时，使用project的default属性所确定的target。<br />
<br />
3.2 Targets<br />
<br />
一个target可以依赖于其他的target。例如，你可能会有一个target用于编译程序，一个target用于生成可执行文件。你在生成可执行文件之前必须先编译通过，所以生成可执行文件的target依赖于编译target。Ant会处理这种依赖关系。<br />
<br />
然而，应当注意到，Ant的depends属性只指定了target应该被执行的顺序－如果被依赖的target无法运行，这种depends对于指定了依赖关系的target就没有影响。<br />
<br />
Ant会依照depends属性中target出现的顺序（从左到右）依次执行每个target。然而，要记住的是只要某个target依赖于一个target，后者就会被先执行。<br />
&lt;target name="A"/&gt;<br />
&lt;target name="B" depends="A"/&gt;<br />
&lt;target name="C" depends="B"/&gt;<br />
&lt;target name="D" depends="C,B,A"/&gt;<br />
假定我们要执行target D。从它的依赖属性来看，你可能认为先执行C，然后B，最后A被执行。错了，C依赖于B，B依赖于A，所以先执行A，然后B，然后C，最后D被执行。<br />
<br />
一个target只能被执行一次，即时有多个target依赖于它（看上面的例子）。<br />
<br />
如果（或如果不）某些属性被设定，才执行某个target。这样，允许根据系统的状态（java version, OS, 命令行属性定义等等）来更好地控制build的过程。要想让一个target这样做，你就应该在target元素中，加入if（或unless）属性，带上target因该有所判断的属性。例如：<br />
&lt;target name="build-module-A" if="module-A-present"/&gt;<br />
&lt;target name="build-own-fake-module-A" unless="module-A-present"/&gt;<br />
如果没有if或unless属性，target总会被执行。<br />
<br />
可选的description属性可用来提供关于target的一行描述，这些描述可由-projecthelp命令行选项输出。<br />
<br />
将你的tstamp task在一个所谓的初始化target是很好的做法，其他的target依赖这个初始化target。要确保初始化target是出现在其他target依赖表中的第一个target。在本手册中大多数的初始化target的名字是"init"。<br />
<br />
target有下面的属性：<br />
Attribute Description Required<br />
name target的名字 Yes<br />
depends 用逗号分隔的target的名字列表，也就是依赖表。 No<br />
if 执行target所需要设定的属性名。 No<br />
unless 执行target需要清除设定的属性名。 No<br />
description 关于target功能的简短描述。 No<br />
<br />
3.3 Tasks<br />
<br />
一个task是一段可执行的代码。<br />
<br />
一个task可以有多个属性（如果你愿意的话，可以将其称之为变量）。属性只可能包含对property的引用。这些引用会在task执行前被解析。<br />
<br />
下面是Task的一般构造形式：<br />
&lt;name attribute1="value1" attribute2="value2" ... /&gt;<br />
这里name是task的名字，attributeN是属性名，valueN是属性值。<br />
<br />
有一套内置的（built-in）task，以及一些可选task，但你也可以编写自己的task。<br />
<br />
所有的task都有一个task名字属性。Ant用属性值来产生日志信息。<br />
<br />
可以给task赋一个id属性：<br />
&lt;taskname id="taskID" ... /&gt;<br />
这里taskname是task的名字，而taskID是这个task的唯一标识符。通过这个标识符，你可以在脚本中引用相应的task。例如，在脚本中你可以这样：<br />
&lt;script ... &gt;<br />
task1.setFoo("bar");<br />
&lt;/script&gt;<br />
设定某个task实例的foo属性。在另一个task中（用java编写），你可以利用下面的语句存取相应的实例。<br />
project.getReference("task1").<br />
注意1：如果task1还没有运行，就不会被生效（例如：不设定属性），如果你在随后配置它，你所作的一切都会被覆盖。<br />
<br />
注意2：未来的Ant版本可能不会兼容这里所提的属性，因为很有可能根本没有task实例，只有proxies。<br />
<br />
3.4 Properties<br />
<br />
一个project可以有很多的properties。可以在buildfile中用property task来设定，或在Ant之外设定。一个property有一个名字和一个值。property可用于task的属性值。这是通过将属性名放在"${"和"}"之间并放在属性值的位置来实现的。例如如果有一个property builddir的值是"build"，这个property就可用于属性值：${builddir}/classes。这个值就可被解析为build/classes。<br />
<br />
内置属性<br />
<br />
如果你使用了&lt;property&gt; task 定义了所有的系统属性，Ant允许你使用这些属性。例如，${os.name}对应操作系统的名字。<br />
<br />
要想得到系统属性的列表可参考the Javadoc of System.getProperties。<br />
<br />
除了Java的系统属性，Ant还定义了一些自己的内置属性： <br />
basedir project基目录的绝对路径 (与&lt;project&gt;的basedir属性一样)。<br />
ant.file buildfile的绝对路径。<br />
ant.version Ant的版本。<br />
ant.project.name 当前执行的project的名字；由&lt;project&gt;的name属性设定.<br />
ant.java.version Ant检测到的JVM的版本； 目前的值有"1.1", "1.2", "1.3" and "1.4".<br />
<br />
例子<br />
&lt;project name="MyProject" default="dist" basedir="."&gt; <br />
<br />
&lt;!-- set global properties for this build --&gt;<br />
&lt;property name="src" value="."/&gt;<br />
&lt;property name="build" value="build"/&gt;<br />
&lt;property name="dist" value="dist"/&gt; <br />
<br />
&lt;target name="init"&gt;<br />
&lt;!-- Create the time stamp --&gt;<br />
&lt;tstamp/&gt;<br />
&lt;!-- Create the build directory structure used by compile --&gt;<br />
&lt;mkdir dir="${build}"/&gt;<br />
&lt;/target&gt;<br />
<br />
&lt;target name="compile" depends="init"&gt;<br />
&lt;!-- Compile the java code from ${src} into ${build} --&gt;<br />
&lt;javac srcdir="${src}" destdir="${build}"/&gt;<br />
&lt;/target&gt;<br />
<br />
&lt;target name="dist" depends="compile"&gt;<br />
&lt;!-- Create the distribution directory --&gt;<br />
&lt;mkdir dir="${dist}/lib"/&gt;<br />
&lt;!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --&gt;<br />
&lt;jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/&gt;<br />
&lt;/target&gt;<br />
<br />
&lt;target name="clean"&gt;<br />
&lt;!-- Delete the ${build} and ${dist} directory trees --&gt;<br />
&lt;delete dir="${build}"/&gt;<br />
&lt;delete dir="${dist}"/&gt;<br />
&lt;/target&gt;<br />
<br />
&lt;/project&gt;<br />
3.5 Path-like Structures<br />
你可以用":"和";"作为分隔符，指定类似PATH和CLASSPATH的引用。Ant会把分隔符转换为当前系统所用的分隔符。<br />
<br />
当需要指定类似路径的值时，可以使用嵌套元素。一般的形式是<br />
&lt;classpath&gt;<br />
&lt;pathelement path="${classpath}"/&gt;<br />
&lt;pathelement location="lib/helper.jar"/&gt;<br />
&lt;/classpath&gt;<br />
location属性指定了相对于project基目录的一个文件和目录，而path属性接受逗号或分号分隔的一个位置列表。path属性一般用作预定义的路径－－其他情况下，应该用多个location属性。<br />
<br />
为简洁起见，classpath标签支持自己的path和location属性。所以：<br />
&lt;classpath&gt;<br />
&lt;pathelement path="${classpath}"/&gt;<br />
&lt;/classpath&gt;<br />
可以被简写作：<br />
&lt;classpath path="${classpath}"/&gt;<br />
也可通过&lt;fileset&gt;元素指定路径。构成一个fileset的多个文件加入path-like structure的顺序是未定的。<br />
&lt;classpath&gt;<br />
&lt;pathelement path="${classpath}"/&gt;<br />
&lt;fileset dir="lib"&gt;<br />
&lt;include name="**/*.jar"/&gt;<br />
&lt;/fileset&gt;<br />
&lt;pathelement location="classes"/&gt;<br />
&lt;/classpath&gt;<br />
上面的例子构造了一个路径值包括：${classpath}的路径，跟着lib目录下的所有jar文件，接着是classes目录。<br />
<br />
如果你想在多个task中使用相同的path-like structure，你可以用&lt;path&gt;元素定义他们（与target同级），然后通过id属性引用－－参考Referencs例子。<br />
<br />
path-like structure可能包括对另一个path-like structurede的引用（通过嵌套&lt;path&gt;元素）：<br />
&lt;path id="base.path"&gt;<br />
&lt;pathelement path="${classpath}"/&gt;<br />
&lt;fileset dir="lib"&gt;<br />
&lt;include name="**/*.jar"/&gt;<br />
&lt;/fileset&gt;<br />
&lt;pathelement location="classes"/&gt;<br />
&lt;/path&gt;<br />
&lt;path id="tests.path"&gt;<br />
&lt;path refid="base.path"/&gt;<br />
&lt;pathelement location="testclasses"/&gt;<br />
&lt;/path&gt;<br />
前面所提的关于&lt;classpath&gt;的简洁写法对于&lt;path&gt;也是有效的，如：<br />
&lt;path id="tests.path"&gt;<br />
&lt;path refid="base.path"/&gt;<br />
&lt;pathelement location="testclasses"/&gt;<br />
&lt;/path&gt;<br />
可写成：<br />
&lt;path id="base.path" path="${classpath}"/&gt;<br />
命令行变量<br />
<br />
有些task可接受参数，并将其传递给另一个进程。为了能在变量中包含空格字符，可使用嵌套的arg元素。<br />
Attribute Description Required<br />
value 一个命令行变量；可包含空格字符。 只能用一个<br />
line 空格分隔的命令行变量列表。 <br />
file 作为命令行变量的文件名；会被文件的绝对名替代。 <br />
path 一个作为单个命令行变量的path-like的字符串；或作为分隔符，Ant会将其转变为特定平台的分隔符。 <br />
<br />
例子<br />
&lt;arg value="-l -a"/&gt;<br />
是一个含有空格的单个的命令行变量。<br />
&lt;arg line="-l -a"/&gt;<br />
是两个空格分隔的命令行变量。<br />
&lt;arg path="/dir;/dir2:\dir3"/&gt;<br />
是一个命令行变量，其值在DOS系统上为\dir;\dir2;\dir3；在Unix系统上为/dir:/dir2:/dir3 。<br />
<br />
References<br />
<br />
buildfile元素的id属性可用来引用这些元素。如果你需要一遍遍的复制相同的XML代码块，这一属性就很有用－－如多次使用&lt;classpath&gt;结构。<br />
<br />
下面的例子：<br />
&lt;project ... &gt;<br />
&lt;target ... &gt; <br />
&lt;rmic ...&gt; <br />
&lt;classpath&gt; <br />
&lt;pathelement location="lib/"/&gt; <br />
&lt;pathelement path="${java.class.path}/"/&gt; <br />
&lt;pathelement path="${additional.path}"/&gt; <br />
&lt;/classpath&gt; <br />
&lt;/rmic&gt; <br />
&lt;/target&gt;<br />
&lt;target ... &gt;<br />
&lt;javac ...&gt;<br />
&lt;classpath&gt;<br />
&lt;pathelement location="lib/"/&gt;<br />
&lt;pathelement path="${java.class.path}/"/&gt;<br />
&lt;pathelement path="${additional.path}"/&gt;<br />
&lt;/classpath&gt;<br />
&lt;/javac&gt;<br />
&lt;/target&gt;<br />
&lt;/project&gt;<br />
可以写成如下形式：<br />
&lt;project ... &gt; <br />
&lt;path id="project.class.path"&gt; <br />
&lt;pathelement location="lib/"/&gt;<br />
&lt;pathelement path="${java.class.path}/"/&gt; <br />
&lt;pathelement path="${additional.path}"/&gt; <br />
&lt;/path&gt;<br />
&lt;target ... &gt;<br />
&lt;rmic ...&gt;<br />
&lt;classpath refid="project.class.path"/&gt;<br />
&lt;/rmic&gt;<br />
&lt;/target&gt;<br />
&lt;target ... &gt; <br />
&lt;javac ...&gt;<br />
&lt;classpath refid="project.class.path"/&gt;<br />
&lt;/javac&gt;<br />
&lt;/target&gt;<br />
&lt;/project&gt;<br />
所有使用PatternSets, FileSets 或 path-like structures嵌套元素的task也接受这种类型的引用。<br />
<br />
<br />
<br />
4.1 File（Directory）类<br />
4.1.1 Mkdir<br />
? 创建一个目录，如果他的父目录不存在，也会被同时创建。<br />
? 例子：<br />
&lt;mkdir dir="build/classes"/&gt;<br />
? 说明： 如果build不存在，也会被同时创建<br />
4.1.2 Copy<br />
? 拷贝一个（组）文件、目录<br />
? 例子：<br />
1. 拷贝单个的文件： <br />
&lt;copy file="myfile.txt" tofile="mycopy.txt"/&gt;<br />
2. 拷贝单个的文件到指定目录下<br />
&lt;copy file="myfile.txt" todir="../some/other/dir"/&gt;<br />
3. 拷贝一个目录到另外一个目录下<br />
&lt;copy todir="../new/dir"&gt;<br />
&lt;fileset dir="src_dir"/&gt;<br />
&lt;/copy&gt;<br />
4. 拷贝一批文件到指定目录下<br />
&lt;copy todir="../dest/dir"&gt;<br />
&lt;fileset dir="src_dir"&gt;<br />
&lt;exclude name="**/*.java"/&gt;<br />
&lt;/fileset&gt;<br />
&lt;/copy&gt;<br />
<br />
&lt;copy todir="../dest/dir"&gt;<br />
&lt;fileset dir="src_dir" excludes="**/*.java"/&gt;<br />
&lt;/copy&gt;<br />
5. 拷贝一批文件到指定目录下，将文件名后增加。Bak后缀<br />
&lt;copy todir="../backup/dir"&gt;<br />
&lt;fileset dir="src_dir"/&gt;<br />
&lt;mapper type="glob" from="*" to="*.bak"/&gt;<br />
&lt;/copy&gt;<br />
6. 拷贝一组文件到指定目录下，替换其中的@标签@内容<br />
&lt;copy todir="../backup/dir"&gt;<br />
&lt;fileset dir="src_dir"/&gt;<br />
&lt;filterset&gt;<br />
&lt;filter token="TITLE" value="Foo Bar"/&gt;<br />
&lt;/filterset&gt;<br />
&lt;/copy&gt;<br />
4.1.3 Delete<br />
? 删除一个（组）文件或者目录<br />
? 例子<br />
1. 删除一个文件<br />
&lt;delete file="/lib/ant.jar"/&gt;<br />
2. 删除指定目录及其子目录<br />
&lt;delete dir="lib"/&gt;<br />
3. 删除指定的一组文件<br />
&lt;delete&gt;<br />
&lt;fileset dir="." includes="**/*.bak"/&gt;<br />
&lt;/delete&gt;<br />
4. 删除指定目录及其子目录，包括他自己<br />
&lt;delete includeEmptyDirs="true"&gt;<br />
&lt;fileset dir="build"/&gt;<br />
&lt;/delete&gt;<br />
4.1.4 Move<br />
? 移动或重命名一个（组）文件、目录<br />
? 例子：<br />
1. 移动或重命名一个文件<br />
&lt;move file="file.orig" tofile="file.moved"/&gt;<br />
2. 移动或重命名一个文件到另一个文件夹下面<br />
&lt;move file="file.orig" todir="dir/to/move/to"/&gt;<br />
3. 将一个目录移到另外一个目录下<br />
&lt;move todir="new/dir/to/move/to"&gt;<br />
&lt;fileset dir="src/dir"/&gt;<br />
&lt;/move&gt;<br />
4. 将一组文件移动到另外的目录下<br />
&lt;move todir="some/new/dir"&gt;<br />
&lt;fileset dir="my/src/dir"&gt;<br />
&lt;include name="**/*.jar"/&gt;<br />
&lt;exclude name="**/ant.jar"/&gt;<br />
&lt;/fileset&gt;<br />
&lt;/move&gt;<br />
5. 移动文件过程中增加。Bak后缀<br />
&lt;move todir="my/src/dir"&gt;<br />
&lt;fileset dir="my/src/dir"&gt;<br />
&lt;exclude name="**/*.bak"/&gt;<br />
&lt;/fileset&gt;<br />
&lt;mapper type="glob" from="*" to="*.bak"/&gt;<br />
&lt;/move&gt;<br />
<br />
<br />
<br />
<br />
4.2 Java相关<br />
4.2.1 Javac<br />
? 编译java原代码<br />
? 例子<br />
1. &lt;javac srcdir="${src}"<br />
destdir="${build}"<br />
classpath="xyz.jar"<br />
debug="on"<br />
/&gt;<br />
编译${src}目录及其子目录下的所有。Java文件，。Class文件将放在$｛build｝指定的目录下，classpath表示需要用到的类文件或者目录，debug设置为on表示输出debug信息<br />
2. &lt;javac srcdir="${src}:${src2}"<br />
destdir="${build}"<br />
includes="mypackage/p1/**,mypackage/p2/**"<br />
excludes="mypackage/p1/testpackage/**"<br />
classpath="xyz.jar"<br />
debug="on"<br />
/&gt;<br />
编译${src}和${src2}目录及其子目录下的所有。Java文件，但是package/p1/**,mypackage/p2/**将被编译，而mypackage/p1/testpackage/**将不会被编译。Class文件将放在$｛build｝指定的目录下，classpath表示需要用到的类文件或者目录，debug设置为on表示输出debug信息<br />
3. &lt;property name="classpath" value=".;./xml-apis.jar;../lib/xbean.jar;./easypo.jar"/&gt;<br />
<br />
&lt;javac srcdir="${src}"<br />
destdir="${src}"<br />
classpath="${classpath}"<br />
debug="on"<br />
/&gt;<br />
路径是在property中定义的<br />
4.2.2 java<br />
? 执行指定的java类<br />
<br />
<br />
? 例子：<br />
1. &lt;java classname="test.Main"&gt;<br />
&lt;classpath&gt;<br />
&lt;pathelement location="dist/test.jar"/&gt;<br />
&lt;pathelement path="${java.class.path}"/&gt;<br />
&lt;/classpath&gt;<br />
&lt;/java&gt;<br />
classname中指定要执行的类，classpath设定要使用的环境变量<br />
2. &lt;path id="project.class.path"&gt;<br />
&lt;pathelement location="lib/"/&gt;<br />
&lt;pathelement path="${java.class.path}/"/&gt;<br />
&lt;pathelement path="${additional.path}"/&gt;<br />
&lt;/path&gt;<br />
<br />
&lt;target ... &gt;<br />
&lt;rmic ...&gt;<br />
&lt;classpath refid="project.class.path"/&gt;<br />
&lt;/rmic&gt;<br />
&lt;/target&gt;<br />
<br />
<br />
<br />
<br />
<br />
4.3 打包相关<br />
4.3.1 jar<br />
? 将一组文件打包<br />
? 例子：<br />
1. &lt;jar destfile="${dist}/lib/app.jar" basedir="${build}/classes"/&gt;<br />
将${build}/classes下面的所有文件打包到${dist}/lib/app.jar中<br />
2. &lt;jar destfile="${dist}/lib/app.jar"<br />
basedir="${build}/classes"<br />
includes="mypackage/test/**"<br />
excludes="**/Test.class"<br />
/&gt;<br />
将${build}/classes下面的所有文件打包到${dist}/lib/app.jar中，但是包括mypackage/test／所有文件不包括所有的Test.class<br />
3. &lt;jar destfile="${dist}/lib/app.jar"<br />
basedir="${build}/classes"<br />
includes="mypackage/test/**"<br />
excludes="**/Test.class"<br />
manifest=&#8221;my.mf&#8221;<br />
/&gt;<br />
manifest属性指定自己的META-INF/MANIFEST.MF文件，而不是由系统生成<br />
4.3.2 war<br />
? 对Jar的扩展，用于打包Web应用<br />
? 例子：<br />
? 假设我们的文件目录如下：<br />
thirdparty/libs/jdbc1.jar<br />
thirdparty/libs/jdbc2.jar<br />
build/main/com/myco/myapp/Servlet.class<br />
src/metadata/myapp.xml<br />
src/html/myapp/index.html<br />
src/jsp/myapp/front.jsp<br />
src/graphics/images/gifs/small/logo.gif<br />
src/graphics/images/gifs/large/logo.gif<br />
? 下面是我们的任务的内容： <br />
&lt;war destfile="myapp.war" webxml="src/metadata/myapp.xml"&gt;<br />
&lt;fileset dir="src/html/myapp"/&gt;<br />
&lt;fileset dir="src/jsp/myapp"/&gt;<br />
&lt;lib dir="thirdparty/libs"&gt;<br />
&lt;exclude name="jdbc1.jar"/&gt;<br />
&lt;/lib&gt;<br />
&lt;classes dir="build/main"/&gt;<br />
&lt;zipfileset dir="src/graphics/images/gifs" <br />
prefix="images"/&gt;<br />
&lt;/war&gt;<br />
? 完成后的结果：<br />
WEB-INF/web.xml<br />
WEB-INF/lib/jdbc2.jar<br />
WEB-INF/classes/com/myco/myapp/Servlet.class<br />
META-INF/MANIFEST.MF<br />
index.html<br />
front.jsp<br />
images/small/logo.gif<br />
images/large/logo.gif<br />
4.3.3 ear<br />
? 用于打包企业应用<br />
? 例子<br />
&lt;ear destfile="${build.dir}/myapp.ear" appxml="${src.dir}/metadata/application.xml"&gt;<br />
&lt;fileset dir="${build.dir}" includes="*.jar,*.war"/&gt;<br />
&lt;/ear&gt;<br />
<br />
<br />
<br />
4.4 时间戳<br />
在生成环境中使用当前时间和日期，以某种方式标记某个生成任务的输出，以便记录它是何时生成的，这经常是可取的。这可能涉及编辑一个文件，以便插入一个字符串来指定日期和时间，或将这个信息合并到 JAR 或 zip 文件的文件名中。<br />
这种需要是通过简单但是非常有用的 tstamp 任务来解决的。这个任务通常在某次生成过程开始时调用，比如在一个 init 目标中。这个任务不需要属性，许多情况下只需 &lt;tstamp/&gt; 就足够了。<br />
tstamp 不产生任何输出；相反，它根据当前系统时间和日期设置 Ant 属性。下面是 tstamp 设置的一些属性、对每个属性的说明，以及这些属性可被设置到的值的例子：<br />
属性 说明 例子 <br />
DSTAMP 设置为当前日期，默认格式为yyyymmdd 20031217<br />
TSTAMP 设置为当前时间，默认格式为 hhmm 1603<br />
TODAY 设置为当前日期，带完整的月份 2003 年 12 月 17 日<br />
例如，在前一小节中，我们按如下方式创建了一个 JAR 文件：<br />
<br />
&lt;jar destfile="package.jar" basedir="classes"/&gt;<br />
<br />
在调用 tstamp 任务之后，我们能够根据日期命名该 JAR 文件，如下所示：<br />
<br />
&lt;jar destfile="package-${DSTAMP}.jar" basedir="classes"/&gt;<br />
<br />
因此，如果这个任务在 2003 年 12 月 17 日调用，该 JAR 文件将被命名为 package-20031217.jar。<br />
还可以配置 tstamp 任务来设置不同的属性，应用一个当前时间之前或之后的时间偏移，或以不同的方式格式化该字符串。所有这些都是使用一个嵌套的 format 元素来完成的，如下所示：<br />
<br />
&lt;tstamp&gt;<br />
&lt;format property="OFFSET_TIME"<br />
pattern="HH:mm:ss"<br />
offset="10" unit="minute"/&gt;<br />
&lt;/tstamp&gt;<br />
<br />
上面的清单将 OFFSET_TIME 属性设置为距离当前时间 10 分钟之后的小时数、分钟数和秒数。<br />
用于定义格式字符串的字符与 java.text.SimpleDateFormat 类所定义的那些格式字符相同<br />
<br />
<br />
<br />
4.5 执行SQL语句<br />
? 通过jdbc执行SQL语句<br />
? 例子：<br />
1. &lt;sql<br />
driver="org.gjt.mm.mysql.Driver"<br />
url="jdbc:mysql://localhost:3306/mydb"<br />
userid="root"<br />
password="root"<br />
src="data.sql"<br />
/&gt;<br />
2. &lt;sql<br />
driver="org.database.jdbcDriver"<br />
url="jdbc:database-url"<br />
userid="sa"<br />
password="pass"<br />
src="data.sql"<br />
rdbms="oracle"<br />
version="8.1."<br />
&gt;<br />
&lt;/sql&gt;<br />
只有在oracle、版本是8.1的时候才执行<br />
<br />
<br />
<br />
4.6 发送邮件<br />
? 使用SMTP服务器发送邮件<br />
? 例子：<br />
&lt;mail mailhost="smtp.myisp.com" mailport="1025" subject="Test build"&gt;<br />
&lt;from address="me@myisp.com"/&gt;<br />
&lt;to address="all@xyz.com"/&gt;<br />
&lt;message&gt;The ${buildname} nightly build has completed&lt;/message&gt;<br />
&lt;fileset dir="dist"&gt;<br />
&lt;includes name="**/*.zip"/&gt;<br />
&lt;/fileset&gt;<br />
&lt;/mail&gt;<br />
? mailhost： SMTP服务器地址<br />
? mailport： 服务器端口<br />
? subject： 主题<br />
? from： 发送人地址<br />
? to： 接受人地址<br />
? message： 发送的消息<br />
? fileset： 设置附件<br />
<br />
<img src ="http://www.blogjava.net/over1988/aggbug/228280.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-09-11 09:38 <a href="http://www.blogjava.net/over1988/archive/2008/09/11/228280.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts2 Spring Hibernate 的简单整合 </title><link>http://www.blogjava.net/over1988/archive/2008/09/03/226792.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Wed, 03 Sep 2008 14:13:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/09/03/226792.html</guid><wfw:comment>http://www.blogjava.net/over1988/comments/226792.html</wfw:comment><comments>http://www.blogjava.net/over1988/archive/2008/09/03/226792.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/over1988/comments/commentRss/226792.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/over1988/services/trackbacks/226792.html</trackback:ping><description><![CDATA[<p>&#160;&#160; 首先，加载Spring框架，如图：</p>
<p>&#160;<img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200806/20080610092525597.jpg" /></p>
<p>&#160;&#160;&#160; 为了便于以后添加新的应用，这里把spring所有的Jar包都添加了，下一步，要将Spring的配置文件创建在</p>
<p>WEB-INF目录下，或许不理它，到项目中去移动也可以。单击Finish， 对Spring的添加到此结束。</p>
<p>&#160;</p>
<p>&#160;&#160;&#160; 接着我们再添加Hibernate框架，如图：</p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200806/20080610092525346.jpg" /></p>
<p>接着选择将Hibernate的配置文件交给Spring来进行管理，如图：</p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200806/20080610092526893.jpg" /></p>
<p>再为Hibernate创建一个sessionFactory，如图：</p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200806/20080610092526739.jpg" /></p>
<p>接着再选择数据源，</p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200806/20080610092527924.jpg" /></p>
<p>接着是提示你是否建立sessionFactory，因为已经将sessionFactory交给Spring管理了，所以在这里不用创建了</p>
<p><img alt="" src="http://java.chinaitlab.com/UploadFiles_8734/200806/20080610092527759.jpg" /></p>
<p>
<p>&#160;&#160; 单击Finish，并将Spring中与Hibernate中一样的Jar包全部替换，这样就完成了对Hibernate框架的加载了。</p>
<p>接着再加载struts2框架，这里就不再详细说明了，详情参考Struts2 + Spring 整合简单例子。呵呵~~~</p>
<p>接着就是配置ApplicationContext.xml 文件。代码如图：</p>
<p>&lt;?xml version="1.0" encoding="UTF-8"?><br />
&lt;beans<br />
&#160;xmlns="http://www.springframework.org/schema/beans"<br />
&#160;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />
&#160;xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"></p>
<p><br />
&#160;&lt;bean id="dataSource"<br />
&#160;&#160;class="org.apache.commons.dbcp.BasicDataSource"><br />
&#160;&#160;&lt;property name="driverClassName"<br />
&#160;&#160;&#160;value="com.mysql.jdbc.Driver"><br />
&#160;&#160;&lt;/property><br />
&#160;&#160;&lt;property name="url" value="jdbc:mysql://localhost:3306/test">&lt;/property><br />
&#160;&#160;&lt;property name="username" value="root">&lt;/property><br />
&#160;&#160;&lt;property name="password" value="3348635">&lt;/property><br />
&#160;&lt;/bean><br />
&#160;&lt;bean id="sessionfactory"<br />
&#160;&#160;class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><br />
&#160;&#160;&lt;property name="dataSource"><br />
&#160;&#160;&#160;&lt;ref bean="dataSource" /><br />
&#160;&#160;&lt;/property><br />
&#160;&#160;&lt;property name="hibernateProperties"><br />
&#160;&#160;&#160;&lt;props><br />
&#160;&#160;&#160;&#160;&lt;prop key="hibernate.dialect"><br />
&#160;&#160;&#160;&#160;&#160;org.hibernate.dialect.MySQLDialect<br />
&#160;&#160;&#160;&#160;&lt;/prop><br />
&#160;&#160;&#160;&#160;<br />
&#160;&#160;&#160;&#160;&lt;!-- 以下是添加的，不是自动生成的 --><br />
&#160;&#160;&#160;&#160;&lt;prop key="hibernate.connection.autocommit">true&lt;/prop><br />
&#160;&#160;&#160;&#160;&lt;prop key="hibernate.show_sql">true&lt;/prop><br />
&#160;&#160;&#160;&#160;&lt;!--上面是方便我们对程序的调试，和操作&#160; -->&#160;&#160;&#160;&#160;<br />
&#160;&#160;&#160;&#160;<br />
&#160;&#160;&#160;&lt;/props><br />
&#160;&#160;&lt;/property><br />
&#160;&lt;/bean><br />
&#160;<br />
&#160;&lt;!-- 以下是添加的，不是自动生成的 --><br />
&#160;&lt;!-- HibernateTemplate是一个帮助类，它能简化Hibernate Session的编码和处理HibernateExceptions--><br />
&#160;&lt;bean id="hibernateTemplate" <br />
&#160;&#160;class="org.springframework.orm.hibernate3.HibernateTemplate"><br />
&#160;&#160;&lt;property name="sessionFactory"><br />
&#160;&#160;&#160;&lt;ref bean="sessionfactory"/><br />
&#160;&#160;&lt;/property><br />
&#160;&lt;/bean><br />
&#160;&lt;!-- 以上是手动添加的内容 --><br />
&#160;&lt;/beans></p>
<p>这里我们要注意添加注释的一段，这些是对我们接下去的程序很有帮助的。</p>
<p>再编写struts.xml 文件，具体代码如下（因现在只是配置三大框架的环境，所以很简单，空空如也）：</p>
<p>&lt;?xml version="1.0" encoding="UTF-8"?><br />
&lt;!DOCTYPE struts PUBLIC<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160; "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160; "http://struts.apache.org/dtds/struts-2.0.dtd"><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;struts><br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;/struts></p>
<p>接着就是最重要的web.xml配置文件了，在Struts2整合Spring的例子已经说明了，这里也不详说了，代码如下：</p>
<p>&lt;?xml version="1.0" encoding="UTF-8"?><br />
&lt;web-app version="2.5" <br />
&#160;xmlns="http://java.sun.com/xml/ns/javaee" <br />
&#160;xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <br />
&#160;xsi:schemaLocation="http://java.sun.com/xml/ns/javaee <br />
&#160;http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><br />
&#160;<br />
&#160;&lt;listener><br />
&#160;&#160;&lt;listener-class>org.springframework.web.context.ContextLoaderListener&lt;/listener-class><br />
&#160;&lt;/listener><br />
&#160;&lt;filter><br />
&#160;&#160;&lt;filter-name>struts2&lt;/filter-name><br />
&#160;&#160;&lt;filter-class>org.apache.struts2.dispatcher.FilterDispatcher&lt;/filter-class>&#160;&#160;<br />
&#160;&lt;/filter><br />
&#160;&lt;filter-mapping>&#160;<br />
&#160;&#160;&lt;filter-name>struts2&lt;/filter-name><br />
&#160;&#160;&lt;url-pattern>/*&lt;/url-pattern><br />
&#160;&lt;/filter-mapping><br />
&#160; &lt;welcome-file-list><br />
&#160;&#160;&#160; &lt;welcome-file>index.jsp&lt;/welcome-file><br />
&#160; &lt;/welcome-file-list><br />
&lt;/web-app></p>
<p>这时，还不能进行编写详细的代码，应该要先测试下这个环境出错了没。部署项目到 tomcat 里，运行没有</p>
<p>出现错误，如出现错误，请详细检查上面每一步的操作是否一致。</p>
<p>到此为止，开发环境三大框架整合的准备工作就完成了。</p>
</p>
<img src ="http://www.blogjava.net/over1988/aggbug/226792.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-09-03 22:13 <a href="http://www.blogjava.net/over1988/archive/2008/09/03/226792.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JPA注释标记一览表</title><link>http://www.blogjava.net/over1988/archive/2008/08/29/225585.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Fri, 29 Aug 2008 07:33:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/08/29/225585.html</guid><wfw:comment>http://www.blogjava.net/over1988/comments/225585.html</wfw:comment><comments>http://www.blogjava.net/over1988/archive/2008/08/29/225585.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/over1988/comments/commentRss/225585.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/over1988/services/trackbacks/225585.html</trackback:ping><description><![CDATA[<div>
<div>
<h2>Table</h2>
<p>Table用来定义entity主表的name，catalog，schema等属性。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name: 表名
    <li>catalog: 对应关系数据库中的catalog
    <li>schema：对应关系数据库中的schema
    <li>UniqueConstraints:定义一个UniqueConstraint数组，指定需要建唯一约束的列 </li>
</ul>
<div>
<pre>    <br />
@Entity<br />
@Table(name="CUST")<br />
public class Customer { ... }<br />
　　</pre>
</div>
</div>
<div>
<h2>SecondaryTable</h2>
<p>一个entity class可以映射到多表，SecondaryTable用来定义单个从表的名字，主键名字等属性。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name: 表名
    <li>catalog: 对应关系数据库中的catalog
    <li>schema：对应关系数据库中的schema
    <li>pkJoin: 定义一个PrimaryKeyJoinColumn数组，指定从表的主键列
    <li>UniqueConstraints:定义一个UniqueConstraint数组，指定需要建唯一约束的列 </li>
</ul>
<p>下面的代码说明Customer类映射到两个表，主表名是CUSTOMER，从表名是CUST_DETAIL，从表的主键列和主表的主键列类型相同，列名为CUST_ID。 </p>
<div>
<pre>                <br />
@Entity<br />
@Table(name="CUSTOMER")<br />
@SecondaryTable(name="CUST_DETAIL",pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"))<br />
public class Customer { ... }<br />
<br />
</pre>
</div>
</div>
<div>
<h2>SecondaryTables</h2>
<p>当一个entity class映射到一个主表和多个从表时，用SecondaryTables来定义各个从表的属性。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>value： 定义一个SecondaryTable数组，指定每个从表的属性。 </li>
</ul>
<div>
<pre>                <br />
@Table(name = "CUSTOMER")<br />
@SecondaryTables( value = {<br />
@SecondaryTable(name = "CUST_NAME", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }),<br />
@SecondaryTable(name = "CUST_ADDRESS", pkJoin = { @PrimaryKeyJoinColumn(name = "STMO_ID", referencedColumnName = "id") }) })<br />
public class Customer {}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>UniqueConstraint</h2>
<p>UniqueConstraint定义在Table或SecondaryTable元数据里，用来指定建表时需要建唯一约束的列。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>columnNames:定义一个字符串数组，指定要建唯一约束的列名。 </li>
</ul>
<div>
<pre>                <br />
@Entity<br />
@Table(name="EMPLOYEE",<br />
uniqueConstraints={@UniqueConstraint(columnNames={"EMP_ID", "EMP_NAME"})}<br />
)<br />
public class Employee { ... }<br />
<br />
</pre>
</div>
</div>
<div>
<h2>Column</h2>
<p>Column元数据定义了映射到数据库的列的所有属性：列名，是否唯一，是否允许为空，是否允许更新等。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name:列名。
    <li>unique: 是否唯一
    <li>nullable: 是否允许为空
    <li>insertable: 是否允许插入
    <li>updatable: 是否允许更新
    <li>columnDefinition: 定义建表时创建此列的DDL
    <li>secondaryTable: 从表名。如果此列不建在主表上（默认建在主表），该属性定义该列所在从表的名字。 </li>
</ul>
<div>
<pre>        <br />
public class Person {<br />
@Column(name = "PERSONNAME", unique = true, nullable = false, updatable = true)<br />
private String name;<br />
<br />
@Column(name = "PHOTO", columnDefinition = "BLOB NOT NULL", secondaryTable="PER_PHOTO")<br />
private byte[] picture;<br />
<br />
</pre>
</div>
</div>
<div>
<h2>JoinColumn</h2>
<p>如果在entity class的field上定义了关系（one2one或one2many等），我们通过JoinColumn来定义关系的属性。JoinColumn的大部分属性和Column类似。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name:列名。
    <li>referencedColumnName:该列指向列的列名（建表时该列作为外键列指向关系另一端的指定列）
    <li>unique: 是否唯一
    <li>nullable: 是否允许为空
    <li>insertable: 是否允许插入
    <li>updatable: 是否允许更新
    <li>columnDefinition: 定义建表时创建此列的DDL
    <li>secondaryTable: 从表名。如果此列不建在主表上（默认建在主表），该属性定义该列所在从表的名字。 </li>
</ul>
<p>下面的代码说明Custom和Order是一对一关系。在Order对应的映射表建一个名为CUST_ID的列，该列作为外键指向Custom对应表中名为ID的列。 </p>
<div>
<pre>                <br />
public class Custom {<br />
<br />
@OneToOne<br />
@JoinColumn(<br />
name="CUST_ID", referencedColumnName="ID", unique=true, nullable=true, updatable=true)<br />
public Order getOrder() {<br />
return order;<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>JoinColumns</h2>
<p>如果在entity class的field上定义了关系（one2one或one2many等），并且关系存在多个JoinColumn，用JoinColumns定义多个JoinColumn的属性。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>value: 定义JoinColumn数组，指定每个JoinColumn的属性。 </li>
</ul>
<p>下面的代码说明Custom和Order是一对一关系。在Order对应的映射表建两列，一列名为CUST_ID，该列作为外键指向Custom对应表中名为ID的列,另一列名为CUST_NAME，该列作为外键指向Custom对应表中名为NAME的列。 </p>
<div>
<pre>                <br />
public class Custom {<br />
@OneToOne<br />
@JoinColumns({<br />
@JoinColumn(name="CUST_ID", referencedColumnName="ID"),<br />
@JoinColumn(name="CUST_NAME", referencedColumnName="NAME")<br />
})<br />
public Order getOrder() {<br />
return order;<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>Id</h2>
<p>声明当前field为映射表中的主键列。id值的获取方式有五种：TABLE, SEQUENCE, IDENTITY, AUTO, NONE。Oracle和DB2支持SEQUENCE，SQL Server和Sybase支持IDENTITY,mysql支持AUTO。所有的数据库都可以指定为AUTO，我们会根据不同数据库做转换。NONE (默认)需要用户自己指定Id的值。元数据属性说明： </p>
<ul>
    <li>generate():主键值的获取类型
    <li>generator():TableGenerator的名字（当generate=GeneratorType.TABLE才需要指定该属性） </li>
</ul>
<p>下面的代码声明Task的主键列id是自动增长的。(Oracle和DB2从默认的SEQUENCE取值，SQL Server和Sybase该列建成IDENTITY，mysql该列建成auto increment。) </p>
<div>
<pre>                <br />
@Entity<br />
@Table(name = "OTASK")<br />
public class Task {<br />
@Id(generate = GeneratorType.AUTO)<br />
public Integer getId() {<br />
return id;<br />
}<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>IdClass</h2>
<p>当entity class使用复合主键时，需要定义一个类作为id class。id class必须符合以下要求:类必须声明为public，并提供一个声明为public的空构造函数。必须实现Serializable接，覆写 equals()和hashCode（）方法。entity class的所有id field在id class都要定义，且类型一样。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>value: id class的类名 </li>
</ul>
<p>&nbsp; </p>
<div>
<pre>                <br />
public class EmployeePK implements java.io.Serializable{<br />
String empName;<br />
Integer empAge;<br />
<br />
public EmployeePK(){}<br />
<br />
public boolean equals(Object obj){ ......}<br />
public int hashCode(){......}<br />
}<br />
<br />
<br />
@IdClass(value=com.acme.EmployeePK.class)<br />
@Entity(access=FIELD)<br />
public class Employee {<br />
@Id String empName;<br />
@Id Integer empAge;<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>MapKey</h2>
<p>在一对多，多对多关系中，我们可以用Map来保存集合对象。默认用主键值做key，如果使用复合主键，则用id class的实例做key，如果指定了name属性，就用指定的field的值做key。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name: 用来做key的field名字 </li>
</ul>
<p>下面的代码说明Person和Book之间是一对多关系。Person的books字段是Map类型，用Book的isbn字段的值作为Map的key。 </p>
<div>
<pre>                <br />
@Table(name = "PERSON")<br />
public class Person {<br />
<br />
@OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")<br />
@MapKey(name = "isbn")<br />
private Map books = new HashMap();<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>OrderBy</h2>
<p>在一对多，多对多关系中，有时我们希望从数据库加载出来的集合对象是按一定方式排序的，这可以通过OrderBy来实现，默认是按对象的主键升序排列。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>value: 字符串类型，指定排序方式。格式为"fieldName1 [ASC|DESC],fieldName2 [ASC|DESC],......",排序类型可以不指定，默认是ASC。 </li>
</ul>
<p>下面的代码说明Person和Book之间是一对多关系。集合books按照Book的isbn升序，name降序排列。 </p>
<div>
<pre>                <br />
@Table(name = "MAPKEY_PERSON")<br />
public class Person {<br />
<br />
@OneToMany(targetEntity = Book.class, cascade = CascadeType.ALL, mappedBy = "person")<br />
@OrderBy(name = "isbn ASC, name DESC")<br />
private List books = new ArrayList();<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>PrimaryKeyJoinColumn</h2>
<p>在三种情况下会用到PrimaryKeyJoinColumn。 </p>
<ul>
    <li>继承。
    <li>entity class映射到一个或多个从表。从表根据主表的主键列（列名为referencedColumnName值的列），建立一个类型一样的主键列，列名由name属性定义。
    <li>one2one关系，关系维护端的主键作为外键指向关系被维护端的主键，不再新建一个外键列。 </li>
</ul>
<p>&nbsp; </p>
<p>元数据属性说明： </p>
<ul>
    <li>name:列名。
    <li>referencedColumnName:该列引用列的列名
    <li>columnDefinition: 定义建表时创建此列的DDL </li>
</ul>
<p>下面的代码说明Customer映射到两个表，主表CUSTOMER,从表CUST_DETAIL，从表需要建立主键列CUST_ID，该列和主表的主键列id除了列名不同，其他定义一样。 </p>
<div>
<pre>            <br />
@Entity<br />
@Table(name="CUSTOMER")<br />
@SecondaryTable(name="CUST_DETAIL",pkJoin=@PrimaryKeyJoinColumn(name="CUST_ID"，referencedColumnName="id"))<br />
public class Customer { <br />
@Id(generate = GeneratorType.AUTO)<br />
public Integer getId() {<br />
return id;<br />
}<br />
}<br />
<br />
</pre>
</div>
<p>下面的代码说明Employee和EmployeeInfo是一对一关系，Employee的主键列id作为外键指向EmployeeInfo的主键列INFO_ID。 </p>
<div>
<pre>            <br />
@Table(name = "Employee")<br />
public class Employee {<br />
@OneToOne<br />
@PrimaryKeyJoinColumn(name = "id", referencedColumnName="INFO_ID")<br />
EmployeeInfo info;<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>PrimaryKeyJoinColumns</h2>
<p>如果entity class使用了复合主键，指定单个PrimaryKeyJoinColumn不能满足要求时，可以用PrimaryKeyJoinColumns来定义多个PrimaryKeyJoinColumn。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>value: 一个PrimaryKeyJoinColumn数组，包含所有PrimaryKeyJoinColumn。 </li>
</ul>
<p>下面的代码说明了Employee和EmployeeInfo是一对一关系。他们都使用复合主键，建表时需要在Employee表建立一个外键，从Employee的主键列id,name指向EmployeeInfo的主键列INFO_ID和INFO_NAME. </p>
<div>
<pre>            <br />
@Entity<br />
@IdClass(EmpPK.class)<br />
@Table(name = "EMPLOYEE")<br />
public class Employee {<br />
<br />
private int id;<br />
<br />
private String name;<br />
<br />
private String address;<br />
<br />
@OneToOne(cascade = CascadeType.ALL)<br />
@PrimaryKeyJoinColumns({<br />
@PrimaryKeyJoinColumn(name="id", referencedColumnName="INFO_ID"),<br />
@PrimaryKeyJoinColumn(name="name" , referencedColumnName="INFO_NAME")})<br />
EmployeeInfo info;<br />
}<br />
<br />
@Entity<br />
@IdClass(EmpPK.class)<br />
@Table(name = "EMPLOYEE_INFO")<br />
public class EmployeeInfo {<br />
<br />
@Id<br />
@Column(name = "INFO_ID")<br />
private int id;<br />
<br />
@Id<br />
@Column(name = "INFO_NAME")<br />
private String name;<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>Transient</h2>
<p>Transient用来注释entity的属性，指定的这些属性不会被持久化，也不会为这些属性建表。 </p>
<div>
<pre>    <br />
@Transient<br />
private String name;<br />
<br />
</pre>
</div>
</div>
<div>
<h2>Version</h2>
<p>Version指定实体类在乐观事务中的version属性。在实体类重新由EntityManager管理并且加入到乐观事务中时，保证完整性。每一个类只能有一个属性被指定为version，version属性应该映射到实体类的主表上。 </p>
<p>下面的代码说明versionNum属性作为这个类的version，映射到数据库中主表的列名是OPTLOCK。 </p>
<div>
<pre>                <br />
@Version<br />
@Column("OPTLOCK")<br />
protected int getVersionNum() { return versionNum; }<br />
<br />
</pre>
</div>
</div>
<div>
<h2>Lob</h2>
<p>Lob指定一个属性作为数据库支持的大对象类型在数据库中存储。使用LobType这个枚举来定义Lob是二进制类型还是字符类型。 </p>
<p>LobType枚举类型说明： </p>
<ul>
    <li>BLOB 二进制大对象，Byte[]或者Serializable的类型可以指定为BLOB。
    <li>CLOB 字符型大对象，char[]、Character[]或String类型可以指定为CLOB。 </li>
</ul>
<p>元数据属性说明： </p>
<ul>
    <li>fetch： 定义这个字段是lazy loaded还是eagerly fetched。数据类型是FetchType枚举，默认为LAZY,即lazy loaded.
    <li>type： 定义这个字段在数据库中的JDBC数据类型。数据类型是LobType枚举，默认为BLOB。 </li>
</ul>
<p>下面的代码定义了一个BLOB类型的属性和一个CLOB类型的属性。 </p>
<div>
<pre>                <br />
@Lob<br />
@Column(name="PHOTO" columnDefinition="BLOB NOT NULL")<br />
protected JPEGImage picture;<br />
<br />
@Lob(fetch=EAGER, type=CLOB)<br />
@Column(name="REPORT")<br />
protected String report;<br />
<br />
</pre>
</div>
</div>
<div>
<h2>JoinTable</h2>
<p>JoinTable在many-to-many关系的所有者一边定义。如果没有定义JoinTable，使用JoinTable的默认值。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>table:这个join table的Table定义。
    <li>joinColumns:定义指向所有者主表的外键列，数据类型是JoinColumn数组。
    <li>inverseJoinColumns:定义指向非所有者主表的外键列，数据类型是JoinColumn数组。 </li>
</ul>
<p>下面的代码定义了一个连接表CUST和PHONE的join table。join table的表名是CUST_PHONE，包含两个外键，一个外键是CUST_ID，指向表CUST的主键ID，另一个外键是PHONE_ID，指向表PHONE的主键ID。 </p>
<div>
<pre>                <br />
@JoinTable(<br />
table=@Table(name=CUST_PHONE),<br />
joinColumns=@JoinColumn(name="CUST_ID", referencedColumnName="ID"),<br />
inverseJoinColumns=@JoinColumn(name="PHONE_ID", referencedColumnName="ID")<br />
)<br />
<br />
</pre>
</div>
</div>
<div>
<h2>TableGenerator</h2>
<p>TableGenerator定义一个主键值生成器，在Id这个元数据的generate＝TABLE时，generator属性中可以使用生成器的名字。生成器可以在类、方法或者属性上定义。 </p>
<p>生成器是为多个实体类提供连续的ID值的表，每一行为一个类提供ID值，ID值通常是整数。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name:生成器的唯一名字，可以被Id元数据使用。
    <li>table:生成器用来存储id值的Table定义。
    <li>pkColumnName:生成器表的主键名称。
    <li>valueColumnName:生成器表的ID值的列名称。
    <li>pkColumnValue:生成器表中的一行数据的主键值。
    <li>initialValue:id值的初始值。
    <li>allocationSize:id值的增量。 </li>
</ul>
<p>下面的代码定义了两个生成器empGen和addressGen，生成器的表是ID_GEN。 </p>
<div>
<pre>                <br />
@Entity public class Employee {<br />
...<br />
@TableGenerator(name="empGen",<br />
table=@Table(name="ID_GEN"),<br />
pkColumnName="GEN_KEY",<br />
valueColumnName="GEN_VALUE",<br />
pkColumnValue="EMP_ID",<br />
allocationSize=1)<br />
@Id(generate=TABLE, generator="empGen")<br />
public int id;<br />
...<br />
}<br />
<br />
@Entity public class Address {<br />
...<br />
@TableGenerator(name="addressGen",<br />
table=@Table(name="ID_GEN"),<br />
pkColumnValue="ADDR_ID")<br />
@Id(generate=TABLE, generator="addressGen")<br />
public int id;<br />
...<br />
}<br />
<br />
</pre>
</div>
</div>
<div>
<h2>SequenceGenerator</h2>
<p>SequenceGenerator定义一个主键值生成器，在Id这个元数据的generator属性中可以使用生成器的名字。生成器可以在类、方法或者属性上定义。生成器是数据库支持的sequence对象。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name:生成器的唯一名字，可以被Id元数据使用。
    <li>sequenceName:数据库中，sequence对象的名称。如果不指定，会使用提供商指定的默认名称。
    <li>initialValue:id值的初始值。
    <li>allocationSize:id值的增量。 </li>
</ul>
<p>下面的代码定义了一个使用提供商默认名称的sequence生成器。 </p>
<div>
<pre>                <br />
@SequenceGenerator(name="EMP_SEQ", allocationSize=25)	<br />
<br />
</pre>
</div>
</div>
<div>
<h2>DiscriminatorColumn</h2>
<p>DiscriminatorColumn定义在使用SINGLE_TABLE或JOINED继承策略的表中区别不继承层次的列。 </p>
<p>元数据属性说明： </p>
<ul>
    <li>name:column的名字。默认值为TYPE。
    <li>columnDefinition:生成DDL的sql片断。
    <li>length:String类型的column的长度，其他类型使用默认值10。 </li>
</ul>
<p>下面的代码定义了一个列名为DISC，长度为20的String类型的区别列。 </p>
<div>
<pre>                <br />
@Entity<br />
@Table(name="CUST")<br />
@Inheritance(strategy=SINGLE_TABLE,<br />
discriminatorType=STRING,<br />
discriminatorValue="CUSTOMER")<br />
@DiscriminatorColumn(name="DISC", length=20)<br />
public class Customer { ... }<br />
</pre>
</div>
</div>
</div>
<img src ="http://www.blogjava.net/over1988/aggbug/225585.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-08-29 15:33 <a href="http://www.blogjava.net/over1988/archive/2008/08/29/225585.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SiteMesh的使用（转）</title><link>http://www.blogjava.net/over1988/archive/2008/08/27/225145.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Wed, 27 Aug 2008 13:22:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/08/27/225145.html</guid><wfw:comment>http://www.blogjava.net/over1988/comments/225145.html</wfw:comment><comments>http://www.blogjava.net/over1988/archive/2008/08/27/225145.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/over1988/comments/commentRss/225145.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/over1988/services/trackbacks/225145.html</trackback:ping><description><![CDATA[<span class="javascript">假设你打算结合多种技术来构建一个企业级web站点。比如，你准备采用J2EE技术往你的web站点里添加新内容，而这个系统的其他部分是用CGI或者微软的IIS Server搭建的。<br />
<br />
在 这种情况下，怎样让你的应用系统从外观和感受(look and feel)上保持一致呢？一种办案就是采用J2EE技术全部重写，然后选用一种框架，比如Struts-Tiles，但这种办案的开发成本太高，不太现 实。另一种可选方案是在你的应用系统的各个部分采用相同的Look and Feel。但这种方案会使维护站点变成噩梦，因为每当一个应用系统里面的Look and Feel需要改变的时候，你就需要让系统里的其他web应用保持同样的改变。<br />
<br />
大多数用于解决这种商务需求的可用框架都有一个共同的缺点， 他们不是平台相关就是框架相关。当你决定采用Tiles作为struts修饰器的时候，需要创建tiles定义文件tiles-defs.xml，然后在 struts-config.xml里面声明forwards，引用这些tiles以修饰原始的JSP。<br />
<br />
最简单的一种可能的解决方案是，全部采用纯html方式来生成你的web应用，每一个html页面都不需要知道自己将会被如何修饰，而是在外部采用某种机制来选择合适的修饰器修饰它们。这就是SiteMesh的功能。<br />
<br />
SiteMesh是基于Java、J2EE和XML的开源框架，依赖于从Servlet 2.3版本里引入的新功能——过滤器(Filters)<br />
<br />
安装和设置<br />
<br />
按照以往的经验，学习任何新技术或新框架最好的办法，就是使用它来创建一个简单的应用程序。所以，我们将使用SiteMesh来创建一个简单的Struts应用程序。我们的应用程序包括三个页面：<br />
<br />
&#8226;一个登录页面<br />
&#8226;一个帮助页面，包括页头和页脚<br />
&#8226;一个主页面，包括页头、页脚和页边菜单<br />
<br />
下面是创建这个简单web应用程序的步骤：<br />
<br />
1．SiteMesh基于过滤器，所以我们需要把SiteMesh过滤器通知给我们的web应用程序。在web.xml文件里加入如下几行：<br />
<br />
&lt;filter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;com.opensymphony.module.sitemesh.filter.PageFilter<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/filter-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-name&gt;debug.pagewriter&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;param-value&gt;true&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<br />
&lt;/filter&gt;<br />
&lt;filter-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />
&lt;/filter-mapping&gt;<br />
这 几行是告诉web容器，所有对web应用的请求都会经由PageFilter&#8220;过滤&#8221;一下。PageFilter是sitemesh-2.1.jar里的 一个类，你可以从http://www.opensymphony.com/sitemesh/download.html下载该jar包。<br />
<br />
2．在WEB-INF目录下生成一个decorators.xml文件，内容如下：<br />
<pre class="codeStyle">&lt;decorators defaultdir="/decorators"&gt;<br />
&lt;!— 给需要页边菜单的页面配置页边菜单修饰器 --&gt;
&lt;decorator name="sidemenu" page="sidemenu.jsp"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;pattern&gt;/home.jsp&lt;/pattern&gt;
&lt;/decorator&gt;<br />
&lt;!— 给需要页头和页脚的页面配置页头页脚修饰器 --&gt;
&lt;decorator name="headerfooter" page="headerfooter.jsp"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;pattern&gt;/help.jsp&lt;/pattern&gt;<br />
&lt;/decorator&gt;
&lt;/decorators&gt;</pre>
<br />
decorators.xml 文件用来在你的应用程序里定义修饰器(decorators)。在这个文件里，每个&lt;decorator&gt;元素定义一个修饰器，name指定 修饰器名，page指定修饰器所使用的JSP页面。&lt;pattern&gt;子元素指定这些修饰器如何应用到实际的页面上去。<br />
<br />
在我 们的示例web应用里，定义了两个修饰器：追加页头和页脚的headerfooter.jsp和追加页边菜单的sidemenu.jsp。我们想修饰 help页面追加页头和页脚，所以我们追加了一个/help.jsp路径子元素给headerfooter.jsp修饰器。<br />
<br />
3．在WebContent/decorators目录下创建headerfooter.jsp：<br />
<pre class="codeStyle"><br />
&lt;%@ taglib uri="<a href="http://www.opensymphony.com/sitemesh/decorator">http://www.opensymphony.com/sitemesh/decorator</a>" prefix="decorator" %&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;My Site - &lt;decorator:title default="Welcome!" /&gt;&lt;/title&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;decorator:head /&gt;
&lt;/head&gt;<br />
&lt;body&gt;
&lt;table&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;H1&gt;siteMesh Corporation&lt;H1&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt;&lt;decorator:body /&gt;&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tr&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;tr&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;td&gt; SiteMesh copyright&lt;/td&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/tr&gt;
&lt;/table&gt;
&lt;/body&gt;<br />
&lt;/html&gt;</pre>
<br />
一 个SiteMesh修饰器其实就是一个使用SiteMesh自定义标签的JSP页面。在我们的web应用里，当用户请求help页面的时候， SiteMesh会拦截这个请求，然后再把它发送给web应用。而当应用返回响应的时候，SiteMesh会结合headerfooter.jsp文件解 析这个响应，遇到&lt;decorator:head/&gt;就插入响应文件的&lt;head&gt;，遇到&lt;decorator: body/&gt;就插入响应文件的&lt;body&gt;。最后，被headerfooter.jsp修饰过的文件会被返回给客户端。<br />
<br />
4．在WebContent目录下创建help.jsp：<br />
<pre class="codeStyle"><br />
&lt;HTML&gt;<br />
&lt;HEAD&gt;<br />
&lt;%@ page <br />
language="java"<br />
contentType="text/html; charset=ISO-8859-1"<br />
pageEncoding="ISO-8859-1"<br />
%&gt;<br />
&lt;TITLE&gt;Help Page&lt;/TITLE&gt;<br />
&lt;/HEAD&gt;<br />
&lt;BODY&gt;<br />
Help Page <br />
&lt;/BODY&gt;<br />
&lt;/HTML&gt;</pre>
<br />
这是一个在web应用里很常见的help页面。<br />
<br />
5．在浏览器里请求help.jsp页面，测试SiteMesh安装是否正常。浏览器将会返回一个包含页头和页脚的help页面。<br />
<br />
SiteMesh架构<br />
<br />
SiteMesh 架构基于PageFilter——一个Servlet过滤器。容器接收到页面请求时，会把请求传递给PageFilter，PageFilter收集应用 程序的响应细节，生成自定义的响应对象，然后连同请求一起传递给web应用程序。web应用程序把响应资源写入到自定义响应对象里，再返回给 PageFilter。<br />
<br />
1．解析阶段<br />
当控制返回给PageFilter的时候，它会检查web应用生成响应的内容类型 (content type)，然后基于响应类型，生成不同的解析器来解析响应。比如，如果应用返回text/html类型的内容，SiteMesh会生成一个 FastPageParser实例，并把web应用生成的页面传递给它。FastPageParser会解析这个页面，提取出这个页面的header、 footer、title 等内容。<br />
<br />
2．修饰阶段<br />
<br />
解析结束后，SiteMesh开始修饰页面。这一阶段分成两部分：<br />
<br />
a．决定如何修饰<br />
<br />
SiteMesh 有一个概念，叫做修饰器映射，实现这个概念的接口是DecoratorMapper(有init()和getDecorator()方法)。映射器在 sitemesh.xml里声明。在sitemesh.xml文件里，每一个映射器都是它上一个映射器的父映射。当SiteMesh需要一个修饰器来修饰 页面的时候，会在sitemesh.xml里查找映射器，生成找到的第一个映射器的实例并调用getDecorator()方法，在这个方法里尝试查找针 对那个页面的修饰器。如果找到了就返回；否则，调用父映射器的getDecorator()方法，反复进行这个过程，直到找到正确的修饰器。<br />
<br />
b．应用修饰<br />
<br />
找到修饰器后，SiteMesh会把请求分发给它。修饰器JSP页面会访问在前阶段里解析出来的页面信息。使用各种SiteMesh自定义标签来提取页面信息不同的部分(比如header、footer和title)并把它们插入到输出文件合适的位置上去。<br />
<br />
你可以在sitemesh.xml文件里自定义使用哪个页面解析器来解析指定的内容类型或者使用哪种修饰器映射方案，比如：<br />
<pre class="codeStyle"><br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;sitemesh&gt;<br />
&lt;property name="decorators-file" value="/WEB-INF/decorators.xml"/&gt;<br />
&lt;excludes file="${decorators-file}"/&gt;<br />
&lt;page-parsers&gt;<br />
&lt;parser content-type="text/html" <br />
class="com.opensymphony.module.sitemesh.parser.FastPageParser" /&gt;<br />
&lt;/page-parsers&gt;<br />
&lt;decorator-mappers&gt;<br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper"&gt;<br />
&lt;param name="property.1" value="meta.decorator" /&gt;<br />
&lt;param name="property.2" value="decorator" /&gt;<br />
&lt;/mapper&gt;<br />
&lt;!-- Mapper for localization --&gt;<br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.LanguageDecoratorMapper"&gt;<br />
&lt;param name="match.en" value="en" /&gt;<br />
&lt;param name="match.zh" value="zh" /&gt;<br />
&lt;/mapper&gt;<br />
&lt;!-- Mapper for browser compatibility --&gt;<br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper"&gt;<br />
&lt;param name="match.MSIE" value="ie" /&gt;<br />
&lt;param name="match.Mozilla/" value="ns" /&gt;<br />
&lt;/mapper&gt;<br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper"&gt;<br />
&lt;param name="decorator" value="printable" /&gt;<br />
&lt;param name="parameter.name" value="printable" /&gt;<br />
&lt;param name="parameter.value" value="true" /&gt;<br />
&lt;/mapper&gt;<br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper"&gt;<br />
&lt;param name="decorator.parameter" value="decorator" /&gt;<br />
&lt;param name="parameter.name" value="confirm" /&gt;<br />
&lt;param name="parameter.value" value="true" /&gt;<br />
&lt;/mapper&gt;<br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper"&gt;<br />
&lt;param name="config" value="${decorators-file}" /&gt;<br />
&lt;/mapper&gt;<br />
&lt;/decorator-mappers&gt;<br />
&lt;/sitemesh&gt;</pre>
<br />
在 这个列表里，&lt;property name="decorators-file"&gt;指定了用于定义修饰器的文件。&lt;page-parsers&gt;定义了SiteMesh可 以处理的内容类型。每一个&lt;parser&gt;子元素指定哪一个解析器解析哪一种特定的内容类型。在我们的示例sitemesh.xml文件里， 我们告诉SiteMesh使用FastPageParser解析text/html类型的内容。默认地，SiteMesh只可以处理HTML，但我们可以 创建自己的解析器来处理其他的内容类型。<br />
<br />
&lt;decorator-mappers&gt;子元素定义了映射方案，SiteMesh使 用这个映射方案来查找修饰指定页面的修饰器。你可以使用&lt;param&gt;子元素来配置每一个映射器。SiteMesh会把这些配置信息包装成 java.util.Properties对象传递给映射器的init()方法。<br />
<br />
区域相关的修饰器<br />
<br />
在我们的示例sitemesh.xml文件里，有下面几行标签：<br />
<pre class="codeStyle"><br />
&lt;mapper class="com.opensymphony.module.sitemesh.mapper.LanguageDecoratorMapper"&gt;<br />
&lt;param name="match.en" value="en" /&gt;<br />
&lt;param name="match.zh" value="zh" /&gt;<br />
&lt;/mapper&gt;</pre>
<br />
当 查找一个应用于页面的修饰器时，SiteMesh会首先读取请求头部的Accept-Language信息。如果匹配en区域，SiteMesh会在修饰 器JSP文件名末尾追加-en。在我们的例子里，如果请求定义了修饰器headerfooter.jsp的help.jsp页面，并且使用的是区域是英 国，SiteMesh会首先查找并应用headerfooter-en.jsp修饰器，如果找不到再去应用headerfooter.jsp。<br />
<br />
浏览器相关的修饰器<br />
<br />
可以使用AgentDecoratorMapper来保证浏览器的兼容性：<br />
<pre class="codeStyle"><br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper"&gt;<br />
&lt;param name="match.MSIE" value="ie" /&gt;<br />
&lt;param name="match.Mozilla/" value="ns" /&gt;<br />
&lt;/mapper&gt;</pre>
<br />
这意味着当SiteMesh查找一个修饰器来修饰页面的时候，会首先提取出请求头部的User-Agent信息。如果是IE，就加上-ie到修饰器的文件名末尾，并查找和应用这个修饰器。如果找不到这样的修饰器，则继续应用headerfooter.jsp。<br />
<br />
高级SiteMesh<br />
<br />
SiteMesh提供映射器，让每一个页面参与到寻找自己修饰器的过程中去。<br />
<br />
PrintableDecoratorMapper<br />
<br />
大 多数的web站点都提供了一个获得可打印版本页面的功能。所谓可打印版本，一般是指去除了页头、页尾和页边菜单，并使用了另一套样式表的页面。在 SiteMesh里，我们可以使用PrintableDecoratorMapper来提供这个功能。要使用这个映射器，需要在sitemesh.xml 里追加如下几行：<br />
<pre class="codeStyle"><br />
&lt;mapper <br />
class= "com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper"&gt;<br />
&lt;param name="decorator" value="printable" /&gt;<br />
&lt;param name="parameter.name" value="printable" /&gt;<br />
&lt;param name="parameter.value" value="true" /&gt;<br />
&lt;/mapper&gt;</pre>
<br />
传递给PrintableDecoratorMapper的三个配置参数会被包装成java.util.Properties对象传递给init()方法。<br />
<br />
&#8226;decorator<br />
用来生成可打印版本页面的修饰器名。<br />
<br />
&#8226;parameter.name<br />
用来通知SiteMesh我们需要一个可打印版本的请求参数名。比如在我们的例子里，通过在查询字符串里追加printable=true参数传递<br />
<br />
&#8226;parameter.value<br />
设置可打印参数为何值时SiteMesh提供可打印版本的页面。<br />
<br />
PageDecoratorMapper<br />
<br />
页面可以通过定义META属性来重载指定修饰自己的修饰器名。<br />
<br />
要使用这个映射器，需要在sitemesh.xml文件里加入如下几行：<br />
<pre class="codeStyle"><br />
&lt;mapper <br />
class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper"&gt;<br />
&lt;param name="property.1" value="meta.decorator" /&gt;<br />
&lt;/mapper&gt;</pre>
<br />
PageDecoratorMapper可以获取一个参数列表。在我们的例子里，提供了一个参数名，指定了通过META属性来取得修饰器名。所以如果我们希望使用test修饰器来修饰页面，则在该页头部加入：<br />
<br />
&lt;META name="decorator" content="test"&gt;<br />
<br />
PageDecoratorMapper提供了一种静态的方法来让页面选择自己想要使用的修饰器。另外，页面还可以通过使用ParameterDecoratorMapper在运行时指定要使用的修饰器。<br />
<br />
ParameterDecoratorMapper<br />
<br />
要使用ParameterDecoratorMapper，在sitemesh.xml里追加如下几行：<br />
<pre class="codeStyle"><br />
&lt;mapper <br />
class= "com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper"&gt;<br />
&lt;param name="decorator.parameter" value="decorator" /&gt;<br />
&lt;param name="parameter.name" value="confirm" /&gt;<br />
&lt;param name="parameter.value" value="true" /&gt;<br />
&lt;/mapper&gt;</pre>
<br />
三个参数的意义分别如下：<br />
<br />
&#8226;decorator.parameter<br />
指定修饰器所使用的请求参数名。<br />
<br />
&#8226;parameter.name<br />
确定使用请求修饰器的确认参数名。<br />
<br />
&#8226;parameter.value<br />
确定使用请求修饰器的确认参数值。<br />
<br />
比如，如果你想使用test修饰器来修饰help.jsp，可以像下面这样访问help.jsp<br />
<br />
help.jsp?decorator=test&amp;confirm=true<br />
<br />
除了以上这些映射器以外，SiteMesh还提供了更多有用的映射器，比如：<br />
<br />
&#8226;FrameSetDecoratorMapper<br />
当页面是Frame的时候使用。<br />
<br />
&#8226;CookieDecoratorMapper<br />
可以通过cookie来指定想要使用的修饰器。<br />
<br />
&#8226;RobotDecoratorMapper<br />
当请求者被确人为robot的时候使用指定的修饰器。你可以手动的在请求头部追加robot关键字，或者通过修饰器来做。<br />
<br />
Velocity 和 Freemarker 修饰器<br />
<br />
SiteMesh 并没有限制你只能修饰JSP页面。你可以自由的选择想要修饰的对象，比如Velocity或者Freemarker。Velocity和 Freemarker是一种可被用于生成web页面的模板语言。这些语言比JSP更加的简单易用，但在可编程性方面不如JSP灵活。<br />
<br />
SiteMesh通过两个servlet支持这两种模板语言，这两个servlet也被定义在SiteMesh.jar文件里。我们可以像这样在web.xml里声明这两个servlet：<br />
<pre class="codeStyle"><br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;sitemesh-velocity&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt; <br />
com.opensymphony.module.sitemesh.velocity.VelocityDecoratorServlet<br />
&lt;/servlet-class&gt;<br />
&lt;/servlet&gt;<br />
&lt;!--Declare servlet for handling freemarker requests --&gt;<br />
&lt;servlet&gt;<br />
&lt;servlet-name&gt;sitemesh-freemarker&lt;/servlet-name&gt;<br />
&lt;servlet-class&gt;<br />
com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet<br />
&lt;/servlet-class&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;TemplatePath&lt;/param-name&gt;<br />
&lt;param-value&gt;/&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;init-param&gt;<br />
&lt;param-name&gt;default_encoding&lt;/param-name&gt;<br />
&lt;param-value&gt;ISO-8859-1&lt;/param-value&gt;<br />
&lt;/init-param&gt;<br />
&lt;/servlet&gt;<br />
&lt;!-- Velocity servlet should serve all requests with .vm extension--&gt;<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt;sitemesh-velocity&lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;*.vm&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;<br />
&lt;!-- FreeMarker servlet should serve all requests with .dec extension--&gt;<br />
&lt;servlet-mapping&gt;<br />
&lt;servlet-name&gt;sitemesh-freemarker&lt;/servlet-name&gt;<br />
&lt;url-pattern&gt;*.dec&lt;/url-pattern&gt;<br />
&lt;/servlet-mapping&gt;</pre>
<br />
当 然，我们还需要在lib文件夹里引入freemarker.jar、velocity-dep.jar和velocity-tools- view.jar。这些jar文件已经包含在SiteMesh的发布包里了。下面让我们修改第一个示例应用，使用Velocity和Freemarker 修饰器来取代JSP。在我们第一个示例应用里定义了两个修饰器：headerfooter和sidemenu。下面我们创建一个 headerfooter.dec：<br />
<pre class="codeStyle"><br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;My Site - $Advanced SiteMesh&lt;/title&gt;<br />
${head}<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;table border="1"&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt;SiteMesh Corporation&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt;${body}&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt;SiteMesh copyright&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/table&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</pre>
<br />
在 这个页面里，我们使用Freemarker模板来请求header、footer和title，而不是使用JSP自定义标签，但页面布局是一样的。当容器 接收到一个.dec扩展名的页面请求时，会把这个请求传递给FreemarkerDecoratorServlet，后者将会调用 FreemarkerDecorator修饰生成的HTML页面。我们使用$Advanced SiteMesh模板来访问应用生成的web页面的title，${head}访问head，${body}访问body。Freemarker提供了非 常丰富的模板，想深入研究的话可以参考http://www.javaworld.com/jw-01-2001/jw-0119- freemarker.html。<br />
<br />
相似的，在decorators目录下创建sidemenu.vm文件，这是Velocity修饰器文件：<br />
<pre class="codeStyle"><br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;title&gt;My Site - $title&lt;/title&gt;<br />
$head<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&lt;table border="1"&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt; SiteMesh Header &lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt; Sidemenu &lt;/td&gt;<br />
&lt;td&gt; $body &lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;tr&gt;<br />
&lt;td&gt; SiteMesh Footer &lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/table&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</pre>
<br />
使用$title模板取代&lt;decorator:title/&gt;，使用$head和$body Velocity模板来取代相应的JSP自定义标签。<br />
<br />
结论<br />
<br />
基 于过滤器的SiteMesh是一个非常灵活和简单易用的修饰器框架。但它还是存在着一些问题。首先，从Servlet 2.3版本才开始支持过滤器，所以一些早期版本的应用服务器无法支持SiteMesh。在使用SiteMesh之前请先检查一下您想使用的应用服务器是否 支持过滤器。<br />
<br />
另外，过滤器只有在使用浏览器请求一个页面的时候才能生效。所以，如果你通过浏览器访问home.jsp，它将被修饰，但如 果你使用Servlet的RequestDispatcher.include()或者forward()来控制home.jsp，修饰器就不起作用了。 但是不用担心，从Servlet 2.4版本开始，你可以配置过滤器适用的环境，包括forward和include的情况下都可以使用了。 </span>
<img src ="http://www.blogjava.net/over1988/aggbug/225145.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-08-27 21:22 <a href="http://www.blogjava.net/over1988/archive/2008/08/27/225145.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SiteMesh的使用 </title><link>http://www.blogjava.net/over1988/archive/2008/08/27/225135.html</link><dc:creator>OVER</dc:creator><author>OVER</author><pubDate>Wed, 27 Aug 2008 12:38:00 GMT</pubDate><guid>http://www.blogjava.net/over1988/archive/2008/08/27/225135.html</guid><wfw:comment>http://www.blogjava.net/over1988/comments/225135.html</wfw:comment><comments>http://www.blogjava.net/over1988/archive/2008/08/27/225135.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/over1988/comments/commentRss/225135.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/over1988/services/trackbacks/225135.html</trackback:ping><description><![CDATA[&nbsp;SiteMesh<span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">是一个用来在<span lang="EN-US">JSP</span>中实现页面布局和装饰（<span lang="EN-US">layout and decoration</span>）的框架组件，能够帮助网站开发人员较容易实现页面中动态内容和静态装饰外观的分离。提供了一种在网站中更有效的组织页面布局的方式。<span lang="EN-US"><o:p></o:p></span></span>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt"><font face="宋体"><span lang="EN-US" style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span>SiteMesh</span><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">设计思想是，用户发送<span lang="EN-US">request</span>至服务器，服务器根据此<span lang="EN-US">request</span>生成动态数据，生成网页，准备返回给客户端。就在返回前，<span lang="EN-US">SiteMesh</span>进行拦截，对此网页进行解析，将<span lang="EN-US">title</span>、<span lang="EN-US">body</span>等部分拆解出来，套上模板后，再返回给客户端。由于<span lang="EN-US">SiteMesh</span>在返回客户端的最后一步工作，此时的网页已经具备了标准的<span lang="EN-US">html</span>网页格式，因此<span lang="EN-US">SiteMesh</span>只需解析标准的<span lang="EN-US">html</span>网页，无需考虑各个<span lang="EN-US">Web</span>应用是应用了<span lang="EN-US">JSP</span>、<span lang="EN-US">ASP</span>，还是<span lang="EN-US">Velocity</span>技术，相当灵活。<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt"><font face="宋体"><span lang="EN-US" style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span>SiteMesh</span><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">使用了<span lang="EN-US">Decorator</span>的设计模式。<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt"><span lang="EN-US" style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体"><o:p><font face="宋体">&nbsp;</font></o:p></span></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体"><font face="宋体">本文为大家展示一个简单的<span lang="EN-US">SiteMesh</span>例子。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-align: left" align="left"><font face="宋体"><span lang="EN-US" style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">首先创建一个<span lang="EN-US">web</span>工程<span lang="EN-US">.</span>名字就叫做<span lang="EN-US">SitemeshSample.</span>将<span lang="EN-US">sitemesh-2.3.jar,</span></span><span lang="EN-US"><font size="3"> </font></span><span lang="EN-US" style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">commons-collections.jar</span><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">放到<span lang="EN-US">lib</span>目录下。<span lang="EN-US"><o:p></o:p></span></span></font></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-indent: 21pt; text-align: left" align="left"><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体"><font face="宋体">在<span lang="EN-US">web.xml</span>中加入如下片段<span lang="EN-US">:<o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;filter&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;filter-class&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>com.opensymphony.module.sitemesh.filter.PageFilter<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/filter-class&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/filter&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;filter-mapping&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;filter-name&gt;sitemesh&lt;/filter-name&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/filter-mapping&gt;<o:p></o:p></span></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-indent: 21pt"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span></span><font face="宋体"><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">这里定义了一个过滤器<span lang="EN-US">.</span>所有的请求都交由<span lang="EN-US">sitemesh</span>来处理</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></span></font></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p>&nbsp;</o:p></span></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-align: left" align="left"><font face="宋体"><span lang="EN-US" style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 9pt; mso-hansi-font-family: 宋体; mso-bidi-font-family: 宋体">在<span lang="EN-US">WEB-INF</span>下创建一个<span lang="EN-US">decorators.xml</span>文件<span lang="EN-US">,</span>内容如下<span lang="EN-US">:<o:p></o:p></span></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;decorators defaultdir="/decorators"&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;decorator name="main" page="main.jsp"&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;pattern&gt;/*&lt;/pattern&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/decorator&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/decorators&gt;<o:p></o:p></span></p>
<p class="MsoPlainText" style="margin: 0cm 0cm 0pt; text-align: left" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span></span><font face="宋体"><span style="font-size: 10pt; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'">这是定义了模板页，也就是所有页面在返回给客户端之前，先在这里加上装饰，套上模板。</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></span></font></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">defaultdir="/decorators"</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'">说明了模板页的路径。</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;decorator name="main" page="main.jsp"&gt;</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">模板页的名称。</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;pattern&gt;/*&lt;/pattern&gt;</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">表示对所有的</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">response</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">进行处理</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span></span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">在</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">web</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">下面建一个文件夹取名</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">decorators.</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">在</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">decoratots</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">下面创建上面定义的模板页面</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">main.jsp,</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">内容如下</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">:<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator"%&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;html&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;head&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;title&gt;&lt;decorator:title /&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;/title&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;body&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;p&gt;Add head decorator...&lt;/p&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;decorator:body /&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;p&gt;Add foot decorator...&lt;/p&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/body&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;/html&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">说明</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">:<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator"%&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">此处为</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">decorator</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">标签的声明。因为我们下面要使用到它</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;decorator:title /&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">把请求的原始页面的</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">title</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">内容插入到</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">&lt;title&gt;&lt;/title&gt;,</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">比如我们要请求</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">index.jsp</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">页面的时候。会把</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">index.jsp</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">中的</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">title</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">的内容放入到这里</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;decorator:body /&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">把请求的原始页面的</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">body</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">内容插入到</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">&lt;body&gt;&lt;/body&gt;,</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">发现没有我们在这句的前面加上了</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;p&gt;Add head decorator...&lt;/p&gt;</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">和</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;p&gt;Add foot decorator...&lt;/p&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">相当于给我们请求的页面的</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">body</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">内容加上了头部和尾部</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">.</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">实现了模板功能。</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">在</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">WEB-INF</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">下创建我们要请求访问的页面</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">index.jsp</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">，内容如下</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">:<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;html&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;head&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;title&gt;SiteMesh Sample Site&lt;/title&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/head&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;body&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Welcome to the SiteMesh sample...<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>&lt;/body&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">&lt;/html&gt;<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">把</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">web</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">工程部署到</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt">tomcat</span><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">容器中。</span><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 10pt; font-family: 宋体; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: 'Courier New'; mso-font-kerning: 0pt; mso-ascii-font-family: 'Courier New'; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">输入</span><span lang="EN-US"><a href="http://localhost:8080/SitemeshSample/index.jsp"><span style="font-size: 10pt; color: windowtext; font-family: 'Courier New'; mso-font-kerning: 0pt">http://localhost:8080/</span><span style="font-size: 9pt; color: windowtext; font-family: 宋体; mso-bidi-font-family: 宋体">SitemeshSample/index.jsp</span></a></span><span lang="EN-US" style="font-size: 9pt; font-family: 宋体; mso-bidi-font-family: 宋体"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 10pt; font-family: 'Courier New'; mso-font-kerning: 0pt"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">页面效果如下：</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'"><o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-layout-grid-align: none" align="left"><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">Add head decorator...<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align="left"><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">Welcome to the SiteMesh sample... <o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align="left"><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">Add foot decorator...<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-align: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align="left"><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">不难发现，我们</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">index.jsp</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">中只有</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">Welcome to the SiteMesh sample... </span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">一句。但是在返回给我们之前套上了</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">main.jsp</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">模板页。在它的前面和后面分别加上了一句话。通过</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'">Sitemesh</span><span style="font-size: 9.5pt; font-family: 宋体; mso-hansi-font-family: Verdana; mso-ascii-font-family: Verdana; mso-fareast-font-family: 宋体; mso-fareast-theme-font: minor-fareast">我们可以很容易实现页面中动态内容和静态装饰外观的分离。<br />
</span><span lang="EN-US" style="font-size: 9.5pt; font-family: 'Verdana','sans-serif'"><o:p><br />
<br />
本文章摘自：http://blog.chinaunix.net/u2/67919/showart_677228.html</o:p></span></p>
 <img src ="http://www.blogjava.net/over1988/aggbug/225135.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/over1988/" target="_blank">OVER</a> 2008-08-27 20:38 <a href="http://www.blogjava.net/over1988/archive/2008/08/27/225135.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>