Simple Spring and JPA with Hibernate tutorial. Part 1: The basics
This is a very basic Spring application, using MVC for the web interface and JPA for persistence. As the JPA implementation we will use Hibernate. However, it is fairly easy to switch to another JPA implementation such as EclipseLink (we will look at how to do this in a later post). In as much as possible, this example uses convention over configuration, favoring brevity over exhaustive listing of options.
This example requires Maven to be installed and functional. I’m using version 3.0.4, but any relatively new version should suffice.
We’ll start taking a look at the pom.xml
:
See below for detailed explanation of this file
- We define the Spring version as a property, since we’ll reuse this property for several dependencies. You could do the same thing for the other libraries we’re importing, but after a point, it becomes overkill. As of the writing of this tutorial, the latest stable Spring 3 is 3.2.4.RELEASE.
- The spring-beans package includes the basics to configure spring, and will be required in basically all spring applications.
- The spring-webmvc package provides front end functionality, which we’ll use to create our UI.
- The spring-orm package provides the infrastructure to map Object Relational Mapping (ORM) tools into Spring. Nowadays most new work is done using JPA (Java Persistence Architecture) interfaces. This module provides the glue logic between the ORMimplementation and your application, exposing standard JPA interfaces, while still allowing to take advantage of specialized features provided by the ORM framework of your choosing.
- The hibernate-entitymanager provides the Hibernate implementation, to do our database work behind the scenes.
- The JSTL api will provide us with some standard tools to make writing our JSPs a bit easier.
- In this simple example will use an embedded database, H2. This database will run within the Java process, so we can do our work without the need to have an external database server. ORM implementations allow you to move between a small embedded database an a big “enterprise” level database without big changes to your code.
- A database connection pool improves performance by keeping a pool of open connections that clients can use. In most J2EE applications the database connection pool is managed by the application server (Tomcat, Weblogic, JBoss, Glassfish, etc… ). For this example we’ll provide our own connection pool.
Now let’s look at src/main/webapp/WEB-INF/web.xml
:
The web.xml
is simple enough, with a single Servlet,
provided by Spring, and a single mapping, which will send requests ending in html
to the Spring MVC servlet. Loading of the DispatcherServlet
will trigger Spring to look for a configuration file named spring-servlet.xml
. This is based on the servlet name and the -servlet.xml
postfix. There are other ways of configuring Spring, but for now the spring-servlet.xml
file will suffice:
- Component scan from the context namespace will crawl through the source tree starting at package
test
and will wire all annotated objects. It will discover and wire any beans with the annotations@Controller
,@Service
,@Component
, and@Repository
. This will also enable configuration based annotation, which would normally be done with<context:annotation-config/>
. - MVC is the user interface framework we’ll use, and
mvc:annotation-driven
wires http actions from beans that have@RequestMapping
annotations. In the MVC (Model View Controller) pattern, these beans are the Controllers. - The
tx
namespace allows configuring Spring’s transaction support. The elementtx:annotation-driven
instructs Spring to apply transaction functionality to beans that have@Transactional
annotations. Spring will inject a transaction manager into the proper beans. By convention, a transaction manager nametransactionManager
will be injected, but can be configured explicitly by addingtransaction-manager="nameOfMyTransactionManagerBean"
to thetx:annotation-driven
element. In this case we’re definingtrasactionManager
further down the configuration file. - The
viewResolver
allows Spring MVC to locate the JSPs that represent the View in the MVC pattern. In this case we’ll keep the JSPs in the/WEB-INF/jsp/
directory, so that they cannot be hit directly, but accessed only through the controllers. - In this example, we’re providing the data source (instead of finding a data source provided by an application server). The properties passed must include at least the driver corresponding to the database to use, and a url. Since we are using an embedded database, nothing else is required, but most other databases will also require a username and password to be passed in as well.
- The entity manager factory provides access to the JPA implementation. In this case we’re using the adapter that allows using Hibernate. The factory requires several attributes to be passed in. In particular a
dataSource
(in this case referencing the one created in point #5) and and package to scan for JPA entity classes. In this case we’re scanning thetest.model
package for classes annotated with@Entity
. - The
jpaVendorAdapter
property takes a class implementingJpaVendorAdapter
. In this case we provide the one appropriate for hibernate. Inside this property we further configure the adapter, however the syntax is more limited than what can be done passing properties directly as we do here in the next element. - The
jpaProperties
allows to pass raw properties to the JPA implementation, bypassing the Spring ORM adapter. In this case we pass parameter so that Hibernate will show us the SQL it’s executing, the type of database we’ll be connecting to, and finally instruct hibernate to recreate the schema every time the EntityManager is started. In this case, the first two parameters could have been expressed inside thejpaVendorAdapter
in a less verbose way. However, the last parameter cannot be expressed insidejpaVendorAdapter
. The only parameter than can be expressed forhibernate.hbm2ddl.auto
inside thejpaVendorAdapter
isupdate
. By settinghibernate.hbm2ddl.auto
tocreate-drop
we get access to a hibernate specific functionality that allows us to execute a file (calledimport.sql
) after the database structure has been created. You can find more information here. - The transaction manager we are using is appropriate to the JPA infrastructure we’re using. By default this bean will be injected with an entity manager factory bean called
entityManagerFactory
. This can be overridden by passing a property with nameentityManagerFactory
.
Looking at the import.sql
file mentioned before will give us an idea of how the database looks, but we’ll into more detail how it looks when we examine the entity class:
Now let’s look at the actual code, starting with the Person
entity class. An application will most likely have more than one entity class, but for this example we’ll make do with only one. If you need more, just add them to one of the packages that will be scanned.
- The
@Entity
annotation specifies that the class is an entity. At the class level, other annotations can be applied, for example@Table
, to specify a table. Otherwise defaults will apply. In this case the table name defaults toPerson
(the class name with the first letter capitalized. - The
@Id
annotation specifies that this field is the primary key of the table.
A few notes when declaring entity classes:
- By default, all fields are persisted, even if not annotated. If you want to exclude a filed, add the
@Transient
annotation. - You can specify the column name (among other properties) using the
@Column
annotation. If you omit this annotation, the default column name will be used (field name with capitalized first letter). - Annotations can be placed on the fields, or on the getters. Placing them on the getters will signal the JPA implementations to use JavaBean property access instead of field access. It is however recommended to not mix both in a single entity class.
Now we’ll look at the DAO (Data Access Object) inside src/main/java/test/dao/impl/PersonDAO.java
. At this point it’s fairly simple, and just implements a single method from an interface:
- The
@Repository
annotation is a Spring stereotype, which is similar to@Component
. The only extra functionality it provides is SQL exception translation. - The
EntityManager
is injected thanks to the@PersistenceContext
annotation. This is the interface that we use to interact with the JPA system. - Our lonely method uses JPQL (Java Persistence Query Language) to query and return a list of all Persons. This is executed through the
EntityManager
.
The DAO is not called directly, but rather through service layer. Lets look at src/main/java/test/service/impl/PersonService.java
:
- The
@Service
annotation is another Spring stereotype. However,@Service
does not provide any additional functionality by default. You can later implement special handling based on this annotation. - The
@Transactional
annotation specifies that method calls on this class. You can specify several parameters, but by default it will require transactions, reusing a current one or starting a new one. This is good enough for a lot of usages, but can be tweaked if needed. - The DAO is injected with
@Autowired
. Where possible we use interfaces. - The actual call to the DAO is fairly simple. However, it’s worth noting that if we called more than one method in the DAO, both calls will be run inside the same transaction.
The web controller provides an “action” that users can invoke through their web browsers. Lets look at src/main/java/test/controllers/TestController.java
:
- The
@Controller
annotation is yet another specialization of@Component
, used to specify that the class is a web controller. However, this needs to go together with one or more@RequestMapping
annotations to actually become accessible. - The person service is autowired, just like we wired the DAO into the service in the previous file.
- The
@RequestMapping
defines what url this controller will respond to. In this case we’re mapping to/view.html
. The html extension comes from the mapping in the web.xml. Further diferenciation can be done based on other elements of the request, such a method, agent, etc. This annotation can be applied to a method, or to a type AND method. If applied to a type, method level annotation are also required, and the paths declared on the method annotation will be appended to path defined in the type annotation. - The ModelAndView is one of the many return types that
@RequestMapping
annotated methods can return, and is one of the most useful ones. It allows us to define the view, and well as the model (data) that will be rendered by the view. In this case the constructor takes a view name. This view name will be resolved to/WEB-INF/jsp/view.jsp
by theInternalResourceViewResolver
we defined inspring.xml
. - The last step is to populate the model data, in this case a list of all persons fetched by our person service. This list will be available in the view under the attribute name
persons
.
The last part is the view, which is a regular JSP (Java Server Pages).
This lives in src/main/webapp/WEB-INF/jsp/view.jsp
:
- We declare the core tag library. This provides basic control functionality, and is part of the Java Server Pages Standard Tag Library.
- The core tag library allows an easy way to iterate over lists. In this case we iterate over the “persons” object we returned from the controller method inside the ModelAndView object.
- For each person we iterate over, we print the first and last name.
We can then compile and run our small application with:
mvn tomcat:run
You can see the product of our work at http://localhost:8080/spring-hib-jpa/view.html:
This is a very basic example, but we’ve explored all of the plumbing required to build a database backed web application. In future posts we’ll build on top of this application, and add feature such as, data entry, security, webservices, etc. Source Code
You can clone the code and play with it from github:
git clone https://github.com/aolarte/tutorials.git
The finished code is contained in directory spring1_basics
.
Simple Spring and JPA with Hibernate tutorial series:
- Part 1: The basics
- Part 2: Forms and persisting entities
- Part 3: Simple security
Comments