Servlet Exception Handling
try-catch in doGet / doPost
The simplest way to handle exceptions in a servlet is with a standard try-catch block inside doGet() or doPost(). This gives you full control over the error response.
package com.example;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.*;
import java.util.logging.*;
@WebServlet("/user")
public class UserServlet extends HttpServlet {
private static final Logger logger = Logger.getLogger(UserServlet.class.getName());
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try {
String idParam = request.getParameter("id");
// Validate parameter
if (idParam == null || idParam.isEmpty()) {
// Send HTTP 400 Bad Request
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Parameter 'id' is required.");
return;
}
int userId = Integer.parseInt(idParam); // may throw NumberFormatException
// Simulate user lookup
if (userId <= 0) {
// Send HTTP 404 Not Found
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"User with id=" + userId + " not found.");
return;
}
// Normal response
PrintWriter out = response.getWriter();
out.println("<h2>User ID: " + userId + "</h2>");
} catch (NumberFormatException e) {
logger.warning("Invalid id parameter: " + e.getMessage());
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Invalid id format. Must be an integer.");
} catch (Exception e) {
logger.log(Level.SEVERE, "Unexpected error in UserServlet", e);
// Forward to container's error handling
throw new ServletException("Internal error processing user request", e);
}
}
}
web.xml Error Pages
Define global error pages in web.xml to handle HTTP error codes and uncaught exceptions across the entire application. The container sets special request attributes on the error page.
<web-app>
<!-- Map HTTP status codes to error handler servlet -->
<error-page>
<error-code>404</error-code>
<location>/error</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error</location>
</error-page>
<!-- Map specific exception types -->
<error-page>
<exception-type>java.lang.NumberFormatException</exception-type>
<location>/error</location>
</error-page>
<!-- Catch-all for any Throwable -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error</location>
</error-page>
</web-app>
package com.example;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.*;
@WebServlet("/error")
public class ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
handleError(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
handleError(request, response);
}
private void handleError(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// Read error attributes set by the container
Integer statusCode = (Integer) request.getAttribute(
"javax.servlet.error.status_code");
String message = (String) request.getAttribute(
"javax.servlet.error.message");
String requestUri = (String) request.getAttribute(
"javax.servlet.error.request_uri");
Throwable exception = (Throwable) request.getAttribute(
"javax.servlet.error.exception");
response.setContentType("text/html;charset=UTF-8");
response.setStatus(statusCode != null ? statusCode : 500);
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html><html><head><title>Error</title></head><body>");
out.println("<h1>Error " + statusCode + "</h1>");
out.println("<p>" + (message != null ? message : "An error occurred.") + "</p>");
if (requestUri != null) out.println("<p>URL: " + requestUri + "</p>");
if (exception != null) out.println("<p>Cause: " + exception.getMessage() + "</p>");
out.println("</body></html>");
}
}
Logging Exceptions
Always log exceptions in servlets. Use java.util.logging (built-in) or a logging framework like SLF4J/Logback. The log() method on GenericServlet writes to the container's log.
package com.example;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.*;
import java.util.logging.*;
@WebServlet("/process")
public class LoggingServlet extends HttpServlet {
// java.util.logging — no extra dependency needed
private static final Logger logger =
Logger.getLogger(LoggingServlet.class.getName());
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = request.getParameter("data");
logger.info("Processing request with data: " + data);
try {
// Simulate processing
if (data == null) throw new IllegalArgumentException("data is null");
processData(data);
logger.info("Processing completed successfully.");
response.sendRedirect("success.jsp");
} catch (IllegalArgumentException e) {
// Log at WARNING level — expected business error
logger.warning("Validation failed: " + e.getMessage());
request.setAttribute("error", e.getMessage());
request.getRequestDispatcher("form.jsp").forward(request, response);
} catch (Exception e) {
// Log at SEVERE level with full stack trace — unexpected error
logger.log(Level.SEVERE, "Unexpected error during processing", e);
// Also use GenericServlet.log() to write to container log
log("Critical error in LoggingServlet", e);
throw new ServletException("Processing failed", e);
}
}
private void processData(String data) {
// Business logic here
}
}
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.