Inside `hotel-management-system-servlet-hibernate-jsp`: A Hotel App That Shows Its Jakarta EE Guts
A multi-role booking system that uses Servlets, JSP, Hibernate, and MySQL not as abstractions, but as visible machinery, from BLOB-stored images to session checks and hybrid querying.
- This repo matters because it makes a classic Jakarta EE hotel app legible instead of hiding the joints behind framework magic.
- Its most memorable choice is storing hotel images as `LONGBLOB`, which trades simplicity of deployment for database bloat and awkward query behavior.
- Security is handled with explicit session checks in controllers, so the reader can see how role-based access works before frameworks abstract it away.
- The codebase mixes `find()`, JPQL, native SQL, and Java-side filtering, which makes it a useful teaching specimen but not a model of production consistency.
What This Repo Really Is
This is a multi-role hotel management system for admins, hotel owners, and customers. That matters less than how openly it exposes the stack: DTOs for data, DAOs for persistence, servlets for routing, and JSP for rendering. It feels less like a polished SaaS product and more like a readable specimen of old-school Java web development.
That is the value. The project shows what a Java EE app looks like when you can see the seams, from session checks to multipart uploads to Hibernate mappings. For a technically curious reader, the transparency is the feature.
The Stack Is the Point
The repo follows a classic Model 2 MVC layout. DTOs act as the model, DAOs own persistence, servlets route requests, and JSP files render the interface. That structure is simple on paper, but in practice it teaches how a Java web app actually moves work across layers.
A booking request does not disappear into a framework. It lands in a controller, gets checked against session state, passes through a DAO, becomes an entity operation, and comes back as a JSP response. That visibility is the educational payoff.
if (httpSession.getAttribute("adminSession") != null) {
// admin-only flow
} else {
response.sendRedirect("admin-login.jsp");
}
The Weirdest Choice Is Also the Most Teachable
The standout decision is storing hotel images directly in MySQL as `LONGBLOB`. That is not the default choice in modern systems, where images usually live in object storage or on disk while the database keeps a path. Here, the image itself becomes part of the row-level data model.
| Approach | What it buys you | What it costs you |
|---|---|---|
| Store image as `LONGBLOB` | One database contains the full record | Bigger tables and slower reads |
| Store file path in DB | Smaller rows and easier caching | Two systems to keep in sync |
| Store in object storage | Scales well for media | More infrastructure and wiring |
That trade-off is the whole point. For a small teaching project, it is a defensible simplification. For production, it is exactly the kind of decision that makes ops teams nervous.
Security Without a Safety Net
The authorization model is hand-rolled. Controllers inspect session attributes to decide whether a request belongs to an admin, owner, or customer. That is straightforward, and it shows the reader what security looks like before a framework starts managing it for you.
if (httpSession.getAttribute("ownerSession") != null) {
// owner-only action
} else {
response.sendRedirect("owner-login.jsp");
}
This approach is easy to follow, but it also spreads access-control logic across controllers. That is the trade-off: clarity for a beginner, repetition for a maintainer.
Hybrid Persistence, Old and New in the Same Repo
The persistence layer mixes `find()`, JPQL, native SQL, and even Java-side stream filtering. That makes the developer look comfortable across the Hibernate toolbox, but it also reveals a loose consistency model.
| Technique | Where it appears | Why it matters |
|---|---|---|
| `find()` | Primary-key lookups | Direct and idiomatic for single records |
| JPQL | Entity queries | Keeps logic object-oriented |
| Native SQL | Status updates | Fast to write, less portable |
| Java streams | Verified hotel filtering | Readable, but shifts work out of the database |
The most interesting case is in-memory filtering of verified hotels. It is fine at small scale. It is also a reminder that code convenience can quietly become database inefficiency.
What the Controllers Reveal About the App
`HotelRegisterController` shows the app’s most manual mechanics. It handles multipart form data, reads uploaded image bytes into a `byte[]`, and hands that data to the persistence layer. Nothing is hidden.
`HotelBookController` is equally direct. It creates a booking identifier with a custom string pattern and moves the booking through the system as a straightforward transaction. The design is plain, but it is easy to reason about because the controller owns the full flow.
byte[] hotelImage = inputStream.readAllBytes();
String bookingId = "jsp" + Math.abs(Math.random() * 1000000);
How It Compares
A modern Spring Boot hotel app would hide more of this plumbing behind annotations, auto-configuration, and convention. A more typical JSP servlet project might look similar on the surface but be less explicit about the odd choices that make this repo interesting.
| Project type | What you learn | What you lose |
|---|---|---|
| This repo | How classic Jakarta EE layers talk to each other | Production polish and abstraction |
| Modern Spring Boot app | Fast delivery and framework conventions | Visibility into the lower-level mechanics |
| Typical educational JSP app | Basic CRUD patterns | The unusual implementation details that make architecture memorable |
That is why the project stands out. It is not trying to be the best hotel system. It is trying, whether intentionally or not, to show exactly how the machinery works.
Why This Repo Matters
The repo’s value is pedagogical. It turns a basic hotel workflow into a readable blueprint for classic Java web development, and it does so with just enough oddity to keep the reader awake. The BLOB choice, the session checks, and the mixed persistence strategies all expose design decisions that modern stacks usually smooth over.
If you want a clean example of Jakarta EE without much abstraction, this is it. It is not production-hardened, but it is legible, and that makes it useful.