In MVC with JSP, a servlet or controller handles the request, a service performs business work, and the JSP renders a prepared model. Place JSP files under WEB-INF so clients cannot bypass the controller and invoke a view without its required data.
MVC (Model-View-Controller) is a software design pattern that separates an application into three interconnected components:
In the JSP+Servlet MVC pattern: the browser sends a request to a Servlet (Controller), which processes it, interacts with the Model, and then forwards to a JSP (View) to render the response.
package com.example.model;
// Model: JavaBean representing a User
public class User {
private String username;
private String password;
private String email;
private String role;
public User() {}
public User(String username, String password, String email, String role) {
this.username = username;
this.password = password;
this.email = email;
this.role = role;
}
// Getters and Setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
// Business logic method
public boolean isAdmin() {
return "admin".equalsIgnoreCase(role);
}
}
package com.example.controller;
import com.example.model.User;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
// Show login form (GET)
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Forward to login view
RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/login.jsp");
rd.forward(request, response);
}
// Process login form (POST)
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
// Validate credentials (in real app, check database)
if ("admin".equals(username) && "password123".equals(password)) {
// Create user model
User user = new User(username, password, "admin@example.com", "admin");
// Store in session
HttpSession session = request.getSession();
session.setAttribute("loggedUser", user);
// Forward to welcome view
RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/welcome.jsp");
rd.forward(request, response);
} else {
// Set error message and forward back to login
request.setAttribute("errorMsg", "Invalid username or password!");
RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/login.jsp");
rd.forward(request, response);
}
}
}
<%-- WEB-INF/views/login.jsp --%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<style>
.login-box { max-width:400px; margin:80px auto; padding:30px;
border:1px solid #ddd; border-radius:8px; }
.error { color:red; margin-bottom:10px; }
input { width:100%; padding:8px; margin:8px 0; box-sizing:border-box; }
button { width:100%; padding:10px; background:#2196F3; color:#fff; border:none; cursor:pointer; }
</style>
</head>
<body>
<div class="login-box">
<h2>Login</h2>
<c:if test="${not empty errorMsg}">
<p class="error">${errorMsg}</p>
</c:if>
<form action="${pageContext.request.contextPath}/login" method="post">
<input type="text" name="username" placeholder="Username" required/>
<input type="password" name="password" placeholder="Password" required/>
<button type="submit">Login</button>
</form>
</div>
</body>
</html>
<%-- WEB-INF/views/welcome.jsp --%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%-- Protect this page: redirect if not logged in --%>
<c:if test="${empty sessionScope.loggedUser}">
<c:redirect url="/login"/>
</c:if>
<!DOCTYPE html>
<html>
<head><title>Welcome</title></head>
<body>
<h1>Welcome, ${sessionScope.loggedUser.username}!</h1>
<p>Email: ${sessionScope.loggedUser.email}</p>
<p>Role: ${sessionScope.loggedUser.role}</p>
<c:if test="${sessionScope.loggedUser.admin}">
<p><a href="admin.jsp">Go to Admin Panel</a></p>
</c:if>
<p><a href="${pageContext.request.contextPath}/logout">Logout</a></p>
</body>
</html>
The controller validates input, selects a status or redirect, stores view data as request attributes, and forwards to the JSP. The JSP reads that model with EL and JSTL. Avoid scriptlets because they mix Java control flow, persistence, and HTML in a file that should express presentation.
Use Post-Redirect-Get after a successful form write and forward on validation failure so entered values and errors remain available. Escape user content, keep authorization in the controller/service boundary, and test the controller contract separately from rendered markup.
<%@ page contentType="text/html;charset=UTF-8" %>
<main>
<h1>MVC</h1>
<p>Use JSP for the view layer and keep business logic in a servlet or service class.</p>
</main>
request.setAttribute("lessonTitle", "MVC");
request.setAttribute("reviewed", Boolean.TRUE);
request.getRequestDispatcher("/WEB-INF/views/lesson.jsp").forward(request, response);
// The servlet prepares data; the JSP renders it.
A Servlet controller should validate the request, call application logic, and select the next view.
They last for one request and avoid retaining page-specific data in the session.
Redirect when refreshing the result must not submit the form again.
Explore 500+ free tutorials across 20+ languages and frameworks.