Welcome to Srini's blog

Thursday, September 9, 2010

Integrating hibernate to java web application

This post is continuation to my last post "Sample web application using struts framework". In this post we will see how to integrate hibernate to our sample web application .

Application : My application is simple login page with server side validation and verify the login details from DB and render success/failure page. I used Mysql as DB.

Step 1 : Setup in Eclipse:
=================
Please create the setup as specified in previous post and add the following additional things.
1. Additional sub folder structure
A. Create src dir structure
i. Login/src/com/srini/model
ii. Login/src/com/srini/model/hbm
iii. Login/src/com/srini/hibernate
iv. Login/src/com/srini/db

2. Addtional Files needs to be create
i. hibernate.cfg.xml [Login/src/com/srini/webapp/WEB-INF/classes]
ii. Login.java [Login/src/com/srini/model]
iii. Login.hbm.xml [Login/src/com/srini/model/hbm]
iv. HibernateSessionFactory.java [Login/src/com/srini/hibernate]
v. mysql_users.sql [Login/src/com/srini/db].
vi. mysql_dbscript.sql [Login/src/com/srini/db]
vii. LoginAction [Login/src/com/srini/action] -- This class is modified

3. Additional Dependency jars :
i. asm.jar
ii. cglib-2.1.jar
iii. dom4j-1.6.jar
iv. ehcache-1.1.jar
v. hibernate3.jar
vi. jaxen-1.1-beta-4.jar
vii. jta.jar
viii. mysql-connector-java-3.1.12-bin.jar

4. Modify 'server.xml' file : This is to specify your DB details and add docBase so that when you hit the url http://localhost:8080, it will automatically run your web application. Add the Context tag to server.xml file in tomcat conf dir. Add the following code with in Host tag . Modify the context path to your server path.

The configuration looks like

<Context path="" docBase="C:/Program Files/Apache Software Foundation/Tomcat 5.5/webapps/login" privileged="true" antiResourceLocking="false" antiJARLocking="false"> <Resource name="jdbc/struts" auth="Container" type="javax.sql.DataSource" maxActive="100" minIdle="10" maxIdle="30" maxWait="10000" username="struts" password="struts" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1/struts?useUnicode=true&characterEncoding=utf8&autoReconnect=true" logAbandoned="true" validationQuery="SELECT 1" removeAbandoned="true" testOnBorrow="true" testWhileIdle="true" timeBetweenEvictionRunsMillis="10000" minEvictableIdleTimeMillis="180000" removeAbandonedTimeout="60" /> </Context>

5. Modify 'login-build.xml' file : Modify ant build script slightly to add hibernate related changes.
i. Add new target 'copy.hbm.files '.
<target name="copy.hbm.files" >
<copy todir="${build}/${name}/WEB-INF/classes/com/srini/model/hbm">
<fileset dir="${login.src.root}/src/com/srini/model/hbm">
<include name="*.xml"/>
</fileset>
</copy>
</target>

ii. Add new target to dependents list in compile target.
<target name="compile" depends="init, copy.login.webapp, copy.hbm.files" >
iii. Add additional jars to classpath.

Step 2 : Each file description and code inside the file :
============================================
1. hibernate.cfg.xml : Hibernate uses the hibernate.cfg.xml to create the connection pool and setup required environment. Hibernate uses the Plain Old Java Objects (POJOs) classes to map to the database table. We can configure the variables to map to the database column.

The configuration looks like

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1/struts?useUnicode=true&characterEncoding=utf8&autoReconnect=true</property>
<property name="hibernate.connection.username">struts</property>
<property name="connection.password">struts</property>
<property name="connection.pool_size">1</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping resource="com/srini/model/hbm/Login.hbm.xml"/>
</session-factory>
</hibernate-configuration>


I think you are already knew the first 6 properties. If 'show_sql' property is 'true' then it will write all SQL statements to console. <mapping resource="com/srini/model/hbm/Login.hbm.xml"/> property is the mapping for our login_details table.

2. Login.java : This is model class to map table.
package com.srini.model;

