You can map HTTP to servlet methods, write a small servlet, explain init-service-destroy, and avoid unsafe shared mutable fields. Readiness: HTTP methods/status, Java classes/interfaces, and JDBC boundaries.
A servlet container creates/configures servlet instances, maps requests, supplies HttpServletRequest and HttpServletResponse, and manages lifecycle. With Jakarta Servlet 6.1 the API package is jakarta.servlet.* and the minimum Java baseline is 17. Older books may show javax.servlet.*; do not mix namespaces in one application.
@WebServlet("/courses")
public final class CourseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
String code = request.getParameter("code");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
if (code == null || code.isBlank()) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("{\"error\":\"code is required\"}");
return;
}
response.getWriter().write("{\"code\":\"" + escapeJson(code) + "\"}");
}
}
In production, use a JSON library rather than handwritten escaping; escapeJson is shown as an explicit warning boundary, not omitted magic.
The container initializes a servlet, may call service concurrently for many requests, then calls destroy before removal. Request-specific values belong in local variables or request scope. A mutable instance field like currentUser can be overwritten by another request and leak data. Shared services must be designed for concurrency.
GET /courses?code=DI-322 -> mapping /courses -> service dispatches to doGet -> parameter validation -> use case -> status/content type/body. A POST should go to doPost; a redirect and a forward are different: redirect tells the client to make another request, while a server-side forward dispatches internally.
Unsafe field: private String lastCode; assigned inside doGet. Hint: can two requests overlap? Solution: keep code local; store legitimate shared immutable/thread-safe dependencies only.
getParameter returns untrusted input; routing through a servlet does not validate it.Build a servlet with GET /courses?code= and POST /courses. Return JSON through a library if available, validate content type/size, and map validation/duplicate/not-found failures. Test two concurrent requests and prove request data is local. If the Servlet API/container is unavailable, deliver compilable project structure plus reasoned traces and mark execution pending.
Q1 Server-side Java’s role? Process requests and produce responses/use cases. Q2 Request object contains? Client request data and metadata. Q3 Who invokes doGet? Container via service dispatch. Q4 Shared mutable request data in fields? Unsafe under concurrent service calls.
Design tests for lifecycle initialization, GET success, validation error, method mismatch, concurrent isolation, and destroy-time cleanup. Rubric: lifecycle 2, HTTP semantics 3, concurrency 2, cleanup 1, test clarity 2.
Container owns lifecycle and dispatch; application code owns validation and behavior. Treat every request as potentially concurrent with another.