DI-322 Web Technologies Lecture 14: Server-side Java, requests, responses and the servlet lifecycle
DI-322 Web Technologies
0% Completed

Lecture 14: Server-side Java, requests, responses and the servlet lifecycle

Outcomes and readiness

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.

Container model

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.

Lifecycle and concurrency

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.

Worked mapping

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.

Faded example

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.

Common mistakes

  • A servlet instance is not “one object per user.”
  • Writing the body before deciding status/encoding can commit an incorrect response.
  • getParameter returns untrusted input; routing through a servlet does not validate it.

Practical – DI322-LAB14

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.

Independent check

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.

Homework – DI322-A14-H1

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.

Revision

Container owns lifecycle and dispatch; application code owns validation and behavior. Treat every request as potentially concurrent with another.