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("მოთხოვნის დამუშავების დროს მოხდა შეცდომა: " + 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-ის საშუალებით) უფრო მარტივია ძირითადი სტატუს კოდებისა და გამონაკლისების ტიპების დამუშავებისთვის. მეორე მეთოდი (ფილტრის საშუალებით) უფრო მოქნილია, რადგან საშუალებას გაძლევთ დამატებითი ლოგიკა შეიტანოთ (მაგალითად, ლოგირება) და გადამისამართებამდე ან დამუშავების დროს.