将Tapestry与Hibernate结合使用

所以,你填写了所有的字段,提交了表格(没有验证错误),瞧:你会得到相同的表格,空白。发生了什么,数据去了哪里?

发生的情况是,我们没有告诉Tapestry在表单成功提交后要做什么(我们的意思是成功,没有验证错误)。Tapestry的默认行为是使用Address对象的新实例(因为地址字段不是持久字段)重新显示在新请求中发生的活动页面。

好吧,既然我们在创建对象,我们不妨将它们存储在某个地方。。。在数据库中。我们将快速将Tapestry与冬眠作为对象/关系映射层,并最终将数据存储在超级SQL(HSQLDB)数据库。HSQLDB是一个嵌入式数据库引擎,不需要安装-它将被Maven作为依赖项删除。

重新配置项目

我们将把这个项目从一个简单的Tapestry项目引导到一个使用Hibernate和HSQLDB的项目。

更新依赖项

首先,我们必须更新POM以列出一组新的依赖项,其中包括Hibernate、Tapestry/Hibernate集成库和HSQLDB JDBC驱动程序:

src/pom.xml(部分)
<依赖项><依赖性>org.apache.tapestry组织<artifactId>tapestry-hibernate<version>${tapestry-release-version}</依赖关系><依赖性><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId><版本>2.3.2</依赖关系>...</依赖项>

tapestry-hibernate库包括hibernate和tapestry核心,作为可传递依赖项。这意味着您可以简单地在<artifactId>元素中用“挂毯休眠”替换“挂毯核心”。

在更改POM并保存之后,Maven应该自动下载新依赖项的JAR。

休眠配置

Hibernate需要一个主配置文件Hibernate.cfg.xml,用于存储连接和其他数据。在src/main/resources文件夹中创建:

src/main/resources/hibernate.cfg.xml
<!DOCTYPE休眠配置PUBLIC“-//Hibernate/Hibernate配置DTD 3.0//EN”http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><休眠配置><会话-工厂>org.hsqldb.jdbcDriver<property name=“hibernate.connection.url”>jdbc:hsqldb:/目标/工作/t5_tutorial1;shutdown=true</property><property name=“hibernate.dialect”>组织.hibernate.对话。HSQL方言</property>sa</property name=“hibernate.connection.username”>sa<property name=“hibernate.connection.password”>更新<property name=“hibernate.show_sql”>true<property name=“hibernate.format_sql”>true</session-factory></hibernate-configuration>

大多数配置都是为了标识JDBC驱动程序和连接URL。

注意连接URL。我们正在指示HSQLDB将其数据库文件存储在项目的目标目录中。我们还指示HSQLDB在关闭时将所有数据刷新到这些文件中。这意味着数据将在该项目的不同调用中保持不变,但如果目标目录被破坏(例如,通过“mvn-clean”),则所有数据库内容都将丢失。

此外,我们正在将Hibernate配置为更新数据库模式;当Hibernate初始化时,它将创建甚至修改表以匹配实体。最后,我们将Hibernate配置为输出它执行的任何SQL,这在最初构建应用程序时非常有用。

但是什么实体呢?通常,可用的实体列在hibernate.cfg.xml中,但Tapestry不需要这样做;在另一个约定优先于配置的示例中,Tapestry将所有实体类定位在实体包中(在我们的示例中是“com.example.tutorial1.entities”),并将它们添加到配置中。目前,这只是Address实体。

添加休眠注释

对于要与Hibernate一起使用的实体类,必须向类中添加一些HibernateAnnotation。

下面是更新后的Address类,带有Hibernate注释(以及Tapestry注释)。

src/main/java/com/example/tutorial/entities/Address.java
包com.example.tutorial1.entities;导入javax.persistence。实体;导入javax.persistence。生成值;导入javax.persistence。GenerationType;导入javax.persistence。身份证件;导入org.apache.tapestry5.beanpeditor。非视觉;导入org.apache.tapestry5.beaneditor。验证;导入com.example.tutorial1.data。荣誉;@实体公共类地址{@身份证@GeneratedValue(策略=GenerationType.INDITY)@非可视公共Long id;公众荣誉敬语;@验证(“必需”)public String firstName;@验证(“必需”)public String lastName;公共String street1;公共String street2;@验证(“必需”)公共字符串城市;@验证(“必需”)公共字符串状态;@验证(“必需,regexp”)public String zip;公共字符串电子邮件;公共String电话;}

