user1538526
user1538526

Reputation: 95

Best approach for integrating Struts 2 and hibernate

I was going to integrate hibernate and struts2. Please advise which is the best approach to that, I was thinking that in Struts2, there are no official plugins to integrate the Hibernate framework. But, you can workaround with the following steps:

  1. Register a custom ServletContextListener.
  2. In the ServletContextListener class, initialize the Hibernate session and store it into the servlet context.
  3. In action class, get the Hibernate session from the servlet context, and perform the Hibernate task as normal.

Please advise that my approach of servlet context for initalizing hibernate session facctory is ok or there can be othe best approch also. Here is the snapshot of the project.

Here is the piece of code..

The model class...

package com.mkyong.customer.model;

import java.util.Date;

public class Customer implements java.io.Serializable {

    private Long customerId;
    private String name;
    private String address;
    private Date createdDate;

    //getter and setter methods
}

the hbm mapping file ..

<hibernate-mapping>
    <class name="com.mkyong.customer.model.Customer" 
    table="customer" catalog="mkyong">

        <id name="customerId" type="java.lang.Long">
            <column name="CUSTOMER_ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="string">
            <column name="NAME" length="45" not-null="true" />
        </property>
        <property name="address" type="string">
            <column name="ADDRESS" not-null="true" />
        </property>
        <property name="createdDate" type="timestamp">
            <column name="CREATED_DATE" length="19" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

The configuration file is...

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.bytecode.use_reflection_optimizer">false</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mkyong</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <property name="use_sql_comments">false</property>
    <mapping resource="com/mkyong/customer/hibernate/Customer.hbm.xml" />
  </session-factory>
</hibernate-configuration>

The listener class...

package com.mkyong.listener;

import java.net.URL;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

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

public class HibernateListener implements ServletContextListener{

    private Configuration config;
    private SessionFactory factory;
    private String path = "/hibernate.cfg.xml";
    private static Class clazz = HibernateListener.class;

    public static final String KEY_NAME = clazz.getName();

    public void contextDestroyed(ServletContextEvent event) {
      //
    }

    public void contextInitialized(ServletContextEvent event) {

     try { 
            URL url = HibernateListener.class.getResource(path);
            config = new Configuration().configure(url);
            factory = config.buildSessionFactory();

            //save the Hibernate session factory into serlvet context
            event.getServletContext().setAttribute(KEY_NAME, factory);
      } catch (Exception e) {
             System.out.println(e.getMessage());
       }
    }
}

finally the action class..

ackage com.mkyong.customer.action;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.struts2.ServletActionContext;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.mkyong.customer.model.Customer;
import com.mkyong.listener.HibernateListener;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class CustomerAction extends ActionSupport 
    implements ModelDriven{

    Customer customer = new Customer();
    List<Customer> customerList = new ArrayList<Customer>();

    public String execute() throws Exception {
        return SUCCESS;
    }

    public Object getModel() {
        return customer;
    }

    public List<Customer> getCustomerList() {
        return customerList;
    }

    public void setCustomerList(List<Customer> customerList) {
        this.customerList = customerList;
    }

    //save customer
    public String addCustomer() throws Exception{

        //get hibernate session from the servlet context
        SessionFactory sessionFactory = 
             (SessionFactory) ServletActionContext.getServletContext()
                     .getAttribute(HibernateListener.KEY_NAME);

        Session session = sessionFactory.openSession();

        //save it
        customer.setCreatedDate(new Date());

        session.beginTransaction();
        session.save(customer);
        session.getTransaction().commit();

        //reload the customer list
        customerList = null;
        customerList = session.createQuery("from Customer").list();

        return SUCCESS;

    }

    //list all customers
    public String listCustomer() throws Exception{

        //get hibernate session from the servlet context
        SessionFactory sessionFactory = 
             (SessionFactory) ServletActionContext.getServletContext()
                     .getAttribute(HibernateListener.KEY_NAME);

        Session session = sessionFactory.openSession();

        customerList = session.createQuery("from Customer").list();

        return SUCCESS;

    }   
}

Guys please post the updated code Thanks a lot, I am stuck up on this..!!

Upvotes: 0

Views: 5344

Answers (2)

Steven Benitez
Steven Benitez

Reputation: 11055

You don't want to put a Hibernate Session in the ServletContext. Sessions are not thread-safe and a best practice for Hibernate is to create and destroy a Session (or an EntityManager if you use JPA) for each request.

This can be accomplished using an interceptor. As Umesh indicates, you should favor using a service layer class, such as a DAO, to interact with the session directly, rather than using it from within an action class. This gives you a more defined separation between your model and controller layers.

Upvotes: 1

Umesh Awasthi
Umesh Awasthi

Reputation: 23587

I was confused about reading the title as it was mentioned about Spring and Hibernate but after reading , it came out to be Struts2 and Hibernate.Here are my quick thoughts about your inputs

Struts2 is for web layer as a MVC framework while Hibernate is responsible to deal with DB interaction, though you can always use both and can inject hibernate session in Struts2 action but i will not suggest you this approach. My suggestion is to create a service layer which should be responsible for interacting between your Struts2 action classes and your Hibernate layer, this will help you to fine tune your code and will make it much easier for you to do any code changes or any modification in future.

There is already a plugin in Struts2 which allow you to inject Hibernate session in your action class

  1. full-hibernate-plugin-for-struts2/

But i am still of opinion not to mix hibernate session with Struts2 action and better place a Service layer in between to do this.

Also as you have tagged your question with Spring so i believe you are also using Spring in your application so its better to let Spring handle your interaction with Hibernate, also introducing a service layer will help you to place transaction demarcation efficient and as fine tuned as possible.

Upvotes: 1

Related Questions