Integrate ZK5 with Spring 3 and Hibernate
Vincent Jian, Engineer, Potix Corporation
December 12, 2011
ZK5+, Spring 3, Hibernate 3.6
Introduction
Fernando De Leon introduced how to integrate ZK2.1.1, Spring and Hibernate. Since ZK have great improvement from version 2 to version 5, this document will demonstrate how to integrate ZK 5.0.x, Spring 3.0 and Hibernate 3.6 with a sample project that connect to MySQL database step by step that extend from the origin.
Step 1: MySQL Database Schema
First we create a database in MySQL called support with two tables, company and contact. Here company and contact has one-to-many relationship.
Step 2: Create a Web Application Project
By ZK Studio
- Create a ZK project
- If you have installed ZK Studio plugin in Eclispe, refer here to create a simple ZK project.
- Add Spring 3.0.6 jar files
- Download jar files from SpringSource Community and copy the following jar files into WEB-INF/lib directory.
- Add Spring 3.0.6 jar files
- Download jar files from Hibernate and copy the following jar files into WEB-INF/lib directory.
By Maven
- Create a Maven Project
- If you prefer to using maven, refer here to create a ZK project with maven.
- Modify the pom.xml file to add Spring and Hibernate jar files.
- a) Add version properties and repositories of Spring and Hibernate.
- b) Add dependencies of Spring and Hibernate
<properties>
<zk.version>5.0.9</zk.version>
<org.springframework.version>3.0.6.RELEASE</org.springframework.version>
<hibernate.version>3.6.8.Final</hibernate.version>
</properties>
...
<repository>
<id>repository.springframework.maven.release</id>
<name>Spring Framework Maven Release Repository</name>
<url>http://maven.springframework.org/release</url>
</repository>
<repository>
<id>Hibernate repository</id>
<url>http://repository.jboss.org/nexus/content/groups/public-jboss/</url>
</repository>
<!-- Spring dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<!-- Hibernate dependency -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- MySql dependency start -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
Step 3: Configure Hibernate and Spring
Setup relative configuration files
At the WEB-INF folder of the project we create a Spring configuration file called applicationContext.xml, this file defines the data source (line 9), session factory (line 16) and DAOs (line 29) that are needed to manage Hibernate resources and manage the business objects.
<!-- applicationContext.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/support" />
<property name="user" value="root" />
<property name="password" value="root" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- set other Hibernate properties in hibernate.cfg.xml file -->
<property name="configLocation" value="/WEB-INF/hibernate.cfg.xml" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- for using annotation @Transaction in DAOs -->
<tx:annotation-driven />
<bean id="companyDAO" class="org.zkoss.model.dao.CompanyDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="companyManager" class="org.zkoss.service.CompanyManagerImpl">
<property name="companyDAO" ref="companyDAO" />
</bean>
<bean id="contactDAO" class="org.zkoss.model.dao.ContactDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="contactManager" class="org.zkoss.service.ContactManagerImpl">
<property name="contactDAO" ref="contactDAO" />
</bean>
</beans>
The configurations above manage Hibernate’s connection to MySQL database by dataSource bean and sessionFactory bean. It also manages the injection of DAOs which are needed to perform different operations on the table (e.g., CRUD operations). And other properties needed in hibernate.cfg.xml are as follow:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<mapping resource="Company.hbm.xml" />
<mapping resource="Contact.hbm.xml" />
</session-factory>
</hibernate-configuration>
Notice that Spring is also able to manage the business layer, review the company manager declaration. The company manager is a business object that uses a company DAO for to define different business rules.
For completeness these are the following Hibernate resources. Create two hibernate bean mapping XML files under classpath folder.
Company.hbm.xml describes the Company bean.
<hibernate-mapping package="org.zkoss.model.bean">
<class name="Company" table="company">
<id name="idcompany" column="idcompany" type="integer">
<generator class="increment" />
</id>
<property name="name" column="name" type="string"/>
<property name="country" column="country" type="string"/>
<set name="contacts">
<key column="companyId"/>
<one-to-many class="org.zkoss.model.bean.Contact"/>
</set>
</class>
</hibernate-mapping>
Contact.hbm.xml describes the Contact bean.
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping package="org.zkoss.model.bean">
<class name="Contact" table="contact">
<id name="idcontact" column="idcontact" type="integer">
<generator class="increment" />
</id>
<property name="name" column="name" type="string" />
<property name="email" column="email" type="string" />
<many-to-one name="company" column="companyId" class="org.zkoss.model.bean.Company" outer-join="true" />
</class>
</hibernate-mapping>
Create relative Bean and DAO class
Create Company.java to represent the Company bean in memory.
public class Company implements Serializable {
private Integer idcompany;
private String name;
private String country;
public Company() {}
// getters and setters
}
And Contact.java to represent the Contact bean in memory.
public class Contact implements Serializable {
private Integer idcontact;
private Company company;
private String name;
private String email;
public Contact() {}
// getters and setters
}
The purpose of Spring doesn’t stop just by providing the service for injecting DAOs. In fact Spring provides with a DAO support object (HibernateDaoSupport) which is a base DAO that your DAOs can use. This Spring base DAO provide getHibernateTemplate() API that enables you to perform the simple CRUD operations in a simple manner.
public class CompanyDAO extends HibernateDaoSupport {
public void saveOrUpdate(Company company) throws DataAccessException {
getHibernateTemplate().saveOrUpdate(company);
}
public void delete(Company company) throws DataAccessException {
getHibernateTemplate().delete(company);
}
public Company find(Class<Company> clazz, Integer id) throws DataAccessException {
Company company = (Company) getHibernateTemplate().load(clazz, id);
return company;
}
public List<Company> findAll(Class<Company> clazz) throws DataAccessException {
List<Company> list = getHibernateTemplate().find("from " + clazz.getName());
return list;
}
}
public class ContactDAO extends HibernateDaoSupport {
// similar with CompanyDAO.java
}
The CompanyDAO inherits HibernateDaoSupport which is a DAO support object provided by Spring. It is this HibernateDaoSupport that has a setter called setSessionFactory (SessionFactory sessionFactory). And this is how you are abstracted from the complexity of opening and closing a Hibernate session. Now that we have a DAO which we can do simple CRUD operations on our Company table we need the business object (CompanyManager) that will support our business rules. Note Spring manages the injection of the CompanyManager object also.
In keeping with well define OOP principles we define a Company manager interface.
public interface CompanyManager {
public boolean save(Company company);
public boolean delete(Company company);
public Company getCompany(Integer id);
public List<Company> getCompanyList();
}
public interface ContactManager {
// similar with CompanyManager.java
}
And the implementation:
public class CompanyManagerImpl implements CompanyManager {
private CompanyDAO companyDAO;
public CompanyDAO getCompanyDAO() {
return companyDAO;
}
public void setCompanyDAO(CompanyDAO companyDAO) {
this.companyDAO = companyDAO;
}
@Transactional
public boolean save(Company company) {
try {
companyDAO.saveOrUpdate(company);
return true;
} catch (DataAccessException e) {
return false;
}
}
@Transactional
public boolean delete(Company company) {
try {
companyDAO.delete(company);
return true;
} catch (DataAccessException e) {
return false;
}
}
@Transactional(readOnly = true)
public Company getCompany(Integer id) {
try {
return companyDAO.find(Company.class, id);
} catch (DataAccessException e) {
return null;
}
}
@Transactional(readOnly = true)
public List<Company> getCompanyList() {
try {
return companyDAO.findAll(Company.class);
} catch (DataAccessException e) {
return null;
}
}
}
public class ContactManagerImpl implements ContactManager {
// similar with CompanyManagerImpl.java
}
Here we use @Transactional annotation for save and delete method with default setting (readOnly = false) because the transaction have to change data in database. On the other hand, the prefix get* methods are used for only retrieve data from database, thus the annotation is @Transactional(readOnly=true).
If annotation is not applicable, these setting can also define in applicationContext.xml.
<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
Inspect the applicationContext.xml notice how we are injecting the companyManager and the reason the operations work in getCompanyList() is because the applicationContex injects the companyDAO bean into a setDao() method. All of this is good enough, however so far we had described the Hibernate + Spring configuration. But whatever happened to ZK? ZK should be agnostic to the data layer and it should not know about business rules, it should only use them. We have seen how Spring’s applicationContext.xml file is the central hub for managing the data and business layer resources. However how is the view layer able to communicate to the business layer? For this we use a special object that ZK can call to load up a manager. This becomes the link between the presentation layer and the business layer. We use a ServiceLocator object. ServiceLocator is responsible in loading up the applicationContext.xml file and thus inspect this file and provide a service to locate different managers. Therefore ServiceLocator would use many managers.
public class ServiceLocator {
private ServiceLocator() {}
public static Session getHibernateSession() {
return ((SessionFactory) SpringUtil.getBean("sessionFactory", SessionFactory.class)).getCurrentSession();
}
public static CompanyManager getCompanyManager() {
return (CompanyManager) SpringUtil.getBean("companyManager", CompanyManager.class);
}
public static ContactManager getContactManager() {
return (ContactManager) SpringUtil.getBean("contactManager", ContactManager.class);
}
}
The service locator is to create singleton objects, as the loading up of the applicationContext.xml needs to happen only once! Here we use SpringUtil object provided by ZK that do the job. It is therefore your ZK object that needs to use the ServiceLocator to get manager objects to perform the desire business operations.
Step 4: Implement User Interfaces with ZK
Summary
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |