Spring MVC and Hibernate Project

Last Updated on: February 8, 2021 pm

Spring MVC and Hibernate Project

Overview

Big Picture

  1. Browser makes a request to the customer controller.
  2. Customer Controller makes use of the Customer DAO.
  3. The DAO access the database using the Hibernate API.
  4. The controller place the data into your Spring MVC model and send that to the JSP pages.
  5. The JSP pages will render that data to the screen.

List Customers

1. Create Hibernate Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;

@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@Column(name = "email")
private String email;
}

Entity Scanning

1
<property name="packagesToScan" value="com.luv2code.springdemo.entity" />

If data source is not found, add a MySQL datasource.

Add Data Sources

2. Create DAO

Customer DAO

Wire them together with Dependency Injection!

Data Source

Data source tells us the database connection info.

1
2
3
4
5
6
7
8
9
10
11
12
<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/web_customer_tracker?useSSL=false&amp;serverTimezone=UTC" />
<property name="user" value="springstudent" />
<property name="password" value="springstudent" />

<!-- these are connection pool properties for C3P0 -->
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="30000" />
</bean>

Session Factory

1
2
3
4
5
6
7
8
9
10
11
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="com.luv2code.springdemo.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>

SessionFactory depends on Data Source.

Define DAO Interface

1
2
3
public interface CustomerDAO {
public List<Customer> getCustomers();
}

Define DAO Implementation

Inject the SessionFactory using @Autowired.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Repository
public class CustomerDAOImpl implements CustomerDAO{
@Autowired
private SessionFactory sessionFactory;

@Override
@Transactional
public List<Customer> getCustomers() {
//get the current session
Session session = sessionFactory.getCurrentSession();
// create a query
Query<Customer> query = session.createQuery("from Customer", Customer.class);
// Execute the query
List<Customer> res = query.getResultList();
// return the result
return res;
}
}

@Repository

Always apply @Repository before your DAOImplementation class.

It’s a subclass and inherits from the @Component, so it will be available for auto-scanning of component scanning.

Spring wil automatically register the DAO implementation.

Spring will also translate any JDBC related exceptions to unchecked exceptions.

Therefore, Repository is specific for code that talks to a data source or back-end repository.

@Transactional

@Transactional will automatically begin and end a transaction for your Hibernate code. So no need for you to explicitly do this.

Always apply @Transactional in your @Override methods.

3. Create Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
@RequestMapping("/customer")
public class CustomerController {
// need to inject Customer DAO into controller

@Autowired
private CustomerDAO customerDAO;

@RequestMapping("/list")
public String listCustomer(Model theModel){
// get customers from the DAO
List<Customer> customers = customerDAO.getCustomers();
// add the customers to the Model
theModel.addAttribute("customers", customers);
return "list-customer";
}
}

4. Create JSP Page

1
2
3
4
<head>                                                                                                        
<title>List Customer</title>
<link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
1
2
3
4
5
6
7
<c:forEach var="tempCustomer" items="${customers}">
<tr>
<td>${tempCustomer.firstName}</td>
<td>${tempCustomer.lastName}</td>
<td>${tempCustomer.email}</td>
</tr>
</c:forEach>

New Annotations

@GetMapping

@GetMapping("/processForm") = @RequestMapping(path="/processForm", method=Request.GET)

This mapping ONLY handles GET method. Any other HTTP REQUEST method will get rejected.

@PostMapping

1
2
<form action="processForm" method="POST">
</form>

@PostMapping("/processForm") = @RequestMapping(path="/processForm", method=Request.POST)

This mapping ONLY handles POST method. Any other HTTP REQUEST method will get rejected.

Service Layer

Add a service layer between the Customer Controller and Customoer DAO.

The purpose of the service layer is to integrate multiple data sources.

@Service

@Service applied to Service Implementations.

Spring wil automatically register the Service implementation.

Develop Customer Service

1. Define Service Interface

1
2
3
public interface CustomerService {
public List<Customer> getCustomer();
}

2. Define Service Implementation

Inject the CustomerDAO

Remove @Transactional from DAO implementation and add @Transactional annotation to Service Layer.

1
2
3
4
5
6
7
8
9
10
11
@Service
public class CustomerServiceImpl implements CustomerService{

@Autowired
private CustomerDAO customerDAO;
@Override
@Transactional
public List<Customer> getCustomer() {
return customerDAO.getCustomers();
}
}

Note: Don’t forget to modify the controller to make it talk to Service layer dirctly.

Revised Big Picture

Revised Big Picture

Add Customers

1. Create “Add Customer” Button

