Sobes.tech
Middle

Kā apstrādāt lietojumprogrammā izņēmumus, kurus ir izmetis cits servlet?

sobes.tech AI

Atbilde no AI

Standarta servletu arhitektūrā, izsviestās izņēmumi no viena servleta nevar tikt tieši apstrādāti cita servleta ietvaros pašreizējā pieprasījumā. Katrs pieprasījums tiek apstrādāts atsevišķā plūsmā, kas ir saistīta ar viena servleta dzīves ciklu.

Tomēr, lai sasniegtu līdzīgu uzvedību, var izmantot šādus pieejas veidus:

  1. Servletu kļūdu apstrādes mehānisma izmantošana:

    • web.xml var konfigurēt kļūdu lapas noteiktiem izņēmumu tipiem vai HTTP statusa kodiem. Servletu konteineris (piemēram, Tomcat, Jetty) novirzīs uz šo lapu, ja rodas izņēmums.
    • Kļūdu lapā (kas var būt cits servlets vai JSP) var iegūt informāciju par izņēmumu no pieprasījuma atribūtiem.
    • Atribūti ir pieejami caur request.getAttribute(). Atslēgas ietver 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>Kļūda!</h2>");
            out.println("<p>Statusa kods: " + statusCode + "</p>");
            out.println("<p>Servlets: " + (servletName != null ? servletName : "Nezināms") + "</p>");
            out.println("<p>Pieprasījuma URI: " + (requestUri != null ? requestUri : "Nezināms") + "</p>");
            if (throwable != null) {
                out.println("<p>Izņēmuma tips: " + throwable.getClass().getName() + "</p>");
                out.println("<p>Ziņojums: " + throwable.getMessage() + "</p>");
                // Var arī izvadīt stack trace
                // throwable.printStackTrace(out);
            }
            out.println("</body></html>");
        }
    }
    
  2. Servletu filtru izmantošana:

    • Filtrs var ietvert doFilter ķēdi try-catch blokā:
    • Ja servlets ķēdē tiek izsviesta izņēmums, filtrs to noķers:
    • catch blokā filtrs var vai nu apstrādāt izņēmumu pats, vai novirzīt pieprasījumu uz īpašu kļūdu apstrādes servletu, izmantojot 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("/*") // Tiek piemērots visiem pieprasījumiem
    public class ExceptionHandlingFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // Filtra inicializācija
        }
    
        @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); // Pārsūtīt pieprasījumu tālāk ķēdē
            } catch (Exception e) {
                // Noķert izņēmumu
                System.err.println("Notika kļūda pieprasījuma apstrādē: " + httpRequest.getRequestURI());
                e.printStackTrace(); // Žurnāls
    
                // Saglabāt kļūdas informāciju
                httpRequest.setAttribute("javax.servlet.error.exception", e);
                httpRequest.setAttribute("javax.servlet.error.message", e.getMessage());
                httpRequest.setAttribute("javax.servlet.error.request_uri", httpRequest.getRequestURI());
                // Iestatīt statusa kodu
                httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500
    
                // Pārsūtīt uz kļūdu apstrādes servletu
                httpRequest.getRequestDispatcher("/errorServlet").forward(httpRequest, httpResponse);
            }
        }
    
        @Override
        public void destroy() {
            // Filtra resursu atbrīvošana
        }
    }
    

Šie divi pieejas veidi ļauj centralizēt kļūdu apstrādi un novērst standarta kļūdu ziņojumu rādīšanu lietotājam. Pirmais veids (web.xml) ir vienkāršāks galvenajai statusa kodu un izņēmumu tipu apstrādei. Otrais veids (caur filtru) ir elastīgāks, ļaujot veikt papildu loģiku (piemēram, žurnālu) pirms novirzīšanas vai apstrādes.