2009-08-19 16 views

Odpowiedz

80

Najpierw należy zapisać kod statusu w dostępnym miejscu. Najlepiej owinąć odpowiedź z implementacji i utrzymania go tam:

public class StatusExposingServletResponse extends HttpServletResponseWrapper { 

    private int httpStatus; 

    public StatusExposingServletResponse(HttpServletResponse response) { 
     super(response); 
    } 

    @Override 
    public void sendError(int sc) throws IOException { 
     httpStatus = sc; 
     super.sendError(sc); 
    } 

    @Override 
    public void sendError(int sc, String msg) throws IOException { 
     httpStatus = sc; 
     super.sendError(sc, msg); 
    } 


    @Override 
    public void setStatus(int sc) { 
     httpStatus = sc; 
     super.setStatus(sc); 
    } 

    public int getStatus() { 
     return httpStatus; 
    } 

} 

W celu korzystania z tej owijki, trzeba dodać filtr serwletu, w którym można wykonać sprawozdawczym:

public class StatusReportingFilter implements Filter { 

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
     StatusExposingServletResponse response = new StatusExposingServletResponse((HttpServletResponse)res); 
     chain.doFilter(req, response); 
     int status = response.getStatus(); 
     // report 
    } 

    public void init(FilterConfig config) throws ServletException { 
     //empty 
    } 

    public void destroy() { 
     // empty 
    } 

} 
+8

w przypadku ktoś nie czyta do końca strony, uważaj na komentarz Joela poniżej, aby ustawić domyślny status = 200, a także nadpisać sendRedirect (..) –

+1

To było bardzo pomocne dla starszej wersji Tomcat, która jest w Servlet spec 2.4. Dziękuję Ci! – user3621633

+0

response.sendRedirect() podaje nielegalneStateExcpetion. Nadpisałem sendRedirect także jako komentarz Joela –

6

Napisz HttpServletResponseWrapper i zastąp wszystkie metody setStatus(), sendError() i sendRedirect(), aby rejestrować wszystko. Napisz filtr, który zamienia twoje opakowanie obiektu odpowiedzi na każde żądanie.

11

Jedną rzeczą, brakuje odpowiedzi Dawida powyższego jest to, że należy również zastąpić inną formę sendError:

@Override 
public void sendError(int sc, String msg) throws IOException { 
    httpStatus = sc; 
    super.sendError(sc, msg); 
} 
+0

Dzięki William, dodałem to do mojej próbki. –

59

od Servlet 3.0, istnieje HttpServletResponse#getStatus().

Tak więc, jeśli jest miejsce na uaktualnienie, zaktualizuj do Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, itd.) I nie potrzebujesz opakowania.

chain.doFilter(request, response); 
int status = ((HttpServletResponse) response).getStatus(); 
+0

to miło mieć. dziekuje panu! – asgs

+0

Co powiecie na tomcat 6 ?? wersja serwletu jest poniżej 3 –

+0

@Sam: nie jest to jedyna odpowiedź na to pytanie. Aktualnie zaakceptowana odpowiedź jest tak stara, że ​​nadal dotyczy Tomcat 6. – BalusC

14

Należy również zawierać otoki dla #sendRedirect, i byłoby lepiej, aby zainicjować status na „200” zamiast „0”

private int httpStatus = SC_OK; 

... 

@Override 
public void sendRedirect(String location) throws IOException { 
    httpStatus = SC_MOVED_TEMPORARILY; 
    super.sendRedirect(location); 
} 
+0

Widzę sytuacje, w których miejsce docelowe mapowania filtra może mieć wpływ na to, czy zostanie włączony wyzwalający kod. Na przykład, kolejny filtr może nie zawijać twojej odpowiedzi, ale raczej ją zastąpić. Poza tymi scenariuszami, czy kod statusu można ustawić na odpowiedź bez wywoływania wariantów setStatus, sendError lub sendRedirect? Czy to dlatego zainicjalizowałeś status na 200? – 1in9ui5t

0

