tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Using Tapestry With Hibernate
Date Tue, 22 Nov 2011 22:13:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Using+Tapestry+With+Hibernate">Using
Tapestry With Hibernate</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~hlship">Howard
M. Lewis Ship</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        Update to 5.3<br />
    </div>
        <br/>
                         <h4>Changes (20)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >So, you fill in all the fields, submit
the form (without validation errors) and voila: you get back the same form, blanked out. What
happened, and where did the data go? <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >What happened is that we haven&#39;t
told Tapestry what to do after the form is <span class="diff-changed-words">succes<span
class="diff-added-chars"style="background-color: #dfd;">s</span>fully</span>
submitted (by <span class="diff-changed-words">succes<span class="diff-added-chars"style="background-color:
#dfd;">s</span>ful,</span> we mean, with no validation errors). Tapestry&#39;s
default behavior is to redisplay the active page, and that occurs in a new request, with a
new instance of the Address object (because the address field is not a peristent field). <br></td></tr>
            <tr><td class="diff-unchanged" > <br>Well, since we&#39;re
creating objects, we might as well store them somewhere ... in a database. We&#39;re going
to quickly integrate Tapestry with [Hibernate|http://hibernate.org] as the object/relational
mapping layer, and ultimately store our data inside a [HSQLDB|http://www.hsqldb.org/] database.
HSQLDB is an embedded database engine and requires no installation -- it will be pulled down
as a dependency via maven. <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >Since Hibernate can work with so many
different databases, we must explicitly add in the correct driver. <br> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">After
changing the POM, you must re-execute the command {{mvn eclipse:eclipse -DdownloadSources=true}}.
Then, inside Eclipse, right click on the project (in Package Explorer) and select the &quot;Refresh&quot;
menu item. You should also stop Jetty. <br> <br></td></tr>
            <tr><td class="diff-unchanged" >h3. Hibernate Configuration <br>
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >        &lt;property name=&quot;hibernate.format_sql&quot;&gt;true&lt;/property&gt;
<br>    &lt;/session-factory&gt; <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-changed-words">&lt;/hibernate-configuration&gt;<span
class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;">{code}</span></span>
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{code}
<br></td></tr>
            <tr><td class="diff-unchanged" > <br>Most of the configuration
is to identify the JDBC driver and connection URL. <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>{code:title=src/main/java/org/apache/tapestry5/tutorial/entities/Address.java}
<br></td></tr>
            <tr><td class="diff-changed-lines" >package <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">org.apache.tapestry5.tutorial.entities;</span>
<span class="diff-added-words"style="background-color: #dfd;">com.example.tutorial.entities;</span>
<br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">import
org.apache.tapestry5.beaneditor.NonVisual; <br>import org.apache.tapestry5.beaneditor.Validate;
<br>import org.apache.tapestry5.tutorial.data.Honorific; <br> <br></td></tr>
            <tr><td class="diff-unchanged" >import javax.persistence.Entity; <br>import
javax.persistence.GeneratedValue; <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >import javax.persistence.Id; <br>
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">import
org.apache.tapestry5.beaneditor.NonVisual; <br>import org.apache.tapestry5.beaneditor.Validate;
<br> <br>import com.example.tutorial.data.Honorific; <br> <br></td></tr>
            <tr><td class="diff-unchanged" >@Entity <br>public class Address
<br>{ <br></td></tr>
            <tr><td class="diff-unchanged" >  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @NonVisual <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> Long
id; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> Honorific
honorific; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-unchanged" >  @Validate(&quot;required&quot;)
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
firstName; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-unchanged" >  @Validate(&quot;required&quot;)
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
lastName; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
street1; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
street2; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-unchanged" >  @Validate(&quot;required&quot;)
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
city; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-unchanged" >  @Validate(&quot;required&quot;)
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
state; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-unchanged" >  @Validate(&quot;required,regexp&quot;)
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
zip; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
email; <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">private</span>
<span class="diff-added-words"style="background-color: #dfd;">public</span> String
phone; <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">}
<br>{code} <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">
   public Long getId() <br>    { <br>        return id; <br>    } <br>
<br>    public void setId(Long id) <br>    { <br>        this.id = id; <br>
   } <br> <br>    public Honorific getHonorific() <br>    { <br> 
      return honorific; <br>    } <br> <br>    public String getFirstName()
<br>    { <br>        return firstName; <br>    } <br> <br>
   public String getLastName() <br>    { <br>        return lastName; <br>
   } <br> <br>    public String getStreet1() <br>    { <br>      
 return street1; <br>    } <br> <br>    public String getStreet2() <br>
   { <br>        return street2; <br>    } <br> <br>    public String
getCity() <br>    { <br>        return city; <br>    } <br> <br>
   public String getState() <br>    { <br>        return state; <br>   
} <br> <br>    public String getZip() <br>    { <br>        return
zip; <br>    } <br> <br>    public String getEmail() <br>    { <br>
       return email; <br>    } <br> <br>    public String getPhone() <br>
   { <br>        return phone; <br>    } <br> <br>    public void
setCity(String city) <br>    { <br>        this.city = city; <br>    } <br>
<br>    public void setEmail(String email) <br>    { <br>        this.email
= email; <br>    } <br> <br>    public void setFirstName(String firstName)
<br>    { <br>        this.firstName = firstName; <br>    } <br> <br>
   public void setHonorific(Honorific honorific) <br>    { <br>        this.honorific
= honorific; <br>    } <br> <br>    public void setLastName(String lastName)
<br>    { <br>        this.lastName = lastName; <br>    } <br> <br>
   public void setPhone(String phone) <br>    { <br>        this.phone = phone;
<br>    } <br> <br>    public void setState(String state) <br>   
{ <br>        this.state = state; <br>    } <br> <br>    public void
setStreet1(String street1) <br>    { <br>        this.street1 = street1; <br>
   } <br> <br>    public void setStreet2(String street2) <br>    { <br>
       this.street2 = street2; <br>    } <br> <br>    public void setZip(String
zip) <br>    { <br>        this.zip = zip; <br>    } <br>}{code} <br>
<br></td></tr>
            <tr><td class="diff-unchanged" >The Tapestry annotations, @NonVisual
and @Validate, may be placed on the setter or getter method or on the field (as we have done
here). As with the Hibernate annotations, putting the annotation on the field requires that
the field name match the corresponding property name. <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Using+BeanEditForm+To+Create+User+Forms"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Using+BeanEditForm+To+Create+User+Forms">Using
BeanEditForm To Create User Forms</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/Tapestry+Tutorial"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/TAPESTRY/Tapestry+Tutorial">Tapestry Tutorial</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;</td></tr></table></div>

<p>So, you fill in all the fields, submit the form (without validation errors) and voila:
you get back the same form, blanked out. What happened, and where did the data go?</p>

<p>What happened is that we haven't told Tapestry what to do after the form is successfully
submitted (by successful, we mean, with no validation errors). Tapestry's default behavior
is to redisplay the active page, and that occurs in a new request, with a new instance of
the Address object (because the address field is not a peristent field).</p>

<p>Well, since we're creating objects, we might as well store them somewhere ... in
a database. We're going to quickly integrate Tapestry with <a href="http://hibernate.org"
class="external-link" rel="nofollow">Hibernate</a> as the object/relational mapping
layer, and ultimately store our data inside a <a href="http://www.hsqldb.org/" class="external-link"
rel="nofollow">HSQLDB</a> database. HSQLDB is an embedded database engine and requires
no installation &#8211; it will be pulled down as a dependency via maven.</p>

<h2><a name="UsingTapestryWithHibernate-ReconfiguringtheProject"></a>Re-configuring
the Project</h2>

<p>We're going to bootstrap this project from a simple Tapestry project to one that
uses Hibernate and HSQLDB.</p>

<h3><a name="UsingTapestryWithHibernate-UpdatingtheDependencies"></a>Updating
the Dependencies</h3>

<p>First, we must update the POM to list a new set of dependencies, that includes Hibernate,
the Tapestry/Hibernate integration library, and the HSQLDB JDBC driver:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>src/pom.xml (partial)</b></div><div
class="codeContent panelContent">
<pre class="code-xml">
    <span class="code-tag">&lt;dependencies&gt;</span>
        <span class="code-tag">&lt;dependency&gt;</span>
            <span class="code-tag">&lt;groupId&gt;</span>org.apache.tapestry<span
class="code-tag">&lt;/groupId&gt;</span>
            <span class="code-tag">&lt;artifactId&gt;</span>tapestry-hibernate<span
class="code-tag">&lt;/artifactId&gt;</span>
            <span class="code-tag">&lt;version&gt;</span>${tapestry-release-version}<span
class="code-tag">&lt;/version&gt;</span>
        <span class="code-tag">&lt;/dependency&gt;</span>

        <span class="code-tag">&lt;dependency&gt;</span>
            <span class="code-tag">&lt;groupId&gt;</span>hsqldb<span
class="code-tag">&lt;/groupId&gt;</span>
            <span class="code-tag">&lt;artifactId&gt;</span>hsqldb<span
class="code-tag">&lt;/artifactId&gt;</span>
            <span class="code-tag">&lt;version&gt;</span>1.8.0.7<span
class="code-tag">&lt;/version&gt;</span>
        <span class="code-tag">&lt;/dependency&gt;</span>

    <span class="code-tag">&lt;/dependencies&gt;</span>
</pre>
</div></div>

<p>The tapestry-hibernate library includes, as transitive dependencies, Hibernate and
tapestry-core. This means that you can simply replace "tapestry-core" with "tapestry-hibernate"
inside the &lt;artifactId&gt; element.</p>

<p>Since Hibernate can work with so many different databases, we must explicitly add
in the correct driver.</p>

<p>After changing the POM, you must re-execute the command <tt>mvn eclipse:eclipse
-DdownloadSources=true</tt>. Then, inside Eclipse, right click on the project (in Package
Explorer) and select the "Refresh" menu item. You should also stop Jetty.</p>

<h3><a name="UsingTapestryWithHibernate-HibernateConfiguration"></a>Hibernate
Configuration</h3>

<p>Hibernate has a master configuration file used to store connection and other data.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>src/main/resources/hibernate.cfg.xml</b></div><div
class="codeContent panelContent">
<pre class="code-xml">
&lt;!DOCTYPE hibernate-configuration PUBLIC
        <span class="code-quote">"-//Hibernate/Hibernate Configuration DTD 3.0//EN"</span>
        <span class="code-quote">"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"</span>&gt;
<span class="code-tag">&lt;hibernate-configuration&gt;</span>
    <span class="code-tag">&lt;session-factory&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hibernate.connection.driver_class"</span>&gt;</span>org.hsqldb.jdbcDriver<span
class="code-tag">&lt;/property&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hibernate.connection.url"</span>&gt;</span>jdbc:hsqldb:./target/work/t5_tutorial1;shutdown=true<span
class="code-tag">&lt;/property&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hibernate.dialect"</span>&gt;</span>org.hibernate.dialect.HSQLDialect<span
class="code-tag">&lt;/property&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hibernate.connection.username"</span>&gt;</span>sa<span
class="code-tag">&lt;/property&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hibernate.connection.password"</span>&gt;</span><span
class="code-tag">&lt;/property&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hbm2ddl.auto"</span>&gt;</span>update<span
class="code-tag">&lt;/property&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hibernate.show_sql"</span>&gt;</span>true<span
class="code-tag">&lt;/property&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"hibernate.format_sql"</span>&gt;</span>true<span
class="code-tag">&lt;/property&gt;</span>
    <span class="code-tag">&lt;/session-factory&gt;</span>
<span class="code-tag">&lt;/hibernate-configuration&gt;</span>
</pre>
</div></div>

<p>Most of the configuration is to identify the JDBC driver and connection URL.</p>

<p>Note the connection URL. We are instructing HSQLDB to store its database files within
our project's target directory. We are also instructing HSQLDB to flush any data to these
files at shutdown. This means that data will persist across different invocations of this
project, but if the target directory is destroyed (e.g., via "mvn clean"), then all the database
contents will be lost.</p>

<p>In addition, we are configuring Hibernate to <em>update</em> the database
schema; when Hibernate initializes it will create or even modify tables to match the entities.
Finally, we are configuring Hibernate to output any SQL it executes, which is very useful
when initially building an application.</p>

<p>But what entities? Normally, the available entities are listed inside hibernate.cfg.xml,
but that's not necessary with Tapestry; in another example of convention over configuration,
Tapestry locates all entity classes inside the entities package and adds them to the configuration.
Currently, that is just the Address entity.</p>

<h2><a name="UsingTapestryWithHibernate-AddingHibernateAnnotations"></a>Adding
Hibernate Annotations</h2>

<p>For an entity class to be used with Hibernate, some Hibernate annotations must be
added to the class.</p>

<p>Below is the updated Address class, with the Hibernate annotations (as well as the
Tapestry ones).</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>src/main/java/org/apache/tapestry5/tutorial/entities/Address.java</b></div><div
class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">package</span> com.example.tutorial.entities;

<span class="code-keyword">import</span> javax.persistence.Entity;
<span class="code-keyword">import</span> javax.persistence.GeneratedValue;
<span class="code-keyword">import</span> javax.persistence.GenerationType;
<span class="code-keyword">import</span> javax.persistence.Id;

<span class="code-keyword">import</span> org.apache.tapestry5.beaneditor.NonVisual;
<span class="code-keyword">import</span> org.apache.tapestry5.beaneditor.Validate;

<span class="code-keyword">import</span> com.example.tutorial.data.Honorific;

@Entity
<span class="code-keyword">public</span> class Address
{
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @NonVisual
  <span class="code-keyword">public</span> <span class="code-object">Long</span>
id;

  <span class="code-keyword">public</span> Honorific honorific;

  @Validate(<span class="code-quote">"required"</span>)
  <span class="code-keyword">public</span> <span class="code-object">String</span>
firstName;

  @Validate(<span class="code-quote">"required"</span>)
  <span class="code-keyword">public</span> <span class="code-object">String</span>
lastName;

  <span class="code-keyword">public</span> <span class="code-object">String</span>
street1;

  <span class="code-keyword">public</span> <span class="code-object">String</span>
street2;

  @Validate(<span class="code-quote">"required"</span>)
  <span class="code-keyword">public</span> <span class="code-object">String</span>
city;

  @Validate(<span class="code-quote">"required"</span>)
  <span class="code-keyword">public</span> <span class="code-object">String</span>
state;

  @Validate(<span class="code-quote">"required,regexp"</span>)
  <span class="code-keyword">public</span> <span class="code-object">String</span>
zip;

  <span class="code-keyword">public</span> <span class="code-object">String</span>
email;

  <span class="code-keyword">public</span> <span class="code-object">String</span>
phone;
}
</pre>
</div></div>

<p>The Tapestry annotations, @NonVisual and @Validate, may be placed on the setter or
getter method or on the field (as we have done here). As with the Hibernate annotations, putting
the annotation on the field requires that the field name match the corresponding property
name.</p>

<ul>
	<li><b>@NonVisual</b> &#8211; indicates a field, such as a primary
key, that should not be made visible to the user.</li>
	<li><b>@Validate</b> &#8211; identifies the validations associated
with a field.</li>
</ul>


<h2><a name="UsingTapestryWithHibernate-UpdatingtheDatabase"></a>Updating
the Database</h2>

<p>So we have a database up and running, and Hibernate is configured to connect to it.
Let's make use of that to store our Address object in the database.</p>

<p>What we need is to provide some code to be executed when the form is submitted. When
a Tapestry form is submitted, there is a whole series of events that get fired. The event
we are interested in is the "success" event, which comes late in the process, after all the
values have been pulled out of the request and applied to the page properties, and after all
server-side validations have occured.</p>

<p>The success event is only fired if there are no validation errors.</p>

<p>Our event handler must do two things:</p>

<ul>
	<li>Use the Hibernate Session object to persist the new Address object.</li>
	<li>Commit the transaction to force the data to be written to the database.</li>
</ul>


<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>src/main/java/org/apache/tapestry5/tutorial/pages/address/CreateAddress.java</b></div><div
class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">package</span> org.apache.tapestry5.tutorial.pages.address;

<span class="code-keyword">import</span> org.apache.tapestry5.annotations.InjectPage;
<span class="code-keyword">import</span> org.apache.tapestry5.annotations.Property;
<span class="code-keyword">import</span> org.apache.tapestry5.hibernate.annotations.CommitAfter;
<span class="code-keyword">import</span> org.apache.tapestry5.ioc.annotations.Inject;
<span class="code-keyword">import</span> org.apache.tapestry5.tutorial.entities.Address;
<span class="code-keyword">import</span> org.apache.tapestry5.tutorial.pages.Index;
<span class="code-keyword">import</span> org.hibernate.Session;

<span class="code-keyword">public</span> class CreateAddress
{
    @Property
    <span class="code-keyword">private</span> Address address;

    @Inject
    <span class="code-keyword">private</span> Session session;

    @InjectPage
    <span class="code-keyword">private</span> Index index;

    @CommitAfter
    <span class="code-object">Object</span> onSuccess()
    {
        session.persist(address);

        <span class="code-keyword">return</span> index;
    }
}
</pre>
</div></div>

<p>The <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html"
class="external-link" rel="nofollow">Inject</a> annotation tells Tapestry to inject
a service into the annotated field; Tapestry includes a sophisticated Inversion of Control
container (similar in many ways to Spring) that is very good at locating available services
by type, rather than by a string id. In any case, the Hibernate Session object is exposed
as a Tapestry IoC service, ready to be injected (this is one of the things provided by the
tapestry-hibernate module).</p>

<p>Tapestry automatically starts a transaction as necessary; however that transaction
will be <em>aborted</em> at the end of the request. If we make changes to persistent
objects, such as adding a new Address object, then it is necessary to commit the transaction.</p>

<p>The <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/hibernate/annotations/CommitAfter.html"
class="external-link" rel="nofollow">CommitAfter</a> annotation can be applied to
any component method; if the method completes normally, the transaction will be committed
(and a new transaction started to replace the committed transaction).</p>

<p>After persisting the new address, we return to the main Index page of the application.</p>

<p><em>Note: In real applications, it is rare to have pages and components directly
use the Hibernate Session. It is generally a better approach to define your own Data Access
Object layer to perform common update operations and queries.</em></p>

<h2><a name="UsingTapestryWithHibernate-ShowingAddresses"></a>Showing Addresses</h2>

<p>As a little preview of what's next, let's display all the Addresses entered by the
user on the Index page of the application. After you enter a few names, it will look something
like:</p>

<p><span class="image-wrap" style=""><img src="/confluence/download/attachments/23340507/index-grid-v1.png?version=1&amp;modificationDate=1286829003000"
style="border: 1px solid black" /></span></p>

<h2><a name="UsingTapestryWithHibernate-AddingtheGridtotheIndexpage"></a>Adding
the Grid to the Index page</h2>

<p>So, how is this implemented? Primarily, its accomplished by the <a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Grid.html"
class="external-link" rel="nofollow">Grid</a> component.</p>

<p>The Grid component is based on the same concepts as the BeanEditForm component; it
can pull apart a bean into columns. The columns are sortable, and when there are more entries
than will fit on a single page, page navigation is automatically added.</p>

<p>A minimal Grid is very easy to add to the template:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>src/main/webapp/Index.tml (partial)</b></div><div
class="codeContent panelContent">
<pre class="code-xml">
  <span class="code-tag">&lt;t:grid source=<span class="code-quote">"addresses"</span>/&gt;</span>
</pre>
</div></div>

<p>And all we have to do is supply the addresses property in the Java code:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>src/main/java/org/apache/tapestry5/tutorial/pages/Index.java
(partial)</b></div><div class="codeContent panelContent">
<pre class="code-java">
    @Inject
    <span class="code-keyword">private</span> Session session;

    <span class="code-keyword">public</span> List&lt;Address&gt; getAddresses()
    {
        <span class="code-keyword">return</span> session.createCriteria(Address.class).list();
    }
</pre>
</div></div>

<p>Here, we're using the Hibernate Session object to find all Address objects in the
database. Any sorting that takes place will be done in memory. This is fine for now (with
only a handful of Address objects in the database). Later we'll see how to optimize this for
very large result sets.</p>

<h2><a name="UsingTapestryWithHibernate-What%27sNext%3F"></a>What's Next?</h2>

<p>We have lots more to talk about: more components, more customizations, built-in Ajax
support, more common design and implementation patterns, and even writing your own components
(which is easy!).</p>

<p>More tutorials are planned, but for now check out the other Tapestry resources available
on the <a href="/confluence/display/TAPESTRY/Documentation" title="Documentation">Tapestry
5 Documentation page</a> page.</p>

<style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/TAPESTRY/Using+BeanEditForm+To+Create+User+Forms"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/TAPESTRY/Using+BeanEditForm+To+Create+User+Forms">Using
BeanEditForm To Create User Forms</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/TAPESTRY/Tapestry+Tutorial"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/TAPESTRY/Tapestry+Tutorial">Tapestry Tutorial</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;</td></tr></table></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Using+Tapestry+With+Hibernate">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23340507&revisedVersion=9&originalVersion=8">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message