Friday, 22 January 2016

Struts2, Hibernate pagination example

In this post, I am going to explain about pagination using struts2 and hibernate. If the result set is large, then it is not efficient way to store it in memory; It is always to do lazy loading in these scenarios. For example, you had 10000 records of employees, instead of loading all 10000 records at a time, first load 100 records in first page, if user asks for 2nd page then send him records between 101 and 200, 3rd page send him from 201 to 300 etc.,

Class
Description
Employee.java
Employee model class, mapped to employee table.
EmployeeService.java
Interface declares the methods to work with Employee table.
EmployeeServiceImpl.java
Implements EmployeeService interface.
EmployeeAction.java
Struts action class that receives requests.

org.hibernate.Criteria class provides methods setFirstResult, setMaxResults methods to support pagination.

public Criteria setFirstResult(int firstResult)
Set the first result to be retrieved.

public Criteria setMaxResults(int maxResults)
Set a limit upon the number of objects to be retrieved.

Following step-by-step procedure set up complete working application in eclipse.

Step 1: Create new dynamic web project ‘struts_pagination’ in eclipse.
File -> New Dynamic Web project.

Step 2: Mavenize the project, Right click on the project -> Configure -> Convert To Maven Project.

Step 3: Update pom.xml for gson, struts, hibernate, MySQL dependencies.


pom.xml
<dependencies>
 <dependency>
  <groupId>org.apache.struts</groupId>
  <artifactId>struts2-core</artifactId>
  <version>2.3.20</version>
 </dependency>

 <dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>4.3.11.Final</version>
 </dependency>

 <dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.5</version>
 </dependency>

 <dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.36</version>
 </dependency>

 <dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.16.6</version>
  <scope>provided</scope>
 </dependency>

</dependencies>

Step 4: Create package com.sample.model, Define Employee class.
Employee.java
package com.sample.model;

import javax.persistence.Entity;
import javax.persistence.Id;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity(name="employee")
@ToString
public class Employee {
 @Id
 @Getter @Setter private long id;
 @Getter @Setter private String firstName;
 @Getter @Setter private String lastName;
 @Getter @Setter private String designation;
 @Getter @Setter private int age;
 @Getter @Setter private double salary;
}


Step 5: Define hibernate.cfg.xml file, and configure all the hibernate settings here. Make sure hibernate.cfg.xml file is located in project classpath.

hibernate.cfg.xml

<?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>

  <!-- Database Connection settings -->
  <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
  <property name="connection.url">jdbc:mysql://127.0.0.1/sample</property>
  <property name="connection.username">root</property>
  <property name="connection.password">tiger</property>

  <!-- Enable the logging of all the generated SQL statements to the console -->
  <property name="show_sql">true</property>

  <!-- Format the generated SQL statement to make it more readable, -->
  <property name="format_sql">false</property>

  <!-- Hibernate will put comments inside all generated SQL statements to
  hint what’s the generated SQL trying to do -->
  <property name="use_sql_comments">true</property>

  <!-- This property makes Hibernate generate the appropriate SQL for the
  chosen database. -->
  <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

  <!-- Drop and re-create the database schema on startup -->
  <property name="hbm2ddl.auto">update</property>

  <!-- mappings for annotated classes -->
  <mapping class="com.sample.model.Employee" />

 </session-factory>

</hibernate-configuration>


Since I mapped Employee to table employee, create table employee in the database sample. Following is the schema for employee table.

create table Employee (id integer not null, age integer not null, designation varchar(255), firstName varchar(255), lastName varchar(255), salary double precision not null, primary key (id));

Step 6: create package com.sample.service. Define the interface EmployeeService.java.

EmployeeService.java

package com.sample.service;

import java.util.List;

import com.sample.model.Employee;

public interface EmployeeService {
 public long insertEmployee(Employee emp);

 public long insertEmployees(List<Employee> emps);

 public List<Employee> getEmployees(int pageNum);
}


Step 7: Create package com.sample.service.impl, define the class EmployeeServiceImpl.java.

EmployeeServiceImpl.java

package com.sample.service.impl;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

import com.sample.model.Employee;
import com.sample.service.EmployeeService;

public class EmployeeServiceImpl implements EmployeeService {
 private static SessionFactory sessionFactory = getSessionFactory();

 private static SessionFactory getSessionFactory() {
  if (sessionFactory == null) {
   Configuration configuration = new Configuration().configure();
   StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
     .applySettings(configuration.getProperties());
   sessionFactory = configuration.buildSessionFactory(builder.build());
  }

  return sessionFactory;
 }

