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.
- 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
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.javaThe Student Model
// StudentBean.javapackage 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 — a simple in-memory store standing in for a databasepackage 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.javapackage 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.javapackage 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>Click Run to see what this code prints.
Common 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.