Added webapp to tutorial
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@8618 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
57c3f1f4ea
commit
601401ef7d
|
@ -39,10 +39,12 @@
|
||||||
description="Compile documentation for all languages and all formats.">
|
description="Compile documentation for all languages and all formats.">
|
||||||
|
|
||||||
<!-- TRANSLATOR: Duplicate this line for your language -->
|
<!-- TRANSLATOR: Duplicate this line for your language -->
|
||||||
|
<!--
|
||||||
<antcall target="lang.all"><param name="lang" value="en"/></antcall>
|
<antcall target="lang.all"><param name="lang" value="en"/></antcall>
|
||||||
<antcall target="lang.all"><param name="lang" value="zh-cn"/></antcall>
|
<antcall target="lang.all"><param name="lang" value="zh-cn"/></antcall>
|
||||||
<antcall target="lang.all"><param name="lang" value="es"/></antcall>
|
<antcall target="lang.all"><param name="lang" value="es"/></antcall>
|
||||||
<antcall target="lang.all"><param name="lang" value="ko"/></antcall>
|
<antcall target="lang.all"><param name="lang" value="ko"/></antcall>
|
||||||
|
-->
|
||||||
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
|
|
@ -397,7 +397,7 @@ Cat fritz = (Cat) iter.next();]]></programlisting>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="performance-fetching-initialization">
|
<sect2 id="performance-fetching-initialization" revision="1">
|
||||||
<title>Initializing collections and proxies</title>
|
<title>Initializing collections and proxies</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -441,11 +441,8 @@ Cat fritz = (Cat) iter.next();]]></programlisting>
|
||||||
correctness of the exception handling of your application infrastructure.
|
correctness of the exception handling of your application infrastructure.
|
||||||
It is vitally important that the <literal>Session</literal> is closed and the
|
It is vitally important that the <literal>Session</literal> is closed and the
|
||||||
transaction ended before returning to the user, even when an exception occurs
|
transaction ended before returning to the user, even when an exception occurs
|
||||||
during rendering of the view. The servlet filter has to be able to access the
|
during rendering of the view. See the Hibernate Wiki for examples of this
|
||||||
<literal>Session</literal> for this approach. We recommend that a
|
"Open Session in View" pattern.
|
||||||
<literal>ThreadLocal</literal> variable be used to hold the current
|
|
||||||
<literal>Session</literal> (see chapter 1,
|
|
||||||
<xref linkend="quickstart-playingwithcats"/>, for an example implementation).
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
|
|
@ -1,623 +0,0 @@
|
||||||
<chapter id="quickstart">
|
|
||||||
<title>Quickstart with Tomcat</title>
|
|
||||||
|
|
||||||
<sect1 id="quickstart-intro" revision="2">
|
|
||||||
<title>Getting started with Hibernate</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This tutorial explains a setup of Hibernate 3.0 with the Apache Tomcat
|
|
||||||
servlet container (we used version 4.1, the differences to 5.0 should be
|
|
||||||
minimal) for a web-based application. Hibernate works
|
|
||||||
well in a managed environment with all major J2EE application servers, or
|
|
||||||
even in standalone Java applications. The database system used in this
|
|
||||||
tutorial is PostgreSQL 7.4, support for other database is only a matter
|
|
||||||
of changing the Hibernate SQL dialect configuration and connection
|
|
||||||
properties.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
First, we have to copy all required libraries to the Tomcat installation.
|
|
||||||
We use a separate web context (<literal>webapps/quickstart</literal>) for
|
|
||||||
this tutorial, so we've to consider both the global library search path
|
|
||||||
(<literal>TOMCAT/common/lib</literal>) and the classloader at the context level in
|
|
||||||
<literal>webapps/quickstart/WEB-INF/lib</literal> (for JAR files) and
|
|
||||||
<literal>webapps/quickstart/WEB-INF/classes</literal>. We refer to both classloader
|
|
||||||
levels as the global classpath and the context classpath.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Now, copy the libraries to the two classpaths:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<orderedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Copy the JDBC driver for the database to the global classpath. This is
|
|
||||||
required for the DBCP connection pool software which comes bundled with Tomcat.
|
|
||||||
Hibernate uses JDBC connections to execute SQL on the database, so you
|
|
||||||
either have to provide pooled JDBC connections or configure Hibernate to
|
|
||||||
use one of the directly supported pools (C3P0, Proxool). For this tutorial,
|
|
||||||
copy the <literal>pg74jdbc3.jar</literal> library (for PostgreSQL 7.4 and JDK 1.4)
|
|
||||||
to the global classloaders path. If you'd like to use a different database, simply
|
|
||||||
copy its appropriate JDBC driver.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Never copy anything else into the global classloader path in Tomcat, or you
|
|
||||||
will get problems with various tools, including Log4j, commons-logging and
|
|
||||||
others. Always use the context classpath for each web application, that is,
|
|
||||||
copy libraries to <literal>WEB-INF/lib</literal> and your own classes and
|
|
||||||
configuration/property files to <literal>WEB-INF/classes</literal>. Both
|
|
||||||
directories are in the context level classpath by default.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Hibernate is packaged as a JAR library. The <literal>hibernate3.jar</literal>
|
|
||||||
file should be copied in the context classpath together with other classes of
|
|
||||||
the application. Hibernate requires some 3rd party libraries at runtime, these
|
|
||||||
come bundled with the Hibernate distribution in the <literal>lib/</literal>
|
|
||||||
directory; see <xref linkend="3rdpartylibs"/>. Copy the required 3rd party
|
|
||||||
libraries to the context classpath.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</orderedlist>
|
|
||||||
|
|
||||||
<table frame="topbot" id="3rdpartylibs">
|
|
||||||
<title>
|
|
||||||
Hibernate 3rd party libraries
|
|
||||||
</title>
|
|
||||||
<tgroup cols="2" rowsep="1" colsep="1">
|
|
||||||
<colspec colname="c1" colwidth="1*"/>
|
|
||||||
<colspec colname="c2" colwidth="2*"/>
|
|
||||||
<thead>
|
|
||||||
<row>
|
|
||||||
<entry align="center">
|
|
||||||
Library
|
|
||||||
</entry>
|
|
||||||
<entry align="center">
|
|
||||||
Description
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
antlr (required)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
Hibernate uses ANTLR to produce query parsers, this library is
|
|
||||||
also needed at runtime.
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
dom4j (required)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
Hibernate uses dom4j to parse XML configuration and XML mapping
|
|
||||||
metadata files.
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
CGLIB, asm (required)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
Hibernate uses the code generation library to enhance classes
|
|
||||||
at runtime (in combination with Java reflection).
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
Commons Collections, Commons Logging (required)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
Hibernate uses various utility libraries from the Apache Jakarta
|
|
||||||
Commons project.
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
EHCache (required)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
Hibernate can use various cache providers for the second-level
|
|
||||||
cache. EHCache is the default cache provider if not changed in
|
|
||||||
the configuration.
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
Log4j (optional)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
Hibernate uses the Commons Logging API, which in turn can use
|
|
||||||
Log4j as the underlying logging mechanism. If the Log4j library is
|
|
||||||
available in the context library directory, Commons Logging will use
|
|
||||||
Log4j and the <literal>log4j.properties</literal> configuration in the
|
|
||||||
context classpath. An example properties file for Log4j is bundled
|
|
||||||
with the Hibernate distribution. So, copy log4j.jar and the configuration
|
|
||||||
file (from <literal>src/</literal>) to your context classpath if
|
|
||||||
you want to see whats going on behind the scenes.
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
Required or not?
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
Have a look at the file <literal>lib/README.txt</literal> in the
|
|
||||||
Hibernate distribution. This is an up-to-date list of 3rd party
|
|
||||||
libraries distributed with Hibernate. You will find all required
|
|
||||||
and optional libraries listed there (note that "buildtime required"
|
|
||||||
here means for Hibernate's build, not your application).
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
</tbody>
|
|
||||||
</tgroup>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
We now set up the database connection pooling and sharing in both Tomcat and
|
|
||||||
Hibernate. This means Tomcat will provide pooled JDBC connections (using its
|
|
||||||
builtin DBCP pooling feature), Hibernate requests theses connections through
|
|
||||||
JNDI. Alternatively, you can let Hibernate manage the connection pool. Tomcat
|
|
||||||
binds its connection pool to JNDI; we add a resource declaration
|
|
||||||
to Tomcats main configuration file, <literal>TOMCAT/conf/server.xml</literal>:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[<Context path="/quickstart" docBase="quickstart">
|
|
||||||
<Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
|
|
||||||
<ResourceParams name="jdbc/quickstart">
|
|
||||||
<parameter>
|
|
||||||
<name>factory</name>
|
|
||||||
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
|
|
||||||
</parameter>
|
|
||||||
|
|
||||||
<!-- DBCP database connection settings -->
|
|
||||||
<parameter>
|
|
||||||
<name>url</name>
|
|
||||||
<value>jdbc:postgresql://localhost/quickstart</value>
|
|
||||||
</parameter>
|
|
||||||
<parameter>
|
|
||||||
<name>driverClassName</name><value>org.postgresql.Driver</value>
|
|
||||||
</parameter>
|
|
||||||
<parameter>
|
|
||||||
<name>username</name>
|
|
||||||
<value>quickstart</value>
|
|
||||||
</parameter>
|
|
||||||
<parameter>
|
|
||||||
<name>password</name>
|
|
||||||
<value>secret</value>
|
|
||||||
</parameter>
|
|
||||||
|
|
||||||
<!-- DBCP connection pooling options -->
|
|
||||||
<parameter>
|
|
||||||
<name>maxWait</name>
|
|
||||||
<value>3000</value>
|
|
||||||
</parameter>
|
|
||||||
<parameter>
|
|
||||||
<name>maxIdle</name>
|
|
||||||
<value>100</value>
|
|
||||||
</parameter>
|
|
||||||
<parameter>
|
|
||||||
<name>maxActive</name>
|
|
||||||
<value>10</value>
|
|
||||||
</parameter>
|
|
||||||
</ResourceParams>
|
|
||||||
</Context>]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The context we configure in this example is named <literal>quickstart</literal>,
|
|
||||||
its base is the <literal>TOMCAT/webapp/quickstart</literal> directory. To access
|
|
||||||
any servlets, call the path <literal>http://localhost:8080/quickstart</literal>
|
|
||||||
in your browser (of course, adding the name of the servlet as mapped in your
|
|
||||||
<literal>web.xml</literal>). You may also go ahead and create a simple servlet
|
|
||||||
now that has an empty <literal>process()</literal> method.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Tomcat provides connections now through JNDI at
|
|
||||||
<literal>java:comp/env/jdbc/quickstart</literal>. If you have trouble getting the
|
|
||||||
connection pool running, refer to the Tomcat documentation. If you get JDBC driver
|
|
||||||
exception messages, try to setup JDBC connection pool without Hibernate first.
|
|
||||||
Tomcat & JDBC tutorials are available on the Web.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Your next step is to configure Hibernate. Hibernate has to know how it should obtain
|
|
||||||
JDBC connections. We use Hibernate's XML-based configuration. The other approach, using
|
|
||||||
a properties file, is almost equivalent but misses a few features the XML syntax allows.
|
|
||||||
The XML configuration file is placed in the context classpath (<literal>WEB-INF/classes</literal>),
|
|
||||||
as <literal>hibernate.cfg.xml</literal>:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
|
|
||||||
<!DOCTYPE hibernate-configuration PUBLIC
|
|
||||||
"-//Hibernate/Hibernate Configuration DTD//EN"
|
|
||||||
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
|
|
||||||
|
|
||||||
<hibernate-configuration>
|
|
||||||
|
|
||||||
<session-factory>
|
|
||||||
|
|
||||||
<property name="connection.datasource">java:comp/env/jdbc/quickstart</property>
|
|
||||||
<property name="show_sql">false</property>
|
|
||||||
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
|
|
||||||
|
|
||||||
<!-- Mapping files -->
|
|
||||||
<mapping resource="Cat.hbm.xml"/>
|
|
||||||
|
|
||||||
</session-factory>
|
|
||||||
|
|
||||||
</hibernate-configuration>]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
We turn logging of SQL commands off and tell Hibernate what database SQL
|
|
||||||
dialect is used and where to get the JDBC connections (by declaring the JNDI
|
|
||||||
address of the Tomcat bound pool). The dialect is a required setting,
|
|
||||||
databases differ in their interpretation of the SQL "standard". Hibernate will take
|
|
||||||
care of the differences and comes bundled with dialects for all major
|
|
||||||
commercial and open source databases.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
A <literal>SessionFactory</literal> is Hibernate's concept of a single
|
|
||||||
datastore, multiple databases can be used by creating multiple XML
|
|
||||||
configuration files and creating multiple <literal>Configuration</literal>
|
|
||||||
and <literal>SessionFactory</literal> objects in your application.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The last element of the <literal>hibernate.cfg.xml</literal> declares
|
|
||||||
<literal>Cat.hbm.xml</literal> as the name of a Hibernate XML mapping
|
|
||||||
file for the persistent class <literal>Cat</literal>. This file contains
|
|
||||||
the metadata for the mapping of the POJO class <literal>Cat</literal> to
|
|
||||||
a datbase table (or tables). We'll come back to that file soon. Let's write
|
|
||||||
the POJO class first and then declare the mapping metadata for it.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="quickstart-persistentclass" revision="1">
|
|
||||||
<title>First persistent class</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Hibernate works best with the Plain Old Java Objects (POJOs, sometimes
|
|
||||||
called Plain Ordinary Java Objects) programming model for persistent classes.
|
|
||||||
A POJO is much like a JavaBean, with properties of the class accessible via getter
|
|
||||||
and setter methods, shielding the internal representation from the publicly
|
|
||||||
visible interface (Hibernate can also access fields directly, if needed):
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[package org.hibernate.examples.quickstart;
|
|
||||||
|
|
||||||
public class Cat {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String name;
|
|
||||||
private char sex;
|
|
||||||
private float weight;
|
|
||||||
|
|
||||||
public Cat() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public char getSex() {
|
|
||||||
return sex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSex(char sex) {
|
|
||||||
this.sex = sex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getWeight() {
|
|
||||||
return weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWeight(float weight) {
|
|
||||||
this.weight = weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
}]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Hibernate is not restricted in its usage of property types, all Java JDK
|
|
||||||
types and primitives (like <literal>String</literal>, <literal>char</literal>
|
|
||||||
and <literal>Date</literal>) can be mapped, including classes from the Java
|
|
||||||
collections framework. You can map them as values, collections of values, or
|
|
||||||
associations to other entities. The <literal>id</literal> is a special property
|
|
||||||
that represents the database identifer (primary key) of that class, it is
|
|
||||||
highly recommended for entities like a <literal>Cat</literal>. Hibernate can
|
|
||||||
use identifiers only internally, but we would lose some of the flexibility in our
|
|
||||||
application architecture.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
No special interface has to be implemented for persistent classes nor do you have
|
|
||||||
to subclass from a special root persistent class. Hibernate also doesn't require
|
|
||||||
any build time processing, such as byte-code manipulation, it relies solely on
|
|
||||||
Java reflection and runtime class enhancement (through CGLIB). So, without any
|
|
||||||
dependency of the POJO class on Hibernate, we can map it to a database table.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="quickstart-mapping" revision="2">
|
|
||||||
<title>Mapping the cat</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The <literal>Cat.hbm.xml</literal> mapping file contains the metadata
|
|
||||||
required for the object/relational mapping. The metadata includes declaration
|
|
||||||
of persistent classes and the mapping of properties (to columns and
|
|
||||||
foreign key relationships to other entities) to database tables.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[<?xml version="1.0"?>
|
|
||||||
<!DOCTYPE hibernate-mapping PUBLIC
|
|
||||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
|
||||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
|
||||||
|
|
||||||
<hibernate-mapping>
|
|
||||||
|
|
||||||
<class name="org.hibernate.examples.quickstart.Cat" table="CAT">
|
|
||||||
|
|
||||||
<!-- A 32 hex character is our surrogate key. It's automatically
|
|
||||||
generated by Hibernate with the UUID pattern. -->
|
|
||||||
<id name="id" type="string" unsaved-value="null" >
|
|
||||||
<column name="CAT_ID" sql-type="char(32)" not-null="true"/>
|
|
||||||
<generator class="uuid"/>
|
|
||||||
</id>
|
|
||||||
|
|
||||||
<!-- A cat has to have a name, but it shouldn' be too long. -->
|
|
||||||
<property name="name">
|
|
||||||
<column name="NAME" length="16" not-null="true"/>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="sex"/>
|
|
||||||
|
|
||||||
<property name="weight"/>
|
|
||||||
|
|
||||||
</class>
|
|
||||||
|
|
||||||
</hibernate-mapping>]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Every persistent class should have an identifer attribute (actually, only
|
|
||||||
classes representing entities, not dependent value-typed classes, which
|
|
||||||
are mapped as components of an entity). This property is used to distinguish
|
|
||||||
persistent objects: Two cats are equal if
|
|
||||||
<literal>catA.getId().equals(catB.getId())</literal> is true, this concept is
|
|
||||||
called <emphasis>database identity</emphasis>. Hibernate comes bundled with
|
|
||||||
various identifer generators for different scenarios (including native generators
|
|
||||||
for database sequences, hi/lo identifier tables, and application assigned
|
|
||||||
identifiers). We use the UUID generator (only recommended for testing, as integer
|
|
||||||
surrogate keys generated by the database should be prefered) and also specify the
|
|
||||||
column <literal>CAT_ID</literal> of the table <literal>CAT</literal> for the
|
|
||||||
Hibernate generated identifier value (as a primary key of the table).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
All other properties of <literal>Cat</literal> are mapped to the same table. In
|
|
||||||
the case of the <literal>name</literal> property, we mapped it with an explicit
|
|
||||||
database column declaration. This is especially useful when the database
|
|
||||||
schema is automatically generated (as SQL DDL statements) from the mapping
|
|
||||||
declaration with Hibernate's <emphasis>SchemaExport</emphasis> tool. All other
|
|
||||||
properties are mapped using Hibernate's default settings, which is what you
|
|
||||||
need most of the time. The table <literal>CAT</literal> in the database looks
|
|
||||||
like this:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[ Column | Type | Modifiers
|
|
||||||
--------+-----------------------+-----------
|
|
||||||
cat_id | character(32) | not null
|
|
||||||
name | character varying(16) | not null
|
|
||||||
sex | character(1) |
|
|
||||||
weight | real |
|
|
||||||
Indexes: cat_pkey primary key btree (cat_id)]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
You should now create this table in your database manually, and later read
|
|
||||||
<xref linkend="toolsetguide"/> if you want to automate this step with the
|
|
||||||
<literal>hbm2ddl</literal> tool. This tool can create a full SQL DDL, including
|
|
||||||
table definition, custom column type constraints, unique constraints and indexes.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="quickstart-playingwithcats" revision="3">
|
|
||||||
<title>Playing with cats</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
We're now ready to start Hibernate's <literal>Session</literal>. It is the
|
|
||||||
<emphasis>persistence manager</emphasis>, we use it to store and retrieve
|
|
||||||
<literal>Cat</literal>s to and from the database. But first, we've to get a
|
|
||||||
<literal>Session</literal> (Hibernate's unit-of-work) from the
|
|
||||||
<literal>SessionFactory</literal>:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[SessionFactory sessionFactory =
|
|
||||||
new Configuration().configure().buildSessionFactory();]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The call to <literal>configure()</literal> loads the <literal>hibernate.cfg.xml</literal>
|
|
||||||
configuration file and initializes the <literal>Configuration</literal> instance.
|
|
||||||
You can set other properties (and even change the mapping metadata) by
|
|
||||||
accessing the <literal>Configuration</literal> <emphasis>before</emphasis>
|
|
||||||
you build the <literal>SessionFactory</literal> (it is immutable). Where
|
|
||||||
do we create the <literal>SessionFactory</literal> and how can we access
|
|
||||||
it in our application?
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
A <literal>SessionFactory</literal> is usually only build once,
|
|
||||||
e.g. at startup with a <emphasis>load-on-startup</emphasis> servlet.
|
|
||||||
This also means you should not keep it in an instance variable in your
|
|
||||||
servlets, but in some other location. Furthermore, we need some kind of
|
|
||||||
<emphasis>Singleton</emphasis>, so we can access the
|
|
||||||
<literal>SessionFactory</literal> easily in application code. The approach
|
|
||||||
shown next solves both problems: startup configuration and easy access to a
|
|
||||||
<literal>SessionFactory</literal>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
We implement a <literal>HibernateUtil</literal> helper class:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[import org.hibernate.*;
|
|
||||||
import org.hibernate.cfg.*;
|
|
||||||
|
|
||||||
public class HibernateUtil {
|
|
||||||
|
|
||||||
private static Log log = LogFactory.getLog(HibernateUtil.class);
|
|
||||||
|
|
||||||
private static final SessionFactory sessionFactory;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
// Create the SessionFactory
|
|
||||||
sessionFactory = new Configuration().configure().buildSessionFactory();
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
// Make sure you log the exception, as it might be swallowed
|
|
||||||
log.error("Initial SessionFactory creation failed.", ex);
|
|
||||||
throw new ExceptionInInitializerError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final ThreadLocal session = new ThreadLocal();
|
|
||||||
|
|
||||||
public static Session getCurrentSession() {
|
|
||||||
Session s = (Session) session.get();
|
|
||||||
// Open a new Session, if this Thread has none yet
|
|
||||||
if (s == null) {
|
|
||||||
s = sessionFactory.openSession();
|
|
||||||
session.set(s);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void closeSession() {
|
|
||||||
Session s = (Session) session.get();
|
|
||||||
if (s != null)
|
|
||||||
s.close();
|
|
||||||
session.set(null);
|
|
||||||
}
|
|
||||||
}]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
This class does not only take care of the <literal>SessionFactory</literal>
|
|
||||||
with its static initializer, but also has a <literal>ThreadLocal</literal>
|
|
||||||
variable which holds the <literal>Session</literal> for the current thread.
|
|
||||||
Make sure you understand the Java concept of a thread-local variable before you
|
|
||||||
try to use this helper. A more complex and powerful <literal>HibernateUtil</literal>
|
|
||||||
class can be found in <literal>CaveatEmptor</literal>, http://caveatemptor.hibernate.org/
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
A <literal>SessionFactory</literal> is threadsafe, many threads can access
|
|
||||||
it concurrently and request <literal>Session</literal>s. A <literal>Session</literal>
|
|
||||||
is a non-threadsafe object that represents a single unit-of-work with the database.
|
|
||||||
<literal>Session</literal>s are opened from a <literal>SessionFactory</literal> and
|
|
||||||
are closed when all work is completed. An example in your servlet's
|
|
||||||
<literal>process()</literal> method might look like this (sans exception handling):
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[Session session = HibernateUtil.getCurrentSession();
|
|
||||||
Transaction tx = session.beginTransaction();
|
|
||||||
|
|
||||||
Cat princess = new Cat();
|
|
||||||
princess.setName("Princess");
|
|
||||||
princess.setSex('F');
|
|
||||||
princess.setWeight(7.4f);
|
|
||||||
|
|
||||||
session.save(princess);
|
|
||||||
|
|
||||||
tx.commit();
|
|
||||||
HibernateUtil.closeSession();]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
In a <literal>Session</literal>, every database operation occurs inside a
|
|
||||||
transaction that isolates the database operations (even read-only operations).
|
|
||||||
We use Hibernates <literal>Transaction</literal> API to abstract from the underlying
|
|
||||||
transaction strategy (in our case, JDBC transactions). This allows our code
|
|
||||||
to be deployed with container-managed transactions (using JTA) without any changes.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Note that you may call <literal>HibernateUtil.getCurrentSession();</literal>
|
|
||||||
as many times as you like, you will always get the current <literal>Session</literal>
|
|
||||||
of this thread. You have to make sure the <literal>Session</literal> is closed
|
|
||||||
after your unit-of-work completes, either in your servlet code or in a servlet filter
|
|
||||||
before the HTTP response is send. The nice side effect of the second option is easy
|
|
||||||
lazy initialization: the <literal>Session</literal> is still open when the view is
|
|
||||||
rendered, so Hibernate can load unitialized objects while you navigate the current
|
|
||||||
object graph.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Hibernate has various methods that can be used to retrieve objects from the
|
|
||||||
database. The most flexible way is using the Hibernate Query Language (HQL),
|
|
||||||
which is an easy to learn and powerful object-oriented extension to SQL:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<programlisting><![CDATA[Transaction tx = session.beginTransaction();
|
|
||||||
|
|
||||||
Query query = session.createQuery("select c from Cat as c where c.sex = :sex");
|
|
||||||
query.setCharacter("sex", 'F');
|
|
||||||
for (Iterator it = query.iterate(); it.hasNext();) {
|
|
||||||
Cat cat = (Cat) it.next();
|
|
||||||
out.println("Female Cat: " + cat.getName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.commit();]]></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Hibernate also offers an object-oriented <emphasis>query by criteria</emphasis> API
|
|
||||||
that can be used to formulate type-safe queries. Hibernate of course uses
|
|
||||||
<literal>PreparedStatement</literal>s and parameter binding for all SQL communication
|
|
||||||
with the database. You may also use Hibernate's direct SQL query feature or
|
|
||||||
get a plain JDBC connection from a <literal>Session</literal> in rare cases.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="quickstart-summary" revision="1">
|
|
||||||
<title>Finally</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
We only scratched the surface of Hibernate in this small tutorial. Please note that
|
|
||||||
we don't include any servlet specific code in our examples. You have to create a
|
|
||||||
servlet yourself and insert the Hibernate code as you see fit.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Keep in mind that Hibernate, as a data access layer, is tightly integrated into
|
|
||||||
your application. Usually, all other layers depent on the persistence mechanism.
|
|
||||||
Make sure you understand the implications of this design.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
For a more complex application example, see http://caveatemptor.hibernate.org/ and
|
|
||||||
have a look at other tutorials linked on http://www.hibernate.org/Documentation
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
</chapter>
|
|
|
@ -1234,20 +1234,286 @@ public void removeFromEvent(Event event) {
|
||||||
need one side as <literal>inverse</literal>. In a one-to-many association it has to be the many-side,
|
need one side as <literal>inverse</literal>. In a one-to-many association it has to be the many-side,
|
||||||
in many-to-many association you can pick either side, there is no difference.
|
in many-to-many association you can pick either side, there is no difference.
|
||||||
</para>
|
</para>
|
||||||
<!--
|
|
||||||
<para>
|
|
||||||
In the next section we integrate Hibernate with Tomcat and WebWork - the <literal>EventManager</literal>
|
|
||||||
doesn't scale anymore with our growing application.
|
|
||||||
</para>
|
|
||||||
-->
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Let's turn this into a small web application.
|
||||||
|
</para>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="tutorial-summary">
|
<sect1 id="tutorial-webapp">
|
||||||
|
<title>Part 3 - The EventManager web application</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A Hibernate web application uses <literal>Session</literal> and <literal>Transaction</literal>
|
||||||
|
almost like a standalone application. However, some common patterns are useful. We now write
|
||||||
|
an <literal>EventManagerServlet</literal>. This servlet can list all events stored in the
|
||||||
|
database, and it provides an HTML form to enter new events.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2 id="tutorial-webapp-servlet">
|
||||||
|
<title>Writing the basic servlet</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Create a new class in your source directory, in the <literal>events</literal>
|
||||||
|
package:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[package events;
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
|
||||||
|
public class EventManagerServlet extends HttpServlet {
|
||||||
|
|
||||||
|
private final SimpleDateFormat dateFormatter =
|
||||||
|
new SimpleDateFormat("dd.MM.yyyy");
|
||||||
|
|
||||||
|
// Servlet code
|
||||||
|
}]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <literal>dateFormatter</literal> is a tool we'll need later to convert
|
||||||
|
<literal>Date</literal> objects from and to strings. It makes sense to only
|
||||||
|
have one formatter as a member of the servlet.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The servlet handles HTTP <literal>GET</literal> requests only, hence, the method
|
||||||
|
we implement is <literal>doGet()</literal>:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[protected void doGet(HttpServletRequest request,
|
||||||
|
HttpServletResponse response)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Begin unit of work
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().beginTransaction();
|
||||||
|
|
||||||
|
// Process request and render page...
|
||||||
|
|
||||||
|
// End unit of work
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().getTransaction().commit();
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().getTransaction().rollback();
|
||||||
|
throw new ServletException(ex);
|
||||||
|
}}]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The pattern we are applying here is called <emphasis>session-per-request</emphasis>.
|
||||||
|
When a request hits the servlet, a new Hibernate <literal>Session</literal> is
|
||||||
|
opened through the first call to <literal>getCurrentSession()</literal> on the
|
||||||
|
<literal>SessionFactory</literal>. Then a database transaction is started—all
|
||||||
|
data access as to occur inside a transaction, no matter if data is read or written
|
||||||
|
(we don't use the auto-commit mode in applications).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Next, the possible actions of the request are processed and the response HTML
|
||||||
|
is rendered. We'll get to that part soon.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Finally, the unit of work ends when processing and rendering is complete. If any
|
||||||
|
problem occured during processing or rendering, an exception will be thrown
|
||||||
|
and the database transaction rolled back. This completes the
|
||||||
|
<literal>session-per-request</literal> pattern. Instead of the transaction
|
||||||
|
demarcation code in every servlet you could also write a servlet filter.
|
||||||
|
See the Hibernate website and Wiki for more information about this pattern,
|
||||||
|
called <emphasis>Open Session in View</emphasis>—you'll need it as soon
|
||||||
|
as you consider rendering your view in JSP, not in a servlet.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="tutorial-webapp-processing">
|
||||||
|
<title>Processing and rendering</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Let's implement the processing of the request and rendering of the page.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[// Write HTML header
|
||||||
|
PrintWriter out = response.getWriter();
|
||||||
|
out.println("<html><head><title>Event Manager</title></head><body>");
|
||||||
|
|
||||||
|
// Handle actions
|
||||||
|
if ( "store".equals(request.getParameter("action")) ) {
|
||||||
|
|
||||||
|
String eventTitle = request.getParameter("eventTitle");
|
||||||
|
String eventDate = request.getParameter("eventDate");
|
||||||
|
|
||||||
|
if ( "".equals(eventTitle) || "".equals(eventDate) ) {
|
||||||
|
out.println("<b><i>Please enter event title and date.</i></b>");
|
||||||
|
} else {
|
||||||
|
createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
|
||||||
|
out.println("<b><i>Added event.</i></b>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print page
|
||||||
|
printEventForm(out);
|
||||||
|
listEvents(out);
|
||||||
|
|
||||||
|
// Write HTML footer
|
||||||
|
out.println("</body></html>");
|
||||||
|
out.flush();
|
||||||
|
out.close();]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Granted, this coding style with a mix of Java and HTMl would not scale
|
||||||
|
in a bigger application—keep in mind that we are only illustrating
|
||||||
|
basic Hibernate concepts in this tutorial. The code prints an HTML
|
||||||
|
header and a footer. Inside this page, an HTML form for event entry and
|
||||||
|
a list of all events in the database are printed. The first method is
|
||||||
|
trivial and only outputs HTML:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[private void printEventForm(PrintWriter out) {
|
||||||
|
out.println("<h2>Add new event:</h2>");
|
||||||
|
out.println("<form>");
|
||||||
|
out.println("Title: <input name='eventTitle' length='50'/><br/>");
|
||||||
|
out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
|
||||||
|
out.println("<input type='submit' name='action' value='store'/>");
|
||||||
|
out.println("</form>");
|
||||||
|
}]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <literal>listEvents()</literal> method uses the Hibernate
|
||||||
|
<literal>Session</literal> bound to the current thread to execute
|
||||||
|
a query:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[private void listEvents(PrintWriter out) {
|
||||||
|
List result = HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().createCriteria(Event.class).list();
|
||||||
|
if (result.size() > 0) {
|
||||||
|
out.println("<h2>Events in database:</h2>");
|
||||||
|
out.println("<table border='1'>");
|
||||||
|
out.println("<tr>");
|
||||||
|
out.println("<th>Event title</th>");
|
||||||
|
out.println("<th>Event date</th>");
|
||||||
|
out.println("</tr>");
|
||||||
|
for (Iterator it = result.iterator(); it.hasNext();) {
|
||||||
|
Event event = (Event) it.next();
|
||||||
|
out.println("<tr>");
|
||||||
|
out.println("<td>" + event.getTitle() + "</td>");
|
||||||
|
out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
|
||||||
|
out.println("</tr>");
|
||||||
|
}
|
||||||
|
out.println("</table>");
|
||||||
|
}
|
||||||
|
}]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Finally, the <literal>store</literal> action is dispatched to the
|
||||||
|
<literal>createAndStoreEvent()</literal> method, which also uses
|
||||||
|
the <literal>Session</literal> of the current thread:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[protected void createAndStoreEvent(String title, Date theDate) {
|
||||||
|
Event theEvent = new Event();
|
||||||
|
theEvent.setTitle(title);
|
||||||
|
theEvent.setDate(theDate);
|
||||||
|
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().save(theEvent);
|
||||||
|
}]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
That's it, the servlet is complete. A request to the servlet will be processed
|
||||||
|
in a single <literal>Session</literal> and <literal>Transaction</literal>. As
|
||||||
|
earlier in the standalone application, Hibernate can automatically bind these
|
||||||
|
ojects to the current thread of execution. This gives you the freedom to layer
|
||||||
|
your code and access the <literal>SessionFactory</literal> in any way you like.
|
||||||
|
Usually you'd use a more sophisticated design and move the data access code
|
||||||
|
into data access objects (the DAO pattern). See the Hibernate Wiki for more
|
||||||
|
examples.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="tutorial-webapp-deploy">
|
||||||
|
<title>Deploying and testing</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To deploy this application you have to create a web archive, a WAR. Add the
|
||||||
|
following Ant target to your <literal>build.xml</literal>:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[<target name="war" depends="compile">
|
||||||
|
<war destfile="hibernate-tutorial.war" webxml="web.xml">
|
||||||
|
<lib dir="${librarydir}">
|
||||||
|
<exclude name="jsdk*.jar"/>
|
||||||
|
</lib>
|
||||||
|
|
||||||
|
<classes dir="${targetdir}"/>
|
||||||
|
</war>
|
||||||
|
</target>]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This target creates a file called <literal>hibernate-tutorial.war</literal>
|
||||||
|
in your project directory. It packages all libraries and the <literal>web.xml</literal>
|
||||||
|
descriptor, which is expected in the base directory of your project:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app version="2.4"
|
||||||
|
xmlns="http://java.sun.com/xml/ns/j2ee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>Event Manager</servlet-name>
|
||||||
|
<servlet-class>events.EventManagerServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>Event Manager</servlet-name>
|
||||||
|
<url-pattern>/eventmanager</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
</web-app>]]></programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Before you compile and deploy the web application, note that an additional library
|
||||||
|
is required: <literal>jsdk.jar</literal>. This is the Java servlet development kit,
|
||||||
|
if you don't have this library already, get it from the Sun website and copy it to
|
||||||
|
your library directory. However, it will be only used for compliation and excluded
|
||||||
|
from the WAR package.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To build and deploy call <literal>ant war</literal> in your project directory
|
||||||
|
and copy the <literal>hibernate-tutorial.war</literal> file into your Tomcat
|
||||||
|
<literal>webapp</literal> directory. If you don't have Tomcat installed, download
|
||||||
|
it and follow the installation instructions. You don't have to change any Tomcat
|
||||||
|
configuration to deploy this application though.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Once deployed and Tomcat is running, access the application at
|
||||||
|
<literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>. Make
|
||||||
|
sure you watch the Tomcat log to see Hibernate initialize when the first
|
||||||
|
request hits your servlet (the static initializer in <literal>HibernateUtil</literal>
|
||||||
|
is called) and to get the detailed output if any exceptions occurs.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="tutorial-summary" revision="1">
|
||||||
<title>Summary</title>
|
<title>Summary</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This tutorial covered the basics of writing a simple standalone Hibernate application.
|
This tutorial covered the basics of writing a simple standalone Hibernate application
|
||||||
|
and a small web application.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -36,4 +36,14 @@
|
||||||
</java>
|
</java>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<target name="war" depends="compile">
|
||||||
|
<war destfile="hibernate-tutorial.war" webxml="web.xml">
|
||||||
|
<lib dir="${librarydir}">
|
||||||
|
<exclude name="jsdk*.jar"/>
|
||||||
|
</lib>
|
||||||
|
|
||||||
|
<classes dir="${targetdir}"/>
|
||||||
|
</war>
|
||||||
|
</target>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -1,3 +1,7 @@
|
||||||
Put all required Hibernate libraries here to run the tutorial.
|
Put all required Hibernate libraries here to run the tutorial.
|
||||||
See lib/README.txt in the Hibernate distribution and the tutorial
|
See lib/README.txt in the Hibernate distribution and the tutorial
|
||||||
chapter in the reference documentation.
|
chapter in the reference documentation.
|
||||||
|
|
||||||
|
You might need other third-party libraries to compile the full
|
||||||
|
tutorial source code. For example, you will need jsdk.jar if you
|
||||||
|
want to compile the servlets of the example web application.
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
package events;
|
||||||
|
|
||||||
|
import util.HibernateUtil;
|
||||||
|
|
||||||
|
import javax.servlet.http.*;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
public class EventManagerServlet extends HttpServlet {
|
||||||
|
|
||||||
|
private final SimpleDateFormat dateFormatter =
|
||||||
|
new SimpleDateFormat("dd.MM.yyyy");
|
||||||
|
|
||||||
|
protected void doGet(HttpServletRequest request,
|
||||||
|
HttpServletResponse response)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Begin unit of work
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().beginTransaction();
|
||||||
|
|
||||||
|
// Write HTML header
|
||||||
|
PrintWriter out = response.getWriter();
|
||||||
|
out.println("<html><head><title>Event Manager</title></head><body>");
|
||||||
|
|
||||||
|
// Handle actions
|
||||||
|
if ( "store".equals(request.getParameter("action")) ) {
|
||||||
|
|
||||||
|
String eventTitle = request.getParameter("eventTitle");
|
||||||
|
String eventDate = request.getParameter("eventDate");
|
||||||
|
|
||||||
|
if ( "".equals(eventTitle) || "".equals(eventDate) ) {
|
||||||
|
out.println("<b><i>Please enter event title and date.</i></b>");
|
||||||
|
} else {
|
||||||
|
createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
|
||||||
|
out.println("<b><i>Added event.</i></b>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print page
|
||||||
|
printEventForm(out);
|
||||||
|
listEvents(out);
|
||||||
|
|
||||||
|
// Write HTML footer
|
||||||
|
out.println("</body></html>");
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
// End unit of work
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().getTransaction().commit();
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().getTransaction().rollback();
|
||||||
|
throw new ServletException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printEventForm(PrintWriter out) {
|
||||||
|
out.println("<h2>Add new event:</h2>");
|
||||||
|
out.println("<form>");
|
||||||
|
out.println("Title: <input name='eventTitle' length='50'/><br/>");
|
||||||
|
out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
|
||||||
|
out.println("<input type='submit' name='action' value='store'/>");
|
||||||
|
out.println("</form>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void listEvents(PrintWriter out) {
|
||||||
|
List result = HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().createCriteria(Event.class).list();
|
||||||
|
if (result.size() > 0) {
|
||||||
|
out.println("<h2>Events in database:</h2>");
|
||||||
|
out.println("<table border='1'>");
|
||||||
|
out.println("<tr>");
|
||||||
|
out.println("<th>Event title</th>");
|
||||||
|
out.println("<th>Event date</th>");
|
||||||
|
out.println("</tr>");
|
||||||
|
for (Iterator it = result.iterator(); it.hasNext();) {
|
||||||
|
Event event = (Event) it.next();
|
||||||
|
out.println("<tr>");
|
||||||
|
out.println("<td>" + event.getTitle() + "</td>");
|
||||||
|
out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
|
||||||
|
out.println("</tr>");
|
||||||
|
}
|
||||||
|
out.println("</table>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createAndStoreEvent(String title, Date theDate) {
|
||||||
|
Event theEvent = new Event();
|
||||||
|
theEvent.setTitle(title);
|
||||||
|
theEvent.setDate(theDate);
|
||||||
|
|
||||||
|
HibernateUtil.getSessionFactory()
|
||||||
|
.getCurrentSession().save(theEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app version="2.4"
|
||||||
|
xmlns="http://java.sun.com/xml/ns/j2ee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>Event Manager</servlet-name>
|
||||||
|
<servlet-class>events.EventManagerServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>Event Manager</servlet-name>
|
||||||
|
<url-pattern>/eventmanager</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
</web-app>
|
Loading…
Reference in New Issue