Servlets and JSP — Complete Guide
In this tutorial, you will learn about Servlets and JSP. We cover key concepts, practical examples, and best practices to help you master this topic.
The Foundation of Java Web Development
Before modern frameworks like Spring Boot and Jakarta Faces, Java web applications were built with Servlets and JavaServer Pages (JSP). Servlets handle the request-response lifecycle on the server side, processing HTTP requests and generating responses. JSP provides a templating engine that mixes HTML with Java code to create dynamic web pages. Together, they formed the Model-View-Controller (MVC) pattern for Java web applications.
Although many developers now use higher-level frameworks, understanding Servlets and JSP is valuable because every Java web framework ultimately runs on top of the Servlet API. The Servlet container (Tomcat, Jetty, Undertow) handles HTTP connections, threading, and request routing. Knowledge of the request lifecycle, session management, filters, and listeners translates directly to Spring MVC and other frameworks.
flowchart TB
subgraph Container[Servlet Container - Tomcat]
direction TB
Client[Web Browser] --> Connector
Connector --> Engine
Engine --> Host[Virtual Host]
Host --> Context[Web Application]
Context --> Filter1 --> Filter2 --> Servlet
Servlet --> JSP[JSP Engine]
Context --> Listener[Context Listener]
end
Servlet --> JDBC[(Database)]
JSP --> HTML[HTML Response]
HTML --> Client
Setting Up a Servlet Application
Project Structure
my-webapp/
src/
main/
java/
com/example/
HelloServlet.java
UserController.java
webapp/
WEB-INF/
web.xml
index.jsp
user-list.jsp
pom.xml
Maven Dependencies
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
Writing Your First Servlet
Servlets extend HttpServlet and override doGet(), doPost(), or other HTTP method handlers.
package com.example;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.*;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("HelloServlet initialized");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
String name = req.getParameter("name");
if (name == null || name.isEmpty()) {
name = "World";
}
out.println("<html><body>");
out.println("<h1>Hello, " + name + "!</h1>");
out.println("<p>Request method: " + req.getMethod() + "</p>");
out.println("<p>User agent: " + req.getHeader("User-Agent") + "</p>");
out.println("</body></html>");
}
@Override
public void destroy() {
System.out.println("HelloServlet destroyed");
}
}
web.xml Configuration (Alternative to Annotations)
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
version="6.0">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Handling Form Data with doPost
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("username");
String email = req.getParameter("email");
String password = req.getParameter("password");
ValidationResult validation = validate(username, email, password);
if (validation.hasErrors()) {
req.setAttribute("errors", validation.getErrors());
req.setAttribute("submitted", Map.of("username", username, "email", email));
req.getRequestDispatcher("/WEB-INF/register.jsp")
.forward(req, resp);
} else {
// Save to database...
req.getSession().setAttribute("message", "Registration successful!");
resp.sendRedirect("/myapp/profile");
}
}
}
JavaServer Pages (JSP)
JSP pages mix HTML with JSP tags and expressions to create dynamic content.
Basic JSP Page
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>User List</title>
</head>
<body>
<h1>Users</h1>
<c:if test="${not empty message}">
<div class="alert">${message}</div>
</c:if>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.email}</td>
</tr>
</c:forEach>
</table>
<%@ include file="footer.jsp" %>
</body>
</html>
JSP Declarations, Scriptlets, and Expressions
<%-- Declaration --%>
<%!
private int counter = 0;
private String formatDate(Date date) {
return new java.text.SimpleDateFormat("yyyy-MM-dd")
.format(date);
}
%>
<%-- Scriptlet (raw Java code - avoid in practice) --%>
<%
counter++;
List<String> items = (List<String>) request.getAttribute("items");
for (String item : items) {
%>
<li><%= item %></li> <%-- Expression --%>
<%
}
%>
<%-- Current counter: <%= counter %> --%>
In modern practice, avoid scriptlets and use JSTL tags and EL expressions instead.
Session Management
HTTP is stateless. Sessions allow the server to maintain state across multiple requests.
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
User user = authenticate(username, password);
if (user != null) {
HttpSession session = req.getSession();
session.setAttribute("user", user);
session.setMaxInactiveInterval(3600); // 1 hour
Cookie cookie = new Cookie("sessionId", session.getId());
cookie.setHttpOnly(true);
cookie.setSecure(true);
cookie.setMaxAge(3600);
resp.addCookie(cookie);
resp.sendRedirect("/myapp/dashboard");
} else {
req.setAttribute("error", "Invalid credentials");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession(false);
if (session != null) {
session.invalidate();
}
resp.sendRedirect("/myapp/login.jsp");
}
}
Filters and Listeners
Servlet Filter
Filters intercept requests before they reach a servlet and responses before they reach the client.
@WebFilter("/*")
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
long start = System.currentTimeMillis();
chain.doFilter(request, response);
long duration = System.currentTimeMillis() - start;
System.out.printf("%s %s (%d ms)%n",
req.getMethod(), req.getRequestURI(), duration);
}
}
Context Listener
@WebListener
public class AppContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
DataSource ds = createDataSource();
ctx.setAttribute("dataSource", ds);
System.out.println("Application started");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Application stopped");
}
}
Common Mistakes
1. Thread Safety Issues
Servlets are singletons shared across all requests. Instance variables are not thread-safe.
// Unsafe: shared mutable state
public class UnsafeServlet extends HttpServlet {
private int counter = 0; // Not thread-safe!
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
counter++;
// ...
}
}
// Safe: store state in local variables or use synchronization
public class SafeServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
int localCounter = incrementCounter(); // Use thread-safe mechanism
}
}
2. Writing Too Much Java Code in JSP
JSP files should contain presentation logic only. Business logic belongs in servlets or service classes (MVC pattern).
3. Not Handling Character Encoding
// Set encoding before reading/writing
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
4. Exposing JSP Files Directly
Place JSP files under WEB-INF/ so they cannot be accessed directly via URL. Route all requests through servlets.
5. Creating Sessions for Every Request
req.getSession() creates a session if one does not exist. Use req.getSession(false) to avoid unnecessary session creation for static resources.
6. Forgetting to Configure Servlets
Ensure your @WebServlet annotation or web.xml mapping covers the correct URL pattern. Common mistake: mapping /user instead of /user/*.
Practice Questions
- What is the lifecycle of a servlet? When are init(), service(), and destroy() called?
- What is the difference between forward() and sendRedirect()?
- How does the Servlet container handle multiple concurrent requests to the same servlet?
- What is the purpose of the WEB-INF directory?
- How do you pass data from a servlet to a JSP page?
Challenge: Build a complete MVC web application with user registration, login/logout, and a protected dashboard. Use servlets as controllers, JSP as views, and a service/DAO layer for business logic and data access. Implement a Filter for authentication checking.
FAQ
Mini Project: Blog Engine with Servlets and JSP
Build a simple blog engine that supports:
- User registration and login with session management
- Creating, editing, and deleting blog posts (CRUD)
- Viewing a list of posts with pagination
- Adding comments to posts
- Admin role that can moderate comments
Use Layered Architecture: Servlets (controller), Service classes (business logic), DAO classes (JDBC data access). Use JSP with JSTL for all views.
What's Next
Servlets and JSP are the foundation, but modern Java web development is dominated by frameworks. In the next lesson, you will learn Spring Boot Basics, which simplifies web application development with auto-configuration and production-ready features.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro