Click here to Skip to main content
15,075,944 members
Articles / Programming Languages / Java / Java8
Article
Posted 18 Jul 2016

Stats

12.5K views
3 bookmarked

JTable Spring Hibernate Demo

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
19 Jul 2016CPOL4 min read
Spring Hibernate Integration along with JTable widget.

Contents

  • Introduction
  • Hibernate Configuration
  • Defining an Interceptor
  • Need for Interceptor
  • Using Interceptor
  • Creating Hibernate Factory
  • Destroying Hibernate Factory
  • Model
  • Controller
  • Database actions using Hibernate
  • Querying database using Hibernate

Introduction

This article is same as the JTable Spring Demo (http://www.codeproject.com/Articles/1112115/JTable-Spring-Demo-with-database-integration). In this demo, Hibernate is used instead of Spring JdbcTemplate for database access.

Hibernate Configuration

Hibernate requires a set of properties to be defined in order to be configured. The configuration is done in hibernate.cfg.xml as follows:

XML
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
       <property name="hibernate.dialect">
            org.hibernate.dialect.HSQLDialect
        </property>
        <property name="hibernate.connection.driver_class">
            org.hsqldb.jdbcDriver
        </property>
        <property name="hibernate.connection.url"> 
   jdbc:hsqldb:file:C:\DB\StudentDB;shutdown=true;hsqldb.default_table_type=cached;sql.enforce_strict_size=false
        </property>
        <property name="hibernate.connection.username">
            sa
        </property>
        <property name="hibernate.connection.password">
        </property>
    </session-factory>
</hibernate-configuration>

Refer http://www.tutorialspoint.com/hibernate/hibernate_configuration.htm for more details.

Defining an Interceptor                          

Spring Interceptor is used to intercept requests and do some processing as desired then hand it over to the Controller for fulfilling the request. In order to do so, an object of SpringRequestInterceptor was created and added to the registry. Interceptor is defined in SpringConfiguration.java as follows:

Java
@Import({SpringSecurityConfig.class})
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"controller"})

public class SpringConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        SpringRequestInterceptor interceptor = new SpringRequestInterceptor();
        registry.addInterceptor(interceptor);
    }
}

Need for Interceptor

Spring provides HttpServletRequest, HttpServletResponse, HttpSession and ServletContext objects. These objects are required to create Hibernate session. However, in order to use these objects, they need to be passed to a method and then used as per Spring requirement. Since the code has various methods that require these objects, to avoid passing them as parameters successively, the interceptor is used. Before any HTTP request is processed, the interceptor is called which in turn calls the desired method to store the objects and close the session as required.

Using Interceptor

An interceptor can be created by overriding methods of the abstract HandlerInterceptorAdapter or by writing HandlerInterceptor interface. The abstract class provides the basic implementation of the HandlerInterceptor interface. Here two methods (preHandle() and postHandle()) of HandlerInterceptorAdapter are overridden. 

When the interceptor is called, SpringRequestInterceptor.java checks if the handler is pointing to BaseController. If it is, then preHandle() and postHandle() methods on the BaseController are called before and after processing any request respectively. 

Java
public class SpringRequestInterceptor extends HandlerInterceptorAdapter {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Object bean = handlerMethod.getBean();
            if (bean instanceof BaseController) {
                BaseController controller = (BaseController) bean;
               return controller.preHandle(request, response, handler);
            }
        }
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Object bean = handlerMethod.getBean();
            if (bean instanceof BaseController) {
                BaseController controller = (BaseController) bean;
                controller.postHandle(request, response, handler, modelAndView);
            }
        }
    }

For any HTTP request, before it is processed the preHandle() method of the interceptor defined in BaseController is called. The HttpServletRequest, HttpServletResponse, HttpSession and ServletContext objects are passed to it and stored to be used later. postHandle() method is called for closing the Hibernate session after processing the request.

Java
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // Store request, response, httpSession and httpContext. Will be useful later.
    this.request = request;
    this.response = response;
    httpSession = request.getSession(true);
    httpContext = request.getServletContext();
    session = null;
    return true;
}
// Closing the hibernate session after processing the request.
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    try {
        session.close();
        session = null;
        request = null;
        response = null;
        httpSession = null;
        httpContext = null;
    } 
catch (Exception ignore) {
    }
}

Creating Hibernate Factory

The code snippet below shows how to create Factory. The Factory is time-consuming and heavy to create, creating it for every request is not suggested since it makes the application slow. The Factory is created once and stored in the application and used as required.

In order to create Factory only once, SessionFactory attribute is set after the Factory is created for the first time and stored in ServletContext. Then every other time, SessionFactory attribute is checked. If it exists then we use the already existing one else new Factory is created.

.addAnnotatedClasses is use to map classes to databases. 

getFactory() of BaseController.java

Java
public static SessionFactory getFactory(ServletContext httpContext) {
    SessionFactory factory = (SessionFactory) httpContext.getAttribute("SessionFactory");
    if (factory != null) return factory;
    StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder();
    registryBuilder.configure();
    StandardServiceRegistry registry = registryBuilder.build();

    MetadataSources metadataSources = new MetadataSources(registry);   
    metadataSources.addAnnotatedClass(City.class);
    metadataSources.addAnnotatedClass(Course.class);
    metadataSources.addAnnotatedClass(Student.class);
    metadataSources.addAnnotatedClass(StudentPhone.class);
    metadataSources.addAnnotatedClass(StudentResult.class);
    metadataSources.addAnnotatedClass(User.class);

    Metadata metadata = metadataSources.buildMetadata();
    factory = metadata.buildSessionFactory();
    httpContext.setAttribute("SessionFactory", factory);
    return factory;
}

