Tapestry 教程(七)在Tapestry中一塊兒使用Hibernate

好了,你填寫了全部的輸入域,提交了這個表單(沒有任何驗證錯誤),瞧:你又回到了相同的表單,全部的格子裏面都是空的。發生了什麼,數據都到哪兒去了?html

所發生的就是咱們尚未告訴Tapestry在表單成功提交(得是成功的,咱們的意思是,沒有驗證錯誤)以後接下來要作什麼。Tapestry的默認行爲是從新顯示當前的page,而這是在一個新的請求當中,Address對象已是一個新的實體了(由於address屬性域不是一個持久化的屬性域)。java

好吧,由於咱們已經建立了對象,咱們可能也應該將它們在某個地方存儲起來……在一個數據庫中。咱們準備將Hibernate快速集成到Tapestry中,做爲其對象/關係映射層,而且最終把數據存儲到一個HyperSQLHSQLDB)數據庫中。HSQLDB是一個嵌入式的數據庫引擎,無需安裝——它將會由Maven做爲依賴獲取下來。web

從新對項目進行配置

咱們將吧這個項目從一個簡單的Tapestry項目慢慢變成一個使用了HibernateHSQLDBTapestry項目。sql

更新依賴

首先,咱們必須更新POM文件,添加一些新的依賴,包括HibernateTapestry/Hibernate集成庫,以及HSQLDB JDBC驅動:數據庫

 

src/pom.xml(局部)apache

<dependencies>api

 

    <dependency>服務器

        <groupId>org.apache.tapestry</groupId>session

        <artifactId>tapestry-hibernate</artifactId>app

        <version>${tapestry-release-version}</version>

    </dependency>

 

    <dependency>

        <groupId>org.hsqldb</groupId>

        <artifactId>hsqldb</artifactId>

        <version>2.3.2</version>

    </dependency>

    ...

</dependencies>

 

Tapestry-hibernate庫包括Hibernatetapestry-core。這意味着你能夠在<artifact>元素中簡單地將「tapestry-core」用「tapestry-hibernate」替換。

修改了POM並保存以後,Maven應該會自動下載新的依賴的JAR包。

Hibernate 配置

Hibernate須要一個主配置文件,hibernate.cfg.xml,用來存儲鏈接和其它數據。在你的src/mian/resources 文件夾下面建立它:

 

src/main/resources/hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC

        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>

        <property name="hibernate.connection.url">jdbc:hsqldb:./target/work/t5_tutorial1;shutdown=true</property>

        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>

        <property name="hibernate.connection.username">sa</property>

        <property name="hibernate.connection.password"></property>

        <property name="hbm2ddl.auto">update</property>

        <property name="hibernate.show_sql">true</property>

        <property name="hibernate.format_sql">true</property>

    </session-factory>

</hibernate-configuration>

 

配置的大部份內容用來指定JDBC驅動和鏈接的URL

注意下鏈接的URL。咱們指示HSQLDB將其數據庫文件存儲在了項目的目標目錄。還指示HSQLDB在停掉應用時將數據刷到這些文件中。這意味着數據在項目的不一樣時期都會持續存在,但若是目標目錄被摧毀了(例如,經過「mvn clean」),那麼全部的數據庫內容都會丟失掉。

此外,咱們還配置了要Hibernate來更新數據庫的schema:當Hibernate初始化時它將會建立甚至於更新數據表,以匹配Java代碼中的實體類。最後,咱們配置Hibernate輸出其執行的任何SQL,這在一開始構建應用程序時很是有用。

然而有哪些實體呢?通常,可用的實體都會列在hibernate.cfg.xml中,不過使用Tapestry的話這就沒什麼必要了;在其它約定大於配置的示例中,Tapestry會定位全部位於entities包(這裏就是「com.example.tutorial1.entities」)中的實體類,並將它們添加到配置中。當前,就只有一個Address實體。

添加Hibernate註解

對於要用上Hibernate的實體,必須向其類中添加一些Hibernate的註解。

下面是更新事後的Address類,帶上了Hibernate的註解(還有就是Tapestry的)。

 

src/main/java/com/example/tutorial/entities/Address.java

package com.example.tutorial1.entities;

 

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

 

import org.apache.tapestry5.beaneditor.NonVisual;

import org.apache.tapestry5.beaneditor.Validate;

 

import com.example.tutorial1.data.Honorific;

 

@Entity

public class Address

{

  @Id

  @GeneratedValue(strategy = GenerationType.IDENTITY)

  @NonVisual

  public Long id;

 

  public Honorific honorific;

 

  @Validate("required")

  public String firstName;

 

  @Validate("required")

  public String lastName;

 

  public String street1;

 

  public String street2;

 

  @Validate("required")

  public String city;

 

  @Validate("required")

  public String state;

 

  @Validate("required,regexp")

  public String zip;

 

  public String email;

 

  public String phone;

}

 

Tapestry的註解,@NonVisual@Validate,可能會被放置在setter或者getter或者屬性域之上(像咱們這裏這樣作的)。因爲使用了Hibernate的註解,將註解放置到了屬性域之上就要求屬性域的名稱對應到屬性的名稱。

