Sobes.tech
Middle

Cum să gestionezi în aplicație excepțiile care au fost aruncate de un alt servlet?

sobes.tech AI

Răspuns de la AI

În arhitectura standard a servlets, excepțiile aruncate de un servlet nu pot fi gestionate direct de către alt servlet în cadrul aceleiași cereri. Fiecare cerere este procesată de un thread separat, asociat cu ciclul de viață al unui singur servlet.

Cu toate acestea, se poate realiza un comportament similar utilizând următoarele abordări:

  1. Utilizarea mecanismului de gestionare a erorilor al containerului de servlets:

    • În web.xml se pot configura pagini de eroare pentru anumite tipuri de excepții sau coduri de stare HTTP. Containerul de servlets (de exemplu, Tomcat, Jetty) va redirecționa către această pagină în cazul unei excepții.
    • Pe pagina de eroare (care poate fi un alt servlet sau JSP) se poate obține informație despre excepție din atributele cererii.
    • Atributele sunt accesibile prin request.getAttribute(). Cheile includ 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>Eroare!</h2>");
            out.println("<p>Cod stare: " + statusCode + "</p>");
            out.println("<p>Servlet: " + (servletName != null ? servletName : "Necunoscut") + "</p>");
            out.println("<p>URI cerere: " + (requestUri != null ? requestUri : "Necunoscut") + "</p>");
            if (throwable != null) {
                out.println("<p>Tip excepție: " + throwable.getClass().getName() + "</p>");
                out.println("<p>Mesaj: " + throwable.getMessage() + "</p>");
                // Se poate afișa și stack trace pentru depanare
                // throwable.printStackTrace(out);
            }
            out.println("</body></html>");
        }
    }
    
  2. Utilizarea filtrelor de servlets:

    • Un filtru poate înveli lanțul doFilter într-un bloc try-catch.
    • Dacă un servlet din lanț aruncă o excepție, filtrul o va captura.
    • În blocul catch, filtrul poate fie să gestioneze excepția singur, fie să redirecționeze cererea către un handler de erori special (posibil alt servlet) folosind 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("/*") // Filtru aplicat tuturor cererilor
    public class ExceptionHandlingFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // Inițializare filtru
        }
    
        @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); // Trimiterea cererii mai departe în lanț (la servlet sau alt filtru)
            } catch (Exception e) {
                // Capturarea excepției aruncate de servlet sau alt filtru
                System.err.println("A apărut o eroare în procesarea cererii pentru URI: " + httpRequest.getRequestURI());
                e.printStackTrace(); // Logare eroare
    
                // Salvarea informației despre eroare pentru handler
                httpRequest.setAttribute("javax.servlet.error.exception", e);
                httpRequest.setAttribute("javax.servlet.error.message", e.getMessage());
                httpRequest.setAttribute("javax.servlet.error.request_uri", httpRequest.getRequestURI());
                // Se poate seta codul de stare, dacă este cunoscut
                httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500 Internal Server Error
    
                // Redirecționare către servlet-ul de gestionare a erorilor
                httpRequest.getRequestDispatcher("/errorServlet").forward(httpRequest, httpResponse);
            }
        }
    
        @Override
        public void destroy() {
            // Curățarea resurselor filtrului
        }
    }
    

Această abordare permite centralizarea gestionării erorilor și evitarea afișării mesajelor standard de eroare ale containerului utilizatorului. Prima metodă (prin web.xml) este mai simplă pentru gestionarea de bază a codurilor de stare și tipurilor de excepții. A doua metodă (prin filtru) oferă mai multă flexibilitate, permițând executarea de logică suplimentară (de exemplu, logare) înainte de redirecționare sau gestionare.