In all previous Hibernate tutorials, we were using 'DriverManagerDataSource' provided by Spring to connect to database. However this approach is not very convenient for obvious reasons like database schema password needs to be configured in application itself which is visible to everyone who has access to application deployable file. Also if password changes, application needs to be redeployed.
So other approach which is recommended and widely used is to use 'DataSource' which is configured on web container/application server and connect to that database using JNDI name of datasource.
We will use tomcat to configure datasource and then using Spring MVC application integrated with Hibernate to connect to that datasource to fetch records.
Below will be final project structure once finished.
Add this element inside the root element in a context.xml file. This file is located inside $CATALINA_BASE/conf directory: this is the preferred place because the JNDI DataSource will be available to all web applications and it’s independent of any applications.
Once done, configure this datasource in Spring bean configuration file like below,
Note, there are two ways in which we can configure this. I have commented out the second way. Difference in these way is with property 'resourceRef'. This property set whether the look up occurs in a J2EE container, i.e. if the prefix "java:comp/env/" needs to be added if the JNDI name doesn't already contain it. If configured as bean shown in first way then default value is 'false'. So we need to set that property to 'true'. However if datasource is configured using jee:jndi-lookup then default value is 'true' so need to set explicitly to true. After this, this datasource is passed to SessionFactory bean to create and configure SessionFactory object.
mvc-context.xml
So other approach which is recommended and widely used is to use 'DataSource' which is configured on web container/application server and connect to that database using JNDI name of datasource.
We will use tomcat to configure datasource and then using Spring MVC application integrated with Hibernate to connect to that datasource to fetch records.
Below will be final project structure once finished.
Let's first configure datasource in tomcat.
1 2 3 4 5 6 7 8 9 10 11 12 | <Resource name="jdbc/rmsystem" auth="Container" type="javax.sql.DataSource" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/rmsystem" username="postgres" password="password" maxTotal="10" maxIdle="4" minIdle="2" maxWaitMillis="10000" validationQuery="SELECT 1"/> |
Add this element inside the root element
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <?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" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <context:property-placeholder location="classpath:hibernate.properties"/> <bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="jdbc/rmsystem"></property> <property name="resourceRef" value="true"></property> </bean> <!-- <jee:jndi-lookup id="myDataSource" jndi-name="jdbc/rmsystem" expected-type="javax.sql.DataSource" /> --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="packagesToScan" value="in.blogspot.ashish4java.employeesystem.model"></property> <property name="dataSource" ref="myDataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> <prop key="current_session_context_class">${hibernate.current_session_context_class}</prop> <prop key="cache.provider_class">${hibernate.cache.provider_class}</prop> <prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop> <prop key="hibernate.autocommit">${hibernate.autocommit}</prop> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> </props> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans> |
Note, there are two ways in which we can configure this. I have commented out the second way. Difference in these way is with property 'resourceRef'. This property set whether the look up occurs in a J2EE container, i.e. if the prefix "java:comp/env/" needs to be added if the JNDI name doesn't already contain it. If configured as bean shown in first way then default value is 'false'. So we need to set that property to 'true'. However if datasource is configured using jee:jndi-lookup then default value is 'true' so need to set explicitly to true. After this, this datasource is passed to SessionFactory bean to create and configure SessionFactory object.
mvc-context.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <mvc:annotation-driven /> <context:component-scan base-package="in.blogspot.ashish4java.employeesystem" /> <tx:annotation-driven /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> </beans> |
EmployeeDao.java
1 2 3 4 5 6 7 8 9 10 11 | package in.blogspot.ashish4java.employeesystem.dao; import java.util.List; import in.blogspot.ashish4java.employeesystem.model.Employee; public interface EmployeeDao { List<Employee> findAllEmployees(); } |
EmployeeDaoImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package in.blogspot.ashish4java.employeesystem.dao; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import in.blogspot.ashish4java.employeesystem.model.Employee; @Repository public class EmployeeDaoImpl implements EmployeeDao { @Autowired SessionFactory sessionFactory; protected Session getsession() { return sessionFactory.getCurrentSession(); } @SuppressWarnings("unchecked") @Override public List<Employee> findAllEmployees() { Session session = getsession(); Criteria criteria = session.createCriteria(Employee.class); return (List<Employee>) criteria.list(); } } |
EmployeeService.java
1 2 3 4 5 6 7 8 9 10 11 | package in.blogspot.ashish4java.employeesystem.service; import java.util.List; import in.blogspot.ashish4java.employeesystem.model.Employee; public interface EmployeeService { List<Employee> findAllEmployees(); } |
EmployeeServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package in.blogspot.ashish4java.employeesystem.service; import java.util.List; import org.springframework.transaction.annotation.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import in.blogspot.ashish4java.employeesystem.dao.EmployeeDao; import in.blogspot.ashish4java.employeesystem.model.Employee; @Service @Transactional public class EmployeeServiceImpl implements EmployeeService { @Autowired EmployeeDao employeeDao; @Override public List<Employee> findAllEmployees() { return employeeDao.findAllEmployees(); } } |
finally, WelcomeController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package in.blogspot.ashish4java.employeesystem.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import in.blogspot.ashish4java.employeesystem.model.Employee; import in.blogspot.ashish4java.employeesystem.service.EmployeeService; @Controller public class WelcomeController { @Autowired private EmployeeService service; @RequestMapping(path = "/employeelist", method = RequestMethod.GET) public String sendMessage(ModelMap map) { List<Employee> empList = service.findAllEmployees(); map.addAttribute("employeeList", empList); return "EmployeeList"; } } |
As mentioned in controller, this controller accepts GET request at {context-root}/employeeList url and returns 'EmployeeList' String which will translate to 'WEB-INF/jsp/EmployeeList.jsp'
EmployeeList.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <%@ page session="false"%> <html> <head> <title>Employee System</title> <style type="text/css"> .tg { border-collapse: collapse; border-spacing: 0; border-color: #ccc; } .tg td { font-family: Arial, sans-serif; font-size: 14px; padding: 10px 5px; border-style: solid; border-width: 1px; overflow: hidden; word-break: normal; border-color: #ccc; color: #333; background-color: #fff; text-align: center; } .tg th { font-family: Arial, sans-serif; font-size: 14px; font-weight: normal; padding: 10px 5px; border-style: solid; border-width: 1px; overflow: hidden; word-break: normal; border-color: #ccc; color: #333; background-color: #f0f0f0; text-align: center; } .tg .tg-4eph { background-color: #f9f9f9 } </style> </head> <body> <h1>List of Employees</h1> <c:if test="${!empty employeeList}"> <table class="tg"> <tr> <th width="80">Employee ID</th> <th width="120">First Name</th> <th width="120">Last Name</th> <th width="220">Designation</th> <th width="180">Joining Date</th> </tr> <c:forEach items="${employeeList}" var="employee"> <tr> <td>${employee.employeeId}</td> <td>${employee.firstName}</td> <td>${employee.lastName}</td> <td>${employee.designation}</td> <td>${employee.joiningDate}</td> </tr> </c:forEach> </table> </c:if> </body> </html> |
Apart from this, to load some initial data in database once hibernate drops and create new schema, create 'import.sql' file on classpath. Hibernate will execute this file after new schema is created by it.
import.sql
1 2 3 4 | INSERT INTO public.employee( employeeid, designation, firstname, joiningdate, lastname, leavingdate) VALUES (1, 'Full Stack Java Developer', 'Ashish', '01/01/2011', 'Gajabi', null); INSERT INTO public.employee( employeeid, designation, firstname, joiningdate, lastname, leavingdate) VALUES (2, 'CTO', 'John', '09/12/2001', 'Varma', null); INSERT INTO public.employee( employeeid, designation, firstname, joiningdate, lastname, leavingdate) VALUES (3, 'Solution Designer', 'Richard', '06/14/2007', 'Hank', null); INSERT INTO public.employee( employeeid, designation, firstname, joiningdate, lastname, leavingdate) VALUES (4, 'Senior Tester', 'Sachin', '03/28/2015', 'Singh', null); |
Once all this done, deploy this application on tomcat where we configured datasource and hit the url http://localhost:8080/SpringDataSourceExample/employeelist
Output clearly shows Spring MVC application was successfully able to connect to datasource configured on tomcat and able to fetch list of employees through Hibernate.