Destroying Hibernate Factory

The Factory needs to be destroyed when the application is closed. ServletContext is the common area of the application.  The Factory is stored in ServletContext. When the context is destroyed then the factory is also destroyed if it exists. Attribute “SessionFactory” is also removed. Annotation @WebListener makes a class ServletContextListener (contextInitialized and contextDestroyed methods gets called).

contextDestroyed() of SpringContextListener.java

Java
@Override

public void contextDestroyed(ServletContextEvent event) {
    ServletContext httpContext = event.getServletContext();
    SessionFactory factory = (SessionFactory) httpContext.getAttribute("SessionFactory");
    if (factory != null) {
        factory.close();
        httpContext.removeAttribute("SessionFactory");
    }
}

Model

Student.java is created to be mapped to Student table. @Entity and @Table annotation are used to indicate the creation of table “student”. @Id, @GeneratedValue, and @Column annotation are used to indicate self-generating primary key for a primary key column. The code snippet shows only a few fields. Refer Student.java in the source code for the actual code. 

Student.java

Java
@Entity
@Table(name = "student")

public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    public int id;
    
    @NotNull
    @Size(min = 2, max = 30)
    public String name;

    @NotNull
    @Email
    public String email;

    @NotNull
    public String password;
}

Similarly, tables are created for

  • City with fields id, name.
  • StudentResults with fields id, student_id, course_name, exam_date,degree.
  • StudentPhone with fields id, student_id, phone_type, phone_number, record_date.
  • Course with fields id, name.

Getter and setter methods were added to all the classes. jTable allows master/child tables (http://jtable.org/Demo/MasterChild). StudentPhone and StudentResults are defined for child tables.

Controller

Each controller has three actions defined: List, Save, Delete.

StudentController.java

List()

Java
@ResponseBody
@RequestMapping(value = "List")

public JTableResult List(JTableRequest jTableRequest) {
    JTableResult rslt = new JTableResult();
    try {
        createSession();
        return Student.retrievePage(session, jTableRequest);
    } catch (Throwable ex) {
        rslt.Result = "Error";
        rslt.Message = exceptionToString(ex);
        return rslt;
    }
}

RetrievePage method will return records based on the paging and sorting parameters. 

Save()

Java
@ResponseBody
@RequestMapping(value = "Save")

public JTableResult Save(@Valid Student student, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) return toError(bindingResult);
    int action = Integer.parseInt(request.getParameter("action"));
    if (student.active_flg == null) student.active_flg = "N";
    if (action == 1) {
        student.record_date = new Date();
        return insert(student);
    } else {
        createSession();
        student.record_date = Student.getRecordDateById(session, student.id);
        return update(student);
    }
}

The getrecorddatebyid() method gets the original record_date for the record that is being updated. Save method calls the insert or the update method of BaseController.java based on the parameter value of action passed.

Delete()

Java
@ResponseBody
@RequestMapping(value = "Delete")

public JTableResult Delete(int id) {
    Student student = new Student();
    student.id = id;
    return delete(student);
}

Delete method of BaseController.java is called.

Database actions using Hibernate

For every database action, a session is created. Once the transaction begins, the desired action is taken ( Ex. save, update or delete) then the action is committed.  Once the request is processed, the postHandle method closes the session.

BaseController.java

Inserting a record in the database using Hibernate.

Java
public JTableResult insert(Object obj) {
    JTableResult rslt = new JTableResult();
    try {
        //Hibernate session is created for database access.
        createSession();
        session.getTransaction().begin();
        session.save(obj);
        session.getTransaction().commit();
        rslt.Result = "OK";
        rslt.Record = obj;
        return rslt;
    } catch (Throwable ex) {
        rslt.Result = "Error";
        rslt.Message = exceptionToString(ex);
        return rslt;
    }

Updating and deleting record in database using Hibernate can done similarly by using .update(obj) and .delete(obj). 

Querying database using Hibernate

In order to get total no. of records for each table, a query was executed.

retrievePage() of Student.java gets the total no. of records as follows:

Java
rslt.TotalRecordCount = ((BigInteger) session.createNativeQuery("Select count(*) From student").getSingleResult()).intValue()

.createNativeQuery allows querying the database. The obtained result can be stored according to what is given in “Select” part of the query and no. of records that will be returned.

Source Code

Code is available at:  https://github.com/pujagani/JTableSpringHibernateDemo

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Puja Jagani
India India
No Biography provided

Comments and Discussions

 
QuestionFormat Pin
Nelek19-Jul-16 1:29
protectorNelek19-Jul-16 1:29 
AnswerRe: Format Pin
Puja Jagani20-Jul-16 19:46
MemberPuja Jagani20-Jul-16 19:46 
GeneralRe: Format Pin
Nelek20-Jul-16 21:16
protectorNelek20-Jul-16 21:16 
Thanks, now it looks better
M.D.V. Wink | ;)

If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.