@NonVisual——表示一個屬性域,好比主鍵,應該不被用戶看見。

@Validate——將驗證同屬性域關聯。

此處你應該中止並重啓應用程序。

更新數據庫

這樣咱們就有了一個數據庫,而且Hibernate也被配置好了來鏈接它。讓咱們利用其來存儲咱們的Address對象。咱們所須要的是提供一些代碼在表單被提交時執行。當Tapestry的表單被提交時,有一系列的時間被觸發。咱們感興趣的是「success」事件,其在過程當中處在比較晚的後期,要等到全部的值都已經從請求中獲取到而且設置到page屬性上以後,還得是在全部服務器端驗證發生以後。

Success事件只會在沒有驗證錯誤的時候被觸發。

咱們的事件處理器必需要作兩件事:

使用Hibernate Session對象將新的Address對象持久化

將事務提交,強制讓數據被寫入數據庫。

讓咱們來更新一下CreateAddress.java類:

 

src/main/java/com/example/tutorial/pages/address/CreateAddress.java

package com.example.tutorial1.pages.address;

 

import com.example.tutorial1.entities.Address;

import com.example.tutorial1.pages.Index;

import org.apache.tapestry5.annotations.InjectPage;

import org.apache.tapestry5.annotations.Property;

import org.apache.tapestry5.hibernate.annotations.CommitAfter;

import org.apache.tapestry5.ioc.annotations.Inject;

import org.hibernate.Session;

 

public class CreateAddress

{

    @Property

    private Address address;

 

    @Inject

    private Session session;

 

    @InjectPage

    private Index index;

 

    @CommitAfter

    Object onSuccess()

    {

        session.persist(address);

 

        return index;

    }

}

 

Inject註解會告訴Tapestry要將一個服務注入到註解的屬性域中;Tapestry包含一個複雜精緻的控制反轉容器(不少方面都相似於Spring),很是善於根據類型定位可用的服務,而不是根據stringid。不管什麼時候,Hibernate Session對象都是做爲一個TapestryIoC服務被暴露出來的,能夠被注入(這是一個由tapestry-hibernate模塊提供的東西)。

必要時Tapestry會自動開啓一個事務;不過該事務默認會在最後被取消。若是咱們隊持久化對象作了修改,好比添加了一個新的Address對象,那麼有必要提交這個事務。

CommitAfter註解能夠被應用於任何component的方法;若是方法照常完成,那事務就會被提交(並且一個新的事務會開始替換已經提交的事務)。

將新的地址持久化了以後,咱們要返回應用程序的Index page

注意:在真實的應用程序中,不多會讓pagecomponent直接使用Hibernate Sessin。通常更好的方式是定義你本身的數據訪問對象(Data Access Object)層來執行通用的更新和查詢操做。

展現地址數據

做爲接下來的一個小預覽,下面所展現的是應用程序的Index page上由用戶輸入的全部地址數據。在你輸入了一些名字以後,看起來就會像下面這樣:

Index page中添加一個表格

好吧,這是如何實現的呢?一般,這是由Grid componet實現的。

Grid component基於跟BeanEditForm component一樣的概念;它能夠將一個bean解析成數據列。數據列是能夠排序的,而且當數據量超過了一頁所能展現的量,分頁導航就會自動被加上。

最輕量的Grid很是容易被添加到模板中。只要把這個添加到Index.tml的底部就好了:

 

src/main/webapp/Index.tml (partial)

<t:grid source="addresses"

       include="honorific,firstName,lastName,street1,city,state,zip,phone"/>

 

注意Grid component能夠接收咱們曾在BeanEditForm上使用過的相同的參數。這裏咱們使用include參數來指定要展現的屬性,還有使用哪一種順序。

現再咱們所要作的就是在Java代碼中提供這個addresses屬性。這裏展現了Index.java如今應該是什麼樣子:

 

src/main/java/com/example/tutorial/pages/Index.java

package com.example.tutorial1.pages;

import java.util.List;

import org.apache.tapestry5.ioc.annotations.Inject;

import org.hibernate.Session;

import com.example.tutorial1.entities.Address;

public class Index

{

    @Inject

    private Session session;

    public List<Address> getAddresses()

    {

        return session.createCriteria(Address.class).list();

    }

}

 

這裏,咱們使用的是Hibernate Session對象找到數據庫中全部的Address對象數據。全部的排序都會在內存中完成。這在目前看來還好(只有幾個Address對象在數據庫中而已)。稍後咱們將會看到如何針對極大的結果集進行優化。

接下來是什麼?

咱們還有更多要聊的:更多的component、更多的自定義、內置的Ajax支持,更多通用的設計和實現模式,甚至還要編寫你本身的組件(這很簡單!)。

去查看文檔頁面上衆多的Tapestry資源吧,包括入門FAQ頁面,還有Cookbook。請確保要利用好用戶指南,它提供了幾乎每個Tapestry主題的很是詳細的信息。最後,確保看過(而且收藏了)Tapestry JumpStart,它提供了幾乎是海量的教程哦。

相關文章
相關標籤/搜索