Sobes.tech
Middle

Como tratar na aplicação as exceções que foram lançadas por outro servlet?

sobes.tech IA

Resposta da IA

Na arquitetura padrão de servlets, as exceções lançadas por um servlet não podem ser tratadas diretamente por outro servlet na mesma requisição. Cada requisição é processada numa thread separada associada ao ciclo de vida de um servlet.

No entanto, é possível alcançar um comportamento semelhante usando as seguintes abordagens:

  1. Utilização do mecanismo de tratamento de erros do contêiner de servlets:

    • No web.xml, pode-se configurar páginas de erro para tipos específicos de exceções ou códigos de estado HTTP. O contêiner de servlets (por exemplo, Tomcat, Jetty) redirecionará para essa página quando ocorrer uma exceção.
    • Na página de erro (que pode ser outro servlet ou JSP), pode-se obter informações sobre a exceção a partir dos atributos da requisição.
    • Os atributos estão disponíveis através de request.getAttribute(). As chaves incluem javax.servlet.error.exception, javax.servlet.error.exception_type, javax.servlet.error.message, javax.servlet.error.request_uri.
    <error-page>
        <exception-type>java.lang.RuntimeException</exception-type>
        <location>/errorServlet</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/errorServlet</location>
    </error-page>
    
    // ErrorServlet.java
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @WebServlet("/errorServlet")
    public class ErrorServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
            Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
            String servletName = (String) request.getAttribute("javax.servlet.error.servlet_name");
            String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri");
    
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html><body>");
            out.println("<h2>Erro!</h2>");
            out.println("<p>Código de estado: " + statusCode + "</p>");
            out.println("<p>Servlet: " + (servletName != null ? servletName : "Desconhecido") + "</p>");
            out.println("<p>URI da requisição: " + (requestUri != null ? requestUri : "Desconhecido") + "</p>");
            if (throwable != null) {
                out.println("<p>Tipo de exceção: " + throwable.getClass().getName() + "</p>");
                out.println("<p>Mensagem: " + throwable.getMessage() + "</p>");
                // Também é possível exibir a stack trace para depuração
                // throwable.printStackTrace(out);
            }
            out.println("</body></html>");
        }
    }
    
  2. Utilização de filtros de servlets:

    • Um filtro pode envolver a cadeia doFilter em um bloco try-catch.
    • Se um servlet na cadeia lançar uma exceção, o filtro a interceptará.
    • Dentro do bloco catch, o filtro pode tratar a exceção por si mesmo ou redirecionar a requisição para um manipulador de erros especial (possivelmente outro servlet) usando request.getRequestDispatcher("/errorServlet").forward(request, response).
    // ExceptionHandlingFilter.java
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebFilter("/*") // O filtro é aplicado a todas as requisições
    public class ExceptionHandlingFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // Inicialização do filtro
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;
    
            try {
                chain.doFilter(request, response); // Passa a requisição para o próximo na cadeia (servlet ou filtro)
            } catch (Exception e) {
                // Captura a exceção lançada pelo servlet ou filtro seguinte
                System.err.println("Ocorreu um erro ao processar a requisição para a URI: " + httpRequest.getRequestURI());
                e.printStackTrace(); // Registro do erro
    
                // Salvando informações do erro para o manipulador
                httpRequest.setAttribute("javax.servlet.error.exception", e);
                httpRequest.setAttribute("javax.servlet.error.message", e.getMessage());
                httpRequest.setAttribute("javax.servlet.error.request_uri", httpRequest.getRequestURI());
                // Pode-se definir um código de status se conhecido
                httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500 Internal Server Error
    
                // Redirecionando para o servlet de tratamento de erros
                httpRequest.getRequestDispatcher("/errorServlet").forward(httpRequest, httpResponse);
            }
        }
    
        @Override
        public void destroy() {
            // Limpeza de recursos do filtro
        }
    }
    

Essas duas abordagens permitem centralizar o tratamento de erros e evitar mostrar mensagens padrão de erro do contêiner ao usuário. A primeira forma (via web.xml) é mais simples para tratamento básico de códigos de estado e tipos de exceções. A segunda forma (via filtro) oferece maior flexibilidade, permitindo executar lógica adicional (por exemplo, registro) antes de redirecionar ou tratar.