Lokesh / Case Study โ† Back to all projects
LIVE โ€” deployed on Render

Course Management Portal

A full-stack course enrollment system rebuilt from a legacy Servlet/JSP codebase into a modern Spring Boot application โ€” role-based access for students and admins, real database-backed enrollment, and a complete migration story from raw JDBC to Spring Data JPA.

Role
Solo Developer
Duration
~3 weeks
Type
Full-Stack Migration
Status
Deployed & Live
~/course-management-portal
$ mvn spring-boot:run
...
Tomcat initialized on port 8080
HikariPool-1 โ€” connection established
Started CourseManagementPortalApplication
Overview

What this project is

Course Management Portal is a web application that lets students browse and enroll in courses, and lets admins create, edit, and manage the course catalog. It started as a Java Servlet + JSP + raw JDBC project, and I rebuilt it end-to-end in Spring Boot โ€” swapping hand-written SQL for Spring Data JPA, a custom session filter for Spring Security, and JSP templates for Thymeleaf โ€” while keeping every original feature intact.

The Challenge

Why rebuild a working app?

THE PROBLEM

The original app worked, but every new feature meant touching a DAO class, a servlet, a JSP, and often web.xml. Manual JDBC connection handling and hand-wired dependencies made the codebase fragile and slow to extend โ€” and it wasn't a stack most modern Java teams actually hire for.

THE SOLUTION

A full migration to Spring Boot: Spring Data JPA repositories replaced ~500 lines of DAO code with five-line interfaces, Spring Security handled dual-role authentication (student/admin) out of the box, and Thymeleaf brought server-side templating in line with how the framework actually expects it.

Features

What it does

๐Ÿ”

Dual-role authentication

One login screen, two roles โ€” Spring Security checks the Admin table first, then falls back to Students, using BCrypt-hashed passwords.

๐Ÿ“š

Course catalog management

Admins can add, edit, and remove courses with fee, duration, trainer, and category fields โ€” all validated server-side.

๐ŸŽ“

Student enrollment

Students browse active courses and enroll with one click; duplicate enrollments are blocked at the database level.

๐Ÿ“Š

Personal dashboard

Each student has a "My Courses" view pulling only their own enrollments via a scoped repository query.

๐Ÿ—„๏ธ

Relational data model

Four related MySQL tables โ€” Admins, Students, Courses, Enrollments โ€” mapped with JPA @ManyToOne relationships.

โ˜๏ธ

Cloud deployed

Live on Render with a custom domain and CNAME routing, connected to a managed MySQL instance.

Architecture

How a request flows

A standard Spring MVC layered architecture โ€” each layer has exactly one job, which is the whole point of the migration.

๐ŸŒ
Browser
Thymeleaf view
โ†’
๐Ÿ›ก๏ธ
Security Filter
Spring Security
โ†’
๐ŸŽฏ
Controller
@Controller
โ†’
โš™๏ธ
Service
business logic
โ†’
๐Ÿ—ƒ๏ธ
Repository
Spring Data JPA
โ†’
๐Ÿฌ
MySQL
4 tables
A closer look

Screens

Challenges & Learnings

What actually broke, and how I fixed it

01

Schema/entity type mismatches

Hibernate's ddl-auto=validate rejected the app on startup because fees was a Java double but the column was DECIMAL(10,2) in MySQL, and a timestamp field was typed as String instead of LocalDateTime.

โ†’ Fixed by matching every entity field type exactly to its SQL column type โ€” BigDecimal for money, LocalDateTime for timestamps.
02

One login form, two different user tables

Admins and Students live in separate tables with different identifying fields (username vs. email). Spring Security's default login only understands a single "username" field.

โ†’ Solved with a custom UserDetailsService that checks the Admin table first, then falls back to Student lookup by email.
03

JSP scriptlets don't translate to Thymeleaf

Direct copy-pasting old JSP templates into the new templates/ folder produced broken pages โ€” Thymeleaf doesn't understand <% %> scriptlets or JSP's pageContext expressions at all.

โ†’ Rebuilt each view using Thymeleaf's own syntax (th:each, th:field, @{...}) rather than translating line-by-line.
By the numbers
4
Related DB entities
2
User roles secured
~500โ†’5
Lines of DAO code cut
100%
Feature parity kept
Tech Stack

Built with

Java 25
Spring Boot
Spring Security
Spring Data JPA
Hibernate
MySQL
Thymeleaf
Bootstrap 5
โ† Back to all projects