/**
* @author srinut096@gmail.com
*
*/
public class Login {

private int id;
private String name;
private String password;

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

3. Login.hbm.xml : This file is used to map Login Object to the login_details table in the database.

The configuration looks like

<?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 package="com.srini.model">
<class name="Login" table="login_details">
<id name="id" unsaved-value="0">
<generator class="native"/>
</id>
<property name="name" type="string" column="name"/>
<property name="password" type="string" column="password"/>
</class>
</hibernate-mapping>


The hibernate-mapping element is the root element. The class element is used to map the Java class with the database table. The Java class name is specified using the name attribute of the class element and the database table name is specified using the table attribute of the class element. The id element is used to create the primary key. The name attribute of the id element refers to the property in the Login class and the column attribute refers to the column in the login_details table. The type attribute holds the hibernate mapping type, this mapping types will convert from Java to SQL data type and vice versa. The generator element within the id element is used to automatically generate the primary key values. When the class attribute of the generator element is set to native, hibernate picks either identity, sequence or hilo algorithm depending upon the capabilities of the underlying database. The property element is used to link a property in the Java class to a column in the database table.

4. HibernateSessionFactory.java : This class helps in creating the SessionFactory from the Hibernate configuration file(it automatically pick up the hibernate.cfg.xml file from WEB-INF dir of web application).

package com.srini.hibernate;

import java.util.logging.Logger;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
* @author srinut096@gmail.com
*
*/
public class HibernateSessionFactory {
private static final SessionFactory sessionFactory;
private static Logger log = Logger.getLogger(HibernateSessionFactory.class.getName());

static {
try {
sessionFactory = new Configuration().configure()
.buildSessionFactory();
} catch (Throwable ex) {
log.severe("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}


The SessionFactory is threadsafe, so it is not necessary to obtain one for each thread. Here the static singleton pattern is used to instantiate the SessionFactory.

5. mysql_users.sql : script to create user, db in mysql.
DROP DATABASE IF EXISTS struts;
DELETE FROM mysql.user WHERE User='struts';
FLUSH PRIVILEGES;
CREATE DATABASE IF NOT EXISTS struts CHARACTER SET utf8;
GRANT ALL PRIVILEGES ON msp.* to `struts`@`127.0.0.1` IDENTIFIED BY 'struts' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON struts.* to `struts`@`localhost` IDENTIFIED BY 'struts' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON struts.* to `struts`@`%` IDENTIFIED BY 'struts' WITH GRANT OPTION;
use struts;


6. mysql_dbscript.sql : script to create db schema.
USE struts;
--
-- Table structure for table login_details
--

DROP TABLE IF EXISTS login_details;
CREATE TABLE login_details (
id bigint(20) NOT NULL auto_increment,
name varchar(255) NOT NULL,
password varchar(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY login_key (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO login_details VALUES (1,'srini','pass123');


7. LoginAction.java : This class is modified slightly to add logic to get data from DB and compare form values with DB values and forward respective pages.
package com.srini.action;

import java.util.List;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.srini.form.LoginForm;
import com.srini.hibernate.HibernateSessionFactory;
import com.srini.model.Login;

/**
*
* @author srinut096@gmail.com
*/
public class LoginAction extends Action {

/* forward name="success" path="" */
private final static String SUCCESS = "success";
private final static String FAILURE = "failure";
private static Logger log = Logger.getLogger(LoginAction.class.getName());
/**
* This is the action called from the Struts framework.
* @param mapping The ActionMapping used to select this instance.
* @param form The optional ActionForm bean for this request.
* @param request The HTTP Request we are processing.
* @param response The HTTP Response we are processing.
* @throws java.lang.Exception
* @return
*/
@SuppressWarnings("unchecked")
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
LoginForm loginForm = (LoginForm) form;
log.severe("Username in Action: " + loginForm.getUserName());

Session session = HibernateSessionFactory.getSessionFactory().openSession();
Transaction transaction = null;
Login loginDetails = null;
ActionForward forward = null;
try {
transaction = session.beginTransaction();
Query query = session.createQuery("from Login where name = ?");
//if (values != null) {
//for (int i = 0; i < logins =" query.list();" logins ="=" logindetails =" (Login)logins.get(0);" logindetails ="=" forward =" mapping.findForward(FAILURE);" forward =" mapping.findForward(SUCCESS);" forward =" mapping.findForward(FAILURE);">


The first call to the HibernateSessionFactory.getSessionFactory().openSession() method begins the session. The session.beginTransaction() method is used to start a new transaction. The session.createQuery() method is used to create a query object which helps in retrieving the persistant objects. Here we use Hibernate Query Language (HQL). "from Login where name=?" returns a the login details matched to name in the login_details table. Note that in the HQL we only specify the java class names and not the table names. Later, using the for loop we iterate the list of login details.

Now run the application in any standard browser

1. Start Tomcat
2. http://localhost:8080
3. Enter the name and password and click login button. It will check the name in DB and returns success/failure page.

2 comments:

  1. Hi Srini,
    Great article! Is it possible to share the binary file of your application(.ear/.war). I followed every step but unfortunately my project does not work. I just want to check and compare the application hierarchy and structure. The problem in my application is in the project, db part is OK and works fine.
    Thx in advance.

    ReplyDelete
  2. Thx for ur comment. First try to build without hibernate(http://tsrini.blogspot.com/2010/09/sample-web-application-using-struts.html). If u r able to build sample application and facing prob with integrating hibernate then let me know. I will help u.

    ReplyDelete