Real-World Project
Plan and build a simple student registration application using Servlets, JSP, and sessions, applying everything covered across the course.
On this page 14 sections
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.