LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 2425 min read

Real-World Project

Plan and build a simple student registration application using Servlets, JSP, and sessions, applying everything covered across the course.

Introduction

This final lesson pulls together everything from the course into one working application: a student registration system. Visitors can register, log in, and see a list of registered students, while the server tracks who is logged in using a session. Every piece — forms, JavaBeans, servlets, forwarding, sessions, JSTL, and error handling — appears here doing real work.

What You Will Build
  • A registration form that posts to a controller servlet.
  • A StudentBean model and an in-memory student store.
  • A login page that establishes a session.
  • A protected student list page only visible to logged-in users.

Planning the Application

Before writing code, sketch the flow: a visitor registers, is redirected to log in, logs in to create a session, and then can view the student list. Any attempt to view the list without a session should redirect back to login — this is the same MVC and session pattern from earlier lessons, just assembled into one flow.

Project Structure

Project Structure
webapp/
├── register.jsp
├── login.jsp
├── students.jsp
├── WEB-INF/
│ ├── web.xml
│ └── classes/
│ └── com/programinds/
│ ├── beans/StudentBean.java
│ ├── controllers/RegisterServlet.java
│ ├── controllers/LoginServlet.java
│ └── store/StudentStore.java

The Student Model

StudentBean.java
// StudentBean.java
package com.programinds.beans;
public class StudentBean {
private String name;
private String email;
private String password;
public StudentBean() { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
StudentStore.java
// StudentStore.java — a simple in-memory store standing in for a database
package com.programinds.store;
import com.programinds.beans.StudentBean;
import java.util.*;
public class StudentStore {
private static final List<StudentBean> students = new ArrayList<>();
public static void add(StudentBean student) {
students.add(student);
}
public static List<StudentBean> all() {
return students;
}
public static StudentBean findByEmail(String email, String password) {
for (StudentBean s : students) {
if (s.getEmail().equals(email) && s.getPassword().equals(password)) {
return s;
}
}
return null;
}
}

The Registration Form

<!-- register.jsp -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<h2>Student Registration</h2>
<c:if test="${not empty errorMessage}">
<p class="error">${errorMessage}</p>
</c:if>
<form action="register" method="post">
<input type="text" name="name" placeholder="Full name" required />
<input type="email" name="email" placeholder="Email" required />
<input type="password" name="password" placeholder="Password" required />
<button type="submit">Register</button>
</form>
<p>Already registered? <a href="login.jsp">Log in</a></p>
</body>
</html>

The Controller Servlet

RegisterServlet.java
// RegisterServlet.java
package com.programinds.controllers;
import com.programinds.beans.StudentBean;
import com.programinds.store.StudentStore;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
String email = request.getParameter("email");
String password = request.getParameter("password");
if (name == null || name.trim().isEmpty() || email == null || !email.contains("@")
|| password == null || password.length() < 6) {
request.setAttribute("errorMessage", "Please fill every field correctly (password 6+ chars).");
request.getRequestDispatcher("/register.jsp").forward(request, response);
return;
}
StudentBean student = new StudentBean();
student.setName(name);
student.setEmail(email);
student.setPassword(password);
StudentStore.add(student);
response.sendRedirect("login.jsp"); // Post/Redirect/Get after a state change
}
}

Storing Registered Students

The StudentStore class above stands in for a real database in this lesson — the same registration flow would work unchanged against JDBC or a JPA repository, since the controller only depends on add() and findByEmail() existing somewhere.

Login and Session Handling

<!-- login.jsp -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${not empty errorMessage}">
<p class="error">${errorMessage}</p>
</c:if>
<form action="login" method="post">
<input type="email" name="email" placeholder="Email" required />
<input type="password" name="password" placeholder="Password" required />
<button type="submit">Log In</button>
</form>
LoginServlet.java
// LoginServlet.java
package com.programinds.controllers;
import com.programinds.beans.StudentBean;
import com.programinds.store.StudentStore;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String email = request.getParameter("email");
String password = request.getParameter("password");
StudentBean student = StudentStore.findByEmail(email, password);
if (student == null) {
request.setAttribute("errorMessage", "Invalid email or password.");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
HttpSession session = request.getSession();
session.setAttribute("loggedInStudent", student);
session.setMaxInactiveInterval(30 * 60); // 30 minutes
response.sendRedirect("students.jsp");
}
}

The Student List View

The final page checks the session before rendering anything, forwarding unauthenticated visitors back to login — the same guard pattern real applications use for every protected page.

<!-- students.jsp -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${empty sessionScope.loggedInStudent}">
<jsp:forward page="login.jsp" />
</c:if>
<h2>Welcome, ${sessionScope.loggedInStudent.name}</h2>
<h3>Registered Students</h3>
<ul>
<c:forEach var="s" items="${studentStore}">
<li>${s.name} — ${s.email}</li>
</c:forEach>
</ul>
<a href="logout">Log Out</a>
Rendered Output

Click Run to see what this code prints.

Common Mistakes

Avoid These Mistakes
  • Forgetting to guard protected pages with a session check, letting anyone view students.jsp directly by URL.
  • Storing plain-text passwords, even in a learning project — always hash passwords in anything beyond a toy example.
  • Redirecting after registration with a forward instead of sendRedirect, risking a duplicate registration on refresh.
  • Forgetting session.invalidate() on logout, leaving the session reachable after the user believes they logged out.

Best Practices

  • Guard every protected view with an explicit session check at the top of the page.
  • Use Post/Redirect/Get after registration and login to avoid duplicate form resubmission.
  • Keep the store/service layer swappable — this project's StudentStore could become a JDBC-backed class with no changes to the JSP views.
  • Log users out with session.invalidate(), not just by clearing a client-side cookie.

Frequently Asked Questions

Only StudentStore would change, replacing the in-memory list with JDBC or JPA calls — the servlets and JSP views stay exactly the same, which is the whole point of separating layers with MVC.

No, it exists purely for teaching. A real application needs a persistent database and hashed passwords; the in-memory store is not thread-safe or durable.

Inside RegisterServlet before calling StudentStore.add(), and inside StudentStore.findByEmail() when comparing the submitted password against the stored hash.

Key Takeaways

  • A complete JSP application combines forms, servlets, beans, sessions, and JSTL views.
  • Controllers validate and process; JSP views only render what the controller prepared.
  • Sessions gate access to protected pages and identify the logged-in user.
  • Swapping the data layer (like an in-memory store for a real database) should not require touching the views.

Summary

This project brought together forms, JavaBeans, servlets, forwarding, sessions, and JSTL into one working application — the same architecture underlying countless real-world Java web systems still running in production today.

JSP Course Completed!

You have successfully completed all 24 lessons — from your first JSP page through Expression Language, JSTL, session management, and the full Servlet-JSP MVC pattern. You now have a genuinely useful foundation for maintaining and building classic Java web applications.

Browse All Courses →