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);
}
}
}
Define global error pages in web.xml to handle HTTP error codes and uncaught exceptions across the entire application. The tl-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 tl-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>");
}
}
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 tl-container log
log("Critical error in LoggingServlet", e);
throw new ServletException("Processing failed", e);
}
}
private void processData(String data) {
// Business logic here
}
}
Explore 500+ free tutorials across 20+ languages and frameworks.