1
2
3
<input type="button" value="Add Customer" 
onclick="window.location.href='showFormForAdd'; return false;"
class="add-button"/>

Call Spring Controller Mapping.

2. Create HTML Form

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
<div id="container">
<h3>Save Customer</h3>
<form:form action="saveCustomer" modelAttribute="customer" method="POST">
<table>
<tbody>
<tr>
<td><label>First Name:</label></td>
<td><form:input path="firstName"/></td>
</tr>
<tr>
<td><label>Last Name:</label></td>
<td><form:input path ="lastName"/> </td>
</tr>
<tr>
<td><label>Email:</label></td>
<td><form:input path="email"/> </td>
</tr>
<tr>
<td><label></label></td>
<td><input type="submit" value="Save" class="save"/> </td>
</tr>
</tbody>
</table>
</form:form>
<p>
<a href="${pageContext.request.contextPath}">Back To List</a>
</p>
</div>

3. Process Form Data

1. Controller

1
2
3
4
5
6
7
8
9
10
11
@GetMapping(value = "/showFormForAdd")
public String showFormForAdd(Model theModel){
theModel.addAttribute("customer", new Customer());
return "customer-form";
}

@PostMapping("/saveCustomer")
public String saveCustomer(@ModelAttribute("customer") Customer theCustomer){
customerService.saveCustomer(theCustomer);
return "redirect:/customer/list";
}

2. Service

1
2
3
4
5
6
7
8
9
10
@Override
@Transactional
public Customer getCustomer(int theId) {
return customerDAO.getCustomer(theId);
}
@Override
@Transactional
public void saveCustomer(Customer customer) {
customerDAO.saveCustomer(customer);
}

3. DAO

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public Customer getCustomer(int theId) {
Session session = sessionFactory.getCurrentSession();
Customer customer = session.get(Customer.class, theId);
return customer;
}

@Override
public void saveCustomer(Customer customer) {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(customer); // save or update !!! important!!
return;
}

Update Customer

1. Update Customer List

1
2
3
4
5
6
7
8
<c:url var="updateLink" value="/customer/showFormForUpdate">
<c:param name="customerId" value="${tempCustomer.id}"/>
</c:url>
<tr>
<td>
<a href="${updateLink}">Update</a>
</td>
</tr>

2. Prepopulate Customer Form

1
<form:hidden path="id"/>

Note: Add <form:hidden path="id"/> into customer form. Very Important!

Track the selected Customer by storing the Id in the HTML form. Then the backend controller can retrive the customer by Id.

3. Process Form Data

1. Controller

1
2
3
4
5
6
7
8
9
10
@GetMapping("/showFormForUpdate")
public String updateCustomer(
@RequestParam("customerId") int theId,
Model theModel){
// get the customer from service
Customer customer = customerService.getCustomer(theId);
// set the customer as a model attribute to pre-populate the form
theModel.addAttribute("customer", customer);
return "customer-form";
}

2. Service

1
2
3
4
5
@Override
@Transactional
public void saveCustomer(Customer customer) {
customerDAO.saveCustomer(customer);
}

3. DAO

1
2
3
4
5
6
@Override
public void saveCustomer(Customer customer) {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(customer); // save or update !!! important!!
return;
}

Note: session.saveOrUpdate(Object o) method will check if there is an existing object in the database, if yes, update its info. If no, save the new object to the database.

Delete Customer

1. Delete Customer List

1
2
3
4
|
<a href="${deleteLink}" onclick="if
(!(confirm('Are you sure you want to delete this customer?')))
return false">Delete</a>

2. Prepopulate Customer Form

1
2
3
<c:url var="deleteLink" value="/customer/delete">
<c:param name="customerId" value="${tempCustomer.id}"/>
</c:url>

Prepopulate Customer Form by storing customerId param in the URL.

3. Process Form Data

1. Controller

1
2
3
4
5
@GetMapping("/delete")
public String deleteCustomer(@RequestParam("customerId") int theId){
customerService.deleteCustomer(theId);
return "redirect:/customer/list";
}

2. Service

1
2
3
4
5
@Override
@Transactional
public void saveCustomer(Customer customer) {
customerDAO.saveCustomer(customer);
}

3. DAO

1
2
3
4
5
6
7
8
9
@Override
public void deleteCustomer(int theId) {
Session session = sessionFactory.getCurrentSession();
// delete the customer in the database
Query theQuery = session.createQuery("delete from Customer where id =:theCustomerId");
theQuery.setParameter("theCustomerId", theId);
theQuery.executeUpdate();
return;
}

Reference: Udemy, Spring & Hibernate for Beginners (including SpringBoot)