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
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
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
testand will wire all annotated objects. It will discover and wire any beans with the annotations
@Repository. This will also enable configuration based annotation, which would normally be done with
- MVC is the user interface framework we’ll use, and
mvc:annotation-drivenwires http actions from beans that have
@RequestMappingannotations. In the MVC (Model View Controller) pattern, these beans are the Controllers.
txnamespace allows configuring Spring’s transaction support. The element
tx:annotation-driveninstructs Spring to apply transaction functionality to beans that have
@Transactionalannotations. Spring will inject a transaction manager into the proper beans. By convention, a transaction manager name
transactionManagerwill be injected, but can be configured explicitly by adding
tx:annotation-drivenelement. In this case we’re defining
trasactionManagerfurther down the configuration file.
viewResolverallows 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 the
test.modelpackage for classes annotated with
jpaVendorAdapterproperty takes a class implementing
JpaVendorAdapter. 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.
jpaPropertiesallows 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 the
jpaVendorAdapterin a less verbose way. However, the last parameter cannot be expressed inside
jpaVendorAdapter. The only parameter than can be expressed for
update. By setting
create-dropwe get access to a hibernate specific functionality that allows us to execute a file (called
import.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 name
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.
@Entityannotation 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 to
Person(the class name with the first letter capitalized.
@Idannotation 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
- You can specify the column name (among other properties) using the
@Columnannotation. 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:
@Repositoryannotation is a Spring stereotype, which is similar to
@Component. The only extra functionality it provides is SQL exception translation.
EntityManageris injected thanks to the
@PersistenceContextannotation. 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
The DAO is not called directly, but rather through service layer. Lets look at
@Serviceannotation is another Spring stereotype. However,
@Servicedoes not provide any additional functionality by default. You can later implement special handling based on this annotation.
@Transactionalannotation 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
@Controllerannotation 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
@RequestMappingannotations to actually become accessible.
- The person service is autowired, just like we wired the DAO into the service in the previous file.
@RequestMappingdefines 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
@RequestMappingannotated 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
InternalResourceViewResolverwe defined in
- 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
The last part is the view, which is a regular JSP (Java Server Pages).
This lives in
- 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:
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