Jeśli utkniesz ze starszym pojemniku następnie zastępcy rozwiązanie David Rabinowitz, który wykorzystuje kod stanu faktycznego (w przypadku zmiany po to jest ustawiana za pomocą owijki) wynosi:

public class StatusExposingServletResponse extends HttpServletResponseWrapper { 

    public StatusExposingServletResponse(HttpServletResponse response) { 
     super(response); 
    } 

    @Override 
    public void sendError(int sc) throws IOException { 
     super.sendError(sc); 
    } 

    @Override 
    public void sendError(int sc, String msg) throws IOException { 
     super.sendError(sc, msg); 
    } 

    @Override 
    public void setStatus(int sc) { 
     super.setStatus(sc); 
    } 

    public int getStatus() { 
     try { 
      ServletResponse object = super.getResponse(); 

      // call the private method 'getResponse' 
      Method method1 = object.getClass().getMethod("getResponse"); 
      Object servletResponse = method1.invoke(object, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method2 = servletResponse.getClass().getMethod("getResponse"); 
      Object parentResponse = method2.invoke(servletResponse, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method3 = parentResponse.getClass().getMethod("getStatus"); 
      int httpStatus = (Integer) method3.invoke(parentResponse, new Object[] {}); 

      return httpStatus; 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
      return HttpServletResponse.SC_ACCEPTED; 
     } 
    } 

    public String getMessage() { 
     try { 
      ServletResponse object = super.getResponse(); 

      // call the private method 'getResponse' 
      Method method1 = object.getClass().getMethod("getResponse"); 
      Object servletResponse = method1.invoke(object, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method2 = servletResponse.getClass().getMethod("getResponse"); 
      Object parentResponse = method2.invoke(servletResponse, new Object[] {}); 

      // call the parents private method 'getResponse' 
      Method method3 = parentResponse.getClass().getMethod("getReason"); 
      String httpStatusMessage = (String) method3.invoke(parentResponse, new Object[] {}); 

      if (httpStatusMessage == null) { 
       int status = getStatus(); 
       java.lang.reflect.Field[] fields = HttpServletResponse.class.getFields(); 

       for (java.lang.reflect.Field field : fields) { 
        if (status == field.getInt(servletResponse)) { 
         httpStatusMessage = field.getName(); 
         httpStatusMessage = httpStatusMessage.replace("SC_", ""); 
         if (!"OK".equals(httpStatusMessage)) { 
          httpStatusMessage = httpStatusMessage.toLowerCase(); 
          httpStatusMessage = httpStatusMessage.replace("_", " "); 
          httpStatusMessage = capitalizeFirstLetters(httpStatusMessage); 
         } 

         break; 
        } 
       } 
      } 

      return httpStatusMessage; 
     } 
     catch (Exception e) { 
      e.printStackTrace(); 
      return ""; 
     } 
    } 

    private static String capitalizeFirstLetters(String s) { 

     for (int i = 0; i < s.length(); i++) { 
      if (i == 0) { 
       // Capitalize the first letter of the string. 
       s = String.format("%s%s", Character.toUpperCase(s.charAt(0)), s.substring(1)); 
      } 

      if (!Character.isLetterOrDigit(s.charAt(i))) { 
       if (i + 1 < s.length()) { 
        s = String.format("%s%s%s", s.subSequence(0, i + 1), 
          Character.toUpperCase(s.charAt(i + 1)), 
          s.substring(i + 2)); 
       } 
      } 
     } 

     return s; 

    } 

    @Override 
    public String toString() { 
     return this.getMessage() + " " + this.getStatus(); 
    } 

} 

Warning: wiele założeń hierarchii klasowej podczas korzystania SNE jako odbicie i introspekcję, aby uzyskać prywatne wartości danych.

6

Oprócz odpowiedzi Dawida, będziesz także chcą zastąpić metodę Reset:

@Override 
public void reset() { 
    super.reset(); 
    this.httpStatus = SC_OK; 
} 

... a także przestarzałe setStatus (int, string)

@Override 
public void setStatus(int status, String string) { 
    super.setStatus(status, string); 
    this.httpStatus = status; 
} 
Powiązane problemy