Sunday, May 23, 2010

Spring, Struts 2 - part 2

Adding database management.

According to previous article, now I am going to show how to manage a database within our previous created web application.
The result is a very simple application, but I hope it will be useful to understand the way to perform similar tasks.

For this purpose, I will use:

* HSQLDB, a data leading SQL relational database engine written in Java, I think I'll write an article about it as soon as possible..It is very interesting and powerful.
* Hibernate, ORM that no needs presentations!
* Spring Framework, especcialy Transaction Manager, I think that it is an underestimated feature of framework.


Our application will retrieve from database some records containing strings that will be printed in a jsp (they will print a classical Hello World message).

First Step: configuring HSQLDB database

Download latest version of hsqldb database, currently is 2.0.0 (rc9). Then I follow instructions from website and report here:

depending on platform you use (Windows or Linux or whatever you prefer) the procedure to be followed is almost the same.

* uncompress the zip folder downloaded from website;
* start HSQLDB server: under installation folder type 'cd data' and then '@java -classpath ../lib/hsqldb.jar org.hsqldb.server.Server %1 %2 %3 %4 %5 %6 %7 %8 %9' (wait for completion of boot process);
* run an SQL client to connect to database server. I use MyEclipse IDE, but anyone can be used, the default connection parameters (if you just downloaded hsqldb package) are: connection URL jdbc:hsqldb:hsql://localhost/ , username SA , password ; for further configuration issues, I suggest to read HSQLDB wiki, it is very helpful and quick.
* Create new table with name HELLO, columns are: ID, PHRASE (ID must be set as numeric primary key, not nullable and incrementable, while PHRASE is a VARCHAR(15));
* Insert new records in that table (follow my same order): ID:1 - PHRASE:'Hello ', ID:2 - PHRASE:'World! ', ID:3 - PHRASE:'This data ', ID:4 - PHRASE:'is stored ', ID:5 - PHRASE:'in database ';


Second Step: configuring Hibernate project

This step is simple for me, making use of MyEclipse and I hope also for you, guessing the procedure to follow is similar.

First of all I create an external (referred in main one) project that will be used as Hibernate's project, from my IDE I click on "Create new Java Project" and once it is created, I right-click on it and then "Add Hibernate Capability". I give it the name: "hibernate-mapping".

Libraries:



Typically, in creation window, the IDE ask to user for innformation about database, here you have to put connection url, username etc etc. Let to create SessionFactory.
Now is time to create mapping between database and POJO. With MyEclipse this thing is very simple:
Just, right-click on table you want to map (in our case is HELLO) -> Hibernate Reverse Engineering ->
In popup window select previously created project's source folder (Hibernate project), select only "Create POJO", select "Java Data Object" -> Finish.

Now you should have something similar to this:




Now we create a new Web Application (it is the same used in previous posted article, with a few of modifies) and import the hibernate project as dependency of this project.
This is our main project.
Main project integrates Struts2 and Spring and for this reason I suggest to read this to full understand the code shown below.
Action code:

package it.nickg.webapp.web.actions;

import it.nickg.webapp.services.HelloService;

import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

public class HelloAction extends ActionSupport {

private HelloService helloService;
private List words;

public List getWords() {
return words;
}

public void setWords(List words) {
this.words = words;
}

public HelloService getHelloService() {
return helloService;
}

public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}

@Override
public String execute() throws Exception {

words = helloService.getWords();
return SUCCESS;
}
}
Business service interface:

package it.nickg.webapp.services;

import java.util.List;

public interface HelloService {

public abstract List getWords();
}


Business service implementation:

package it.nickg.webapp.services.impl;

import it.nickg.hibernate.mapping.Hello;
import it.nickg.webapp.DAO.HelloDAO;
import it.nickg.webapp.services.HelloService;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class HelloServiceImpl implements Serializable, HelloService {

private HelloDAO helloDao;

public void setHelloDao(HelloDAO helloDao) {
this.helloDao = helloDao;
}

public List getWords() {

List

phrases = (List) helloDao.getPhrases(); List words = new ArrayList(); for (Iterator

iterator = phrases.iterator(); iterator.hasNext();) { String word = ((Hello) iterator.next()).getPhrase(); words.add(word); } return words; } }

DAO Interface:
package it.nickg.webapp.DAO;

import java.util.Collection;

import org.hibernate.SessionFactory;

public interface HelloDAO {

public abstract void setSessionFactory(SessionFactory sessionFactory);

public abstract Collection

getPhrases(); }

DAO Implementation:
package it.nickg.webapp.DAO.impl;

import it.nickg.hibernate.mapping.Hello;
import it.nickg.webapp.DAO.HelloDAO;

import java.util.Collection;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class HelloDaoImpl implements HelloDAO {
private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

public Collection

getPhrases() { Collection

phrases; Session session = this.sessionFactory.getCurrentSession(); phrases = session.createCriteria(Hello.class).list(); return phrases; } }

At this point, the essential point of integration, applicationContext.xml file. Adding this lines lets Spring to manage datasource:






Then define Hibernate's SessionFactory, within Spring management:




it/nickg/hibernate/mapping/Hello.hbm.xml




hibernate.dialect=org.hibernate.dialect.HSQLDialect
       


Now, let's define Dependency Injection, briefly: inject SessionFactory into DAO, DAO into Service, Service into Action and applicationContext.xml will look as shown below:













it/nickg/hibernate/mapping/Hello.hbm.xml




hibernate.dialect=org.hibernate.dialect.HSQLDialect
       














BUT, if you try to run application an Hibernate exception will prevent it from working, because Transaction Management misses. There are many choices for Transaction management, I prefer to use the annotation-base approach, which requires to add this lines at applicationContext.xml:




Final applicationContext.xml will be:
>












it/nickg/hibernate/mapping/Hello.hbm.xml




hibernate.dialect=org.hibernate.dialect.HSQLDialect
       


















and to add @Transactional over each (concrete) classes that make use of transaction; in our case these are the services' ones. NOTE: at this point hibernate.cfg.xml can be deleted! Datasource definition and links are defined and handled through Spring configuration file, there is no more need of another external xml file. Add '@Transactional' on top of HelloServiceImpl:
@Transactional
public class HelloServiceImpl implements Serializable, HelloService {

private HelloDAO helloDao;

public void setHelloDao(HelloDAO helloDao) {
this.helloDao = helloDao;
}

public List getWords() {

List

phrases = (List) helloDao.getPhrases(); List words = new ArrayList(); for (Iterator

iterator = phrases.iterator(); iterator.hasNext();) { String word = ((Hello) iterator.next()).getPhrase(); words.add(word); } return words; } }

JSPs, as explained in previous posted article, work in this way: index.jsp redirects to hellopage.action that, in turn, redirects to success.jsp. index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


success.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<%@ taglib prefix="s" uri="/struts-tags"%>


Result shown on web page is this:
I hope this article will be usefule to someone, for me