On this page
JSP Basics
JavaServer Pages (JSP) generate dynamic HTML by embedding Java code in web pages. JSPs are compiled into servlets by the container and support Expression Language (EL) and JSTL for cleaner templates.
JSP Lifecycle
JSP file → Translation (to servlet) → Compilation → Class loading → init → service
First request triggers translation and compilation; subsequent requests use the compiled servlet.
Basic JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.example.model.User" %>
<!DOCTYPE html>
<html>
<head><title>User Profile</title></head>
<body>
<h1>Welcome, <%= request.getAttribute("user") %></h1>
<p>Current time: <%= new java.util.Date() %></p>
</body>
</html>
Expression Language (EL)
Preferred over scriptlets:
<h1>Welcome, ${user.name}</h1>
<p>Email: ${user.email}</p>
<p>Orders: ${user.orders.size()}</p>
<!-- Conditional -->
<c:if test="${user.active}">
<span class="badge">Active</span>
</c:if>
<!-- Loop -->
<c:forEach var="order" items="${user.orders}">
<tr>
<td>${order.id}</td>
<td>${order.total}</td>
</tr>
</c:forEach>
JSTL (JSP Standard Tag Library)
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<!-- Set variable -->
<c:set var="greeting" value="Hello" />
<!-- Choose/when/otherwise -->
<c:choose>
<c:when test="${user.role == 'ADMIN'}">Admin Panel</c:when>
<c:when test="${user.role == 'USER'}">User Dashboard</c:when>
<c:otherwise>Guest View</c:otherwise>
</c:choose>
<!-- Format -->
<fmt:formatDate value="${order.createdAt}" pattern="yyyy-MM-dd HH:mm"/>
<fmt:formatNumber value="${order.total}" type="currency" currencySymbol="$"/>
JSP Directives
<%@ page contentType="text/html;charset=UTF-8" %> <!-- page config -->
<%@ page import="java.util.List" %> <!-- imports -->
<%@ page errorPage="/error.jsp" %> <!-- error handler -->
<%@ include file="/WEB-INF/header.jsp" %> <!-- static include -->
<%@ taglib prefix="c" uri="jakarta.tags.core" %> <!-- tag library -->
MVC with JSP
Servlet (Controller) → sets attributes → forwards to JSP (View)
@WebServlet("/users")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
List<User> users = userService.findAll();
request.setAttribute("users", users);
request.getRequestDispatcher("/WEB-INF/views/users.jsp").forward(request, response);
}
}
<!-- /WEB-INF/views/users.jsp -->
<table>
<c:forEach var="user" items="${users}">
<tr><td>${user.name}</td><td>${user.email}</td></tr>
</c:forEach>
</table>
Store JSPs under /WEB-INF/ to prevent direct browser access.
JSP vs Modern Alternatives
| Technology | Status | Use case |
|---|---|---|
| JSP + JSTL | Legacy but stable | Existing Java EE apps |
| Thymeleaf | Active | Spring Boot default |
| React/Vue + REST API | Modern | SPAs |
| Spring MVC + Thymeleaf | Recommended | New Spring projects |
Best Practices
- Avoid scriptlets (
<% %>) — use EL and JSTL instead - Place JSP files under
/WEB-INF/views/for security - Use JSTL
<c:forEach>and<c:if>over Java loops in JSP - Separate business logic into servlets/controllers — JSP is view only
- For new Spring Boot projects, use Thymeleaf instead of JSP