Spring MVC with Bootstrap and Hibernate – Full CRUD Application
Spring MVC is the most widely used Java web framework, and combining it with Hibernate for persistence and Bootstrap for UI gives you a powerful, production-ready stack. This tutorial builds a complete product management CRUD application using Spring MVC 5, Hibernate 5, Bootstrap 5, and MySQL.
Technology Stack
- Spring MVC 5.3.x
- Hibernate 5.6.x
- Bootstrap 5.3
- MySQL 8.x
- Thymeleaf (or JSP) for views
- Maven
Maven pom.xml (Key Dependencies)
<properties>
<spring.version>5.3.27</spring.version>
<hibernate.version>5.6.15.Final</hibernate.version>
</properties>
<dependencies>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring ORM (integrates Hibernate) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Jakarta EE for Servlets -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
Spring Configuration (AppConfig.java)
package com.java9r.config;
import org.springframework.context.annotation.*;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.*;
import javax.sql.DataSource;
import java.util.Properties;
import com.mysql.cj.jdbc.MysqlDataSource;
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.java9r")
public class AppConfig implements WebMvcConfigurer {
// DataSource (use HikariCP in production)
@Bean
public DataSource dataSource() {
MysqlDataSource ds = new MysqlDataSource();
ds.setURL("jdbc:mysql://localhost:3306/java9rdb?useSSL=false");
ds.setUser("root");
ds.setPassword("yourpassword");
return ds;
}
// Hibernate SessionFactory
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sf = new LocalSessionFactoryBean();
sf.setDataSource(dataSource());
sf.setPackagesToScan("com.java9r.model");
Properties props = new Properties();
props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
props.put("hibernate.show_sql", "true");
props.put("hibernate.hbm2ddl.auto", "update");
sf.setHibernateProperties(props);
return sf;
}
// Transaction Manager
@Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory().getObject());
}
// JSP ViewResolver
@Bean
public org.springframework.web.servlet.ViewResolver viewResolver() {
var vr = new org.springframework.web.servlet.view
.InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/views/");
vr.setSuffix(".jsp");
return vr;
}
}
Product Entity
package com.java9r.model;
import javax.persistence.*;
import javax.validation.constraints.*;
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@NotBlank(message = "Product name is required")
@Size(min = 2, max = 100)
@Column(name = "name", nullable = false)
private String name;
@Positive(message = "Price must be positive")
@Column(name = "price")
private double price;
@Min(value = 0, message = "Quantity cannot be negative")
@Column(name = "quantity")
private int quantity;
// Constructors, getters, setters
public Product() {}
public int getId() { return id; }
public String getName() { return name; }
public double getPrice() { return price; }
public int getQuantity() { return quantity; }
public void setId(int id) { this.id = id; }
public void setName(String n){ this.name = n; }
public void setPrice(double p){ this.price = p; }
public void setQuantity(int q){ this.quantity = q; }
}
ProductDAO.java – Repository Layer
package com.java9r.dao;
import com.java9r.model.Product;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Repository
@Transactional
public class ProductDAO {
@Autowired
private SessionFactory sessionFactory;
public void save(Product p) {
sessionFactory.getCurrentSession().saveOrUpdate(p);
}
public List<Product> findAll() {
return sessionFactory.getCurrentSession()
.createQuery("FROM Product ORDER BY id", Product.class)
.list();
}
public Product findById(int id) {
return sessionFactory.getCurrentSession().get(Product.class, id);
}
public void delete(int id) {
var session = sessionFactory.getCurrentSession();
Product p = session.get(Product.class, id);
if (p != null) session.delete(p);
}
}
ProductController.java
package com.java9r.controller;
import com.java9r.dao.ProductDAO;
import com.java9r.model.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Controller
@RequestMapping("/products")
public class ProductController {
@Autowired
private ProductDAO dao;
// List all products
@GetMapping
public String list(Model model) {
model.addAttribute("products", dao.findAll());
return "product/list"; // WEB-INF/views/product/list.jsp
}
// Show add form
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("product", new Product());
model.addAttribute("action", "Add");
return "product/form";
}
// Show edit form
@GetMapping("/edit/{id}")
public String editForm(@PathVariable int id, Model model) {
model.addAttribute("product", dao.findById(id));
model.addAttribute("action", "Edit");
return "product/form";
}
// Save (add or update)
@PostMapping("/save")
public String save(@Valid @ModelAttribute Product product,
BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("action", product.getId() == 0 ? "Add" : "Edit");
return "product/form";
}
dao.save(product);
return "redirect:/products";
}
// Delete
@GetMapping("/delete/{id}")
public String delete(@PathVariable int id) {
dao.delete(id);
return "redirect:/products";
}
}
list.jsp (Bootstrap 5 Table)
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>Products – Java9R</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="p-4">
<div class="container">
<h2 class="mb-3">Product Management</h2>
<a href="/products/add" class="btn btn-primary mb-3">+ Add Product</a>
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr><th>ID</th><th>Name</th><th>Price (Rs.)</th><th>Qty</th><th>Actions</th></tr>
</thead>
<tbody>
<c:forEach var="p" items="${products}">
<tr>
<td>${p.id}</td>
<td>${p.name}</td>
<td>${p.price}</td>
<td>${p.quantity}</td>
<td>
<a href="/products/edit/${p.id}" class="btn btn-sm btn-warning">Edit</a>
<a href="/products/delete/${p.id}" class="btn btn-sm btn-danger"
onclick="return confirm('Delete ${p.name}?')">Delete</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</body>
</html>
Summary
This Spring MVC + Hibernate + Bootstrap application follows the standard three-layer architecture: Controller (handles HTTP), DAO/Repository (handles database via Hibernate), and JSP/Thymeleaf views (handles HTML). Spring's @Transactional manages Hibernate sessions automatically. Bean Validation (@NotBlank, @Positive) catches bad input before it reaches the database. Bootstrap 5 provides a responsive, professional UI without writing custom CSS. This is a solid foundation that you can extend with security, pagination, and file uploads for real-world applications.
Comments