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