 @Override
 public long insertEmployee(Employee emp) {
  Session session = null;
  try {
   session = sessionFactory.openSession();
   session.beginTransaction();
   session.save(emp);
   Transaction trans = session.getTransaction();
   trans.commit();
   return getLastInsertId(session);
  } catch (Exception e) {
   System.out.println(e.getMessage());
  } finally {
   if (session != null)
    session.close();
  }

  return -1;
 }

 @Override
 public long insertEmployees(List<Employee> emps) {
  Session session = null;
  try {
   session = sessionFactory.openSession();
   session.beginTransaction();
   for (Employee emp : emps)
    session.save(emp);
   Transaction trans = session.getTransaction();
   trans.commit();
   return getLastInsertId(session);
  } catch (Exception e) {
   System.out.println(e.getMessage());
  } finally {
   if (session != null)
    session.close();
  }

  return -1;
 }

 private long getLastInsertId(Session session) {
  BigInteger id = (BigInteger) session.createSQLQuery(
    "SELECT LAST_INSERT_ID()").uniqueResult();
  return id.longValue();
 }

 @SuppressWarnings("unchecked")
 @Override
 public List<Employee> getEmployees(int pageNum) {
  Session session = null;
  List<Employee> list = new ArrayList<>();
  try {
   session = sessionFactory.openSession();
   Criteria crit = session.createCriteria(Employee.class
     .getCanonicalName());

   crit.setFirstResult(pageNum * 100 + 1);
   crit.setMaxResults(100);

   list = (List<Employee>) crit.list();
   return list;
  } catch (Exception e) {
   System.out.println(e.getMessage());
  } finally {
   if (session != null)
    session.close();
  }
  return list;
 }

}


Step 8: Create packge com.sample.util. Define class JSONUtil.java.

JSONUtil.java

package com.sample.util;

import com.google.gson.Gson;

public class JSONUtil {
 private static Gson gson = new Gson();

 public static String getJson(Object obj) {
  return gson.toJson(obj);
 }
}


Step 9: Create package com.sample.actions, define the class EmployeeAction.java.

EmployeeAction.java

package com.sample.actions;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import lombok.Getter;
import lombok.Setter;

import com.sample.model.Employee;
import com.sample.service.EmployeeService;
import com.sample.service.impl.EmployeeServiceImpl;
import com.sample.util.JSONUtil;

public class EmployeeAction {
 @Getter
 @Setter
 private int pageNum;
 private InputStream inputStream;

 EmployeeService service = new EmployeeServiceImpl();

 public InputStream getInputStream() {
  return inputStream;
 }

 public String insert1000Employess() throws UnsupportedEncodingException {
  List<Employee> emps = new ArrayList<>();

  for (int i = 0; i < 1000; i++) {
   Employee emp = new Employee();

   emp.setAge(28);
   emp.setDesignation("Engineer");
   emp.setFirstName("PTR" + i);
   emp.setId(i);
   emp.setLastName("nayan" + i);
   emp.setSalary(12345 + i);

   emps.add(emp);
  }

  service.insertEmployees(emps);

  String data = "Employees saved successfully";
  inputStream = new ByteArrayInputStream(data.getBytes("UTF-8"));
  return "success";

 }

 public String getEmployees() throws UnsupportedEncodingException {
  List<Employee> emps = service.getEmployees(pageNum);
  String json = JSONUtil.getJson(emps);
  inputStream = new ByteArrayInputStream(json.getBytes("UTF-8"));
  return "success";
 }
}


Step 10: Update web.xml to transfer all requests to struts.
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
 <display-name>struts_pagination</display-name>
 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 <session-config>
  <session-timeout>1</session-timeout>
 </session-config>
</web-app>


Step 11: It is time to create struts.xml. Since Struts 2 requires struts.xml to be present in classes folder. Create struts.xml file under the WebContent/WEB-INF/classes folder. Eclipse does not create the "classes" folder by default, so you need to do this yourself. To do this, right click on the WEB-INF folder in the project explorer and select New > Folder. Create struts.xml file inside classes.

struts.xml

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
 <package name="default" extends="struts-default">
  <action name="getEmployees" class="com.sample.actions.EmployeeAction" method="getEmployees">
   <result type="stream">
    <param name="contentType">text/html</param>
    <param name="inputName">inputStream</param>
   </result>
  </action>
  <action name="insert1000Employess" class="com.sample.actions.EmployeeAction" method="insert1000Employess">
   <result type="stream">
    <param name="contentType">text/html</param>
    <param name="inputName">inputStream</param>
   </result>
  </action>
 </package>

</struts>


Step 12: Total project structure looks like below.



Run the project in server.

Hit following url, all the 1000 employees are saved to table employee.


Now, hit following url, to get first 100 employee details.

Hit following url, to get employees from 101 to 200.








Previous                                                 Next                                                 Home

No comments:

Post a Comment