Tapestry注释@NonVisual和@Validate可以放在setter或getter方法或字段上(正如我们在这里所做的那样)。与Hibernate注释一样,将注释放在字段上需要字段名与相应的属性名匹配。

  • @非可视–表示用户不应看到的字段,如主键。
  • @验证–标识与字段关联的验证。

此时,您应该停止并重新启动应用程序。

更新数据库

所以我们建立了一个数据库,Hibernate被配置为连接到它。让我们利用它将Address对象存储在数据库中。

我们需要的是在提交表单时提供一些要执行的代码。提交Tapestry表单时,会触发一系列事件。我们感兴趣的事件是“成功”事件,在从请求中提取所有值并将其应用于页面属性之后,以及在发生所有服务器端验证之后,该事件在流程的后期出现。

只有在没有验证错误时才会触发成功事件。

我们的事件处理程序必须做两件事:

  • 使用Hibernate Session对象保存新的Address对象。
  • 提交事务以强制将数据写入数据库。

让我们更新CreateAddress.java类:

src/main/java/com/example/tutorial/pages/address/CreateAddress.java
包com.example.tutorial1.pages.address;导入com.example.tutorial1.entities。地址;导入com.example.tutorial1.pages。索引;导入org.apache.tapestry5.annotations。注入页面;导入org.apache.tapestry5.annotations。财产;导入org.apache.tapestry5.hibernate.annotations。CommitAfter;导入org.apache.tapestry5.ioc.annotations。注入;导入org.hibernate。会议;公共类CreateAddress{@财产私人地址;@注入私人会话;@注入页面私有指数;@提交之后对象onSuccess(){session.persist(地址);收益指数;}}

这个注入注释告诉Tapestry将服务注入注释字段;Tapestry包括一个复杂的Inversion of Control容器(在许多方面与Spring类似),它非常善于按类型而不是字符串id定位可用服务。在任何情况下,Hibernate Session对象都是作为Tapestry-IoC服务公开的,准备注入(这是tapestry-hibernate模块提供的功能之一)。

Tapestry根据需要自动启动事务;然而,该交易将中止默认情况下,在请求结束时。如果我们对持久性对象进行更改,例如添加新的Address对象,则必须提交事务。

这个提交之后注释可以应用于任何组件方法;如果该方法正常完成,则将提交事务(并启动一个新事务来替换提交的事务)。

保存新地址后,我们返回到应用程序的主索引页面。

注意:在实际应用程序中,很少有页面和组件直接使用Hibernate会话。通常,定义自己的数据访问对象层以执行常见的更新操作和查询是一种更好的方法。

显示地址

作为下一步操作的预览,让我们在应用程序的“索引”页面上显示用户输入的所有地址。输入几个名称后,它将类似于:

将网格添加到索引页面

那么,这是如何实现的呢?主要是由网格组件。

网格组件基于与BeanEditForm组件相同的概念;它可以把一个豆子分成几列。这些列是可排序的,当一个页面上容纳的条目太多时,会自动添加页面导航。

最小网格很容易添加到模板中。只需将其添加到Index.tml底部附近即可:

src/main/webapp/Index.tml(部分)
<t:grid source=“地址”include=“荣誉,名字,姓氏,街道1,城市,州,邮政编码,电话”/>

请注意,Grid组件接受许多与BeanEditForm相同的参数。在这里,我们使用include参数指定要显示的属性以及显示顺序。

现在我们要做的就是在Java代码中提供地址属性。下面是Index.java现在的外观:

src/main/java/com/example/tutorial/pages/Index.java
软件包com.example.tutorial1.pages;导入java.util。列表;导入org.apache.tapestry5.ioc.annotations。注入;导入org.hibernate。会议;导入com.example.tutorial1.entities。地址;公共类索引{@注入私人会话;公共列表<Address>getAddresses(){return session.createCriteria(Address.class).list();}}

这里,我们使用Hibernate Session对象查找数据库中的所有Address对象。发生的任何排序都将在内存中完成。目前这还可以(数据库中只有少数Address对象)。稍后,我们将看到如何为非常大的结果集优化此操作。

接下来是什么?

我们还有很多要谈的:更多的组件、更多的定制、内置的Ajax支持、更常见的设计和实现模式,甚至编写自己的组件(这很容易!)。