Java Spring

Spring MVC with Bootstrap and Hibernate – Full CRUD Application

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.

Topics: Java Spring
← Newer Post Older Post →