Sobes.tech
Middle

Hogyan kezeljük az alkalmazásban azokat a kivételeket, amelyeket egy másik servlet dobott?

sobes.tech MI

Válasz az MI-től

A szabványos servlet architektúrában az egy servlet által dobott kivételek nem kezelhetők közvetlenül egy másik servlet által a jelenlegi kérés keretében. Minden kérés külön szálon kerül feldolgozásra, amely egy adott servlet életciklusához kapcsolódik.

Azonban elérhető hasonló viselkedés a következő megközelítésekkel:

  1. A servlet konténer hibakezelő mechanizmusának használata:

    • A web.xml-ben konfigurálhatók hibák oldalak bizonyos kivételtípusokra vagy HTTP státuszkódokra. A servlet konténer (pl. Tomcat, Jetty) átirányít erre az oldalra kivétel esetén.
    • A hibás oldal (amely lehet más servlet vagy JSP) hozzáférhet a kérés attribútumaihoz az exception információkhoz.
    • Az attribútumokat a request.getAttribute() segítségével érhetjük el. Kulcsok például: 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>Hiba!</h2>");
            out.println("<p>Státuszkód: " + statusCode + "</p>");
            out.println("<p>Servlet: " + (servletName != null ? servletName : "Ismeretlen") + "</p>");
            out.println("<p>Kérés URI: " + (requestUri != null ? requestUri : "Ismeretlen") + "</p>");
            if (throwable != null) {
                out.println("<p>Kivétel típusa: " + throwable.getClass().getName() + "</p>");
                out.println("<p>Üzenet: " + throwable.getMessage() + "</p>");
                // Stack trace kiírása hibakereséshez
                // throwable.printStackTrace(out);
            }
            out.println("</body></html>");
        }
    }
    
  2. Servlet szűrők használata:

    • Egy szűrő becsomagolhatja a doFilter láncot egy try-catch blokkba.
    • Ha a láncban a servlet kivételt dob, a szűrő elkapja azt.
    • A catch blokkban a szűrő vagy saját maga kezeli a kivételt, vagy átirányítja a kérést egy speciális hibakezelőhöz (pl. más servlethez) a request.getRequestDispatcher("/errorServlet").forward(request, response) segítségével.
    // 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("/*") // A szűrő minden kérésre alkalmazva
    public class ExceptionHandlingFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // Szűrő inicializálása
        }
    
        @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); // A kérés továbbítása a láncban (servlet vagy következő szűrő)
            } catch (Exception e) {
                // Kivétel elkapása, amit a servlet vagy a következő szűrő dobott
                System.err.println("Hiba történt a kérés feldolgozása során: " + httpRequest.getRequestURI());
                e.printStackTrace(); // Hibák naplózása
    
                // Információk mentése a hibakezelő számára
                httpRequest.setAttribute("javax.servlet.error.exception", e);
                httpRequest.setAttribute("javax.servlet.error.message", e.getMessage());
                httpRequest.setAttribute("javax.servlet.error.request_uri", httpRequest.getRequestURI());
                // Státuszkód beállítása, ha ismert
                httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500 belső szerverhiba
    
                // Átirányítás a hibakezelő servlethez
                httpRequest.getRequestDispatcher("/errorServlet").forward(httpRequest, httpResponse);
            }
        }
    
        @Override
        public void destroy() {
            // Erőforrások felszabadítása
        }
    }
    

Ezek a megközelítések lehetővé teszik a hibák központosított kezelését és megakadályozzák, hogy a konténer alapértelmezett hibajelzései jelenjenek meg a felhasználónak. Az első módszer (a web.xml-en keresztül) egyszerűbb az alapvető státuszkód és kivételtípus kezeléséhez. A második módszer (a szűrőn keresztül) nagyobb rugalmasságot biztosít, lehetővé téve további logika végrehajtását (pl. naplózás) az átirányítás vagy kezelés előtt.