Sobes.tech
Middle

Ինչպե՞ս մշակել հավելվածում այն արտակարգ իրավիճակները, որոնք նետվել են այլ սերվլետով։

sobes.tech AI

Պատասխան AI-ից

Ստանդարտ սերվլետային ճարտարապետությունում, մեկ սերվլետով արտածված արտահայտությունները չեն կարող ուղղակիորեն մշակվել մյուս սերվլետով ընթացիկ հարցում։ Յուրաքանչյուր հարցում մշակվում է առանձին հոսքով, որը կապված է մեկ սերվլետի կյանքի ցիկլի հետ։

Այնուամենայնիվ, նման վարքագիծ հասնելու համար կարող եք օգտագործել հետևյալ մոտեցումները:

  1. Սերվլետների կոնտեյների սխալի մշակման մեխանիզմի օգտագործում:

    • web.xml-ում կարող եք կարգավորել սխալի էջեր որոշակի արտահայտությունների կամ HTTP վիճակային կոդերի համար։ Սերվլետ կոնտեյները (օրինակ, Tomcat, Jetty) կուղղորդի այս էջը արտահայտության դեպքում։
    • Սխալի էջում (որը կարող է լինել այլ սերվլետ կամ JSP) կարող եք ստանալ արտահայտության մասին տեղեկատվություն հարցման ատրիբուտներից։
    • Ատրիբուտները հասանելի են request.getAttribute()-ով։ Կլուպները ներառում են 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>Սխալ!</h2>");
            out.println("<p>Կարգավիճակի կոդը: " + statusCode + "</p>");
            out.println("<p>Սերվլետը: " + (servletName != null ? servletName : "Անհայտ") + "</p>");
            out.println("<p>Հարցման URI: " + (requestUri != null ? requestUri : "Անհայտ") + "</p>");
            if (throwable != null) {
                out.println("<p>Արտահայտության տեսակ: " + throwable.getClass().getName() + "</p>");
                out.println("<p>Հաղորդագրություն: " + throwable.getMessage() + "</p>");
                // Կարող եք նաև արտածել stack trace-ը դետալների համար
                // throwable.printStackTrace(out);
            }
            out.println("</body></html>");
        }
    }
    
  2. Սերվլետների ֆիլտրերի օգտագործում:

    • Ֆիլտրն կարող է շրջապատել doFilter շղթան try-catch բլոկով:
    • Եթե սերվլետը շղթայում արտածում է արտահայտություն, ֆիլտրն այն կփողվի:
    • catch բլոկում ֆիլտրն կարող է ինքնուրույն մշակել արտահայտությունը կամ ուղղորդել հարցումը հատուկ սխալի մշակողին (միգուցե այլ սերվլետ) 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("/*") // Ֆիլտրն կիրառվում է բոլոր հարցումների վրա
    public class ExceptionHandlingFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // Ֆիլտրի ինիցիալիզացիա
        }
    
        @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); // Հարցման փոխանցում շղթայում
            } catch (Exception e) {
                // Արտածված արտահայտության բռնում
                System.err.println("Սխալ է տեղի ունեցել հարցման մշակման ժամանակ URI: " + httpRequest.getRequestURI());
                e.printStackTrace(); // Լոգավորում
    
                // Սխալի մասին տեղեկատվության պահպանում
                httpRequest.setAttribute("javax.servlet.error.exception", e);
                httpRequest.setAttribute("javax.servlet.error.message", e.getMessage());
                httpRequest.setAttribute("javax.servlet.error.request_uri", httpRequest.getRequestURI());
                // Կարող եք կարգավորել կարգավիճակի կոդը, եթե այն հայտնի է
                httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500 Internal Server Error
    
                // Մղում սխալի մշակման սերվլետ
                httpRequest.getRequestDispatcher("/errorServlet").forward(httpRequest, httpResponse);
            }
        }
    
        @Override
        public void destroy() {
            // Ֆիլտրի ռեսուրսների մաքրում
        }
    }
    

Այս երկու մոտեցումները թույլ են տալիս կենտրոնականացնել սխալի մշակումը և կանխել ստանդարտ սխալի հաղորդագրությունների ցուցադրությունը։ Առաջին մեթոդը (web.xml-ով) ավելի պարզ է հիմնական սխալի կոդերի և արտահայտությունների տեսակների համար։ Երկրորդ մեթոդը (ֆիլտրով) ավելի ճկուն է, թույլ տալով ավելացնել լրացուցիչ լոգիկա (օրինակ, լոգավորում) նախքան ուղղորդումը կամ մշակումը։