Server-side forward
Spring Concepts / Server-side forward
A forward delegates to another server resource inside the same request.
Understand the idea
The Servlet prepares data as request attributes, selects a JSP through RequestDispatcher, and forwards the request and response to it. The JSP reads those attributes and produces the HTML response.
A concrete example
request.getRequestDispatcher("/WEB-INF/views/list.jsp")
.forward(request, response);In the application
TodoServlet forwards for list/form rendering and validation failures.
Do not commit the response body before forwarding. Forward is different from a redirect that asks the browser for a new request.
1. Prepare the data in the Servlet
These statements belong inside the Servlet request handler. The existing store loads the tasks; setAttribute() then places that Java list on the current request under the name todos.
List<Todo> tasks = store.list();
request.setAttribute("todos", tasks);
request.getRequestDispatcher("/WEB-INF/views/list.jsp")
.forward(request, response);setAttribute() makes the data available to the view. It does not render a JSP or send the list to the browser by itself.
2. Understand each part
| Expression | What it does |
|---|---|
| tasks | The Java List<Todo> containing the data. |
| "todos" | The attribute name the JSP will use to find that list. |
| request.setAttribute("todos", tasks) | Stores the list on this request. |
| getRequestDispatcher("/WEB-INF/views/list.jsp") | Obtains a dispatcher for the JSP resource. The initial slash means the web application root. |
| forward(request, response) | Hands the current request and response to that resource so it can generate the response. |
3. Read the data in the JSP
Save the view at src/main/webapp/WEB-INF/views/list.jsp. This excerpt uses the JSTL dependencies already included in the supplied project.
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<ul>
<c:forEach items="${requestScope.todos}" var="todo">
<li><c:out value="${todo.title}" /></li>
</c:forEach>
</ul>${requestScope.todos} reads the request attribute explicitly. ${todos} also works here when no closer scope shadows the name. The loop visits each Todo; ${todo.title} reads its getTitle() property, and c:out escapes the title for safe HTML text output.
4. Follow the complete flow
If the list contains tasks titled Learn Java and Learn JSP, the page displays the following bullet list.
Browser requests /todo-servlet-jsp/todos
-> Servlet loads tasks
-> setAttribute("todos", tasks)
-> forward to /WEB-INF/views/list.jsp
-> JSP reads the list and renders HTML
-> Browser displays that HTMLThe browser URL remains /todo-servlet-jsp/todos. The JSP runs on the server; the browser receives its generated HTML, not JSP source. Files inside WEB-INF cannot be opened directly by a browser URL.
5. Expected browser output
The same request carries the attributes into the JSP. A redirect starts another browser request, so these request attributes do not automatically travel with it.
• Learn Java
• Learn JSP6. Common mistakes to check
The names must match: setAttribute("todos", tasks) pairs with ${requestScope.todos}, not ${requestScope.tasks}. The Java variable name tasks does not become the attribute name automatically.
If the list is null or empty, c:forEach has no items to display. First check the attribute name and the data returned by store.list().
Prepare the data before forwarding. Keep data loading in the Servlet or its service layer and presentation in the JSP. Do not send or flush response content before calling forward().
Practice: change the attribute name to taskList in both the Servlet and the JSP, rebuild the WAR, redeploy it, and confirm that the tasks still appear.