2009-08-19 15 views

risposta

80

Innanzitutto, è necessario salvare il codice di stato in un luogo accessibile. Il migliore per avvolgere la risposta con l'implementazione e tenerlo lì:

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; 
    } 

} 

Per poter utilizzare questo wrapper, è necessario aggiungere un filtro servlet, dove si può fare il vostro report:

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

nel caso in cui qualcuno non legge fino alla fine della pagina, guarda il commento di Joel qui sotto per impostare anche lo stato di default = 200 e anche per sovrascrivere sendRedirect (..) –

+1

Questo è stato estremamente utile per una versione precedente di Tomcat che è sulla specifica Servlet 2.4. Grazie! – user3621633

+0

response.sendRedirect() sta dando illegalStateExcpetion. Ho sovrascritto sendRedirect anche come commento di Joel –

6

Scrivere un HttpServletResponseWrapper e sovrascrivere tutti i metodi setStatus(), sendError() e sendRedirect() per registrare tutto. Scrivi un filtro che scambia il tuo wrapper per l'oggetto risposta su ogni richiesta.

11

una cosa che manca dalla risposta di David sopra è che si dovrebbe anche ignorare l'altra forma di sendError:

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

Grazie William, l'ho aggiunto al mio esempio –

59

dal Servlet 3.0, c'è un HttpServletResponse#getStatus().

Quindi, se c'è spazio per l'aggiornamento, eseguire l'aggiornamento a Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, ecc.) E non è necessario un wrapper.

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

è bello avere. grazie Signore! – asgs

+0

Che dire di Tomcat 6 ?? la versione servlet è inferiore a 3 –

+0

@ Sam: questa non è l'unica risposta alla domanda. La risposta attualmente accettata è così vecchia che si applica ancora a Tomcat 6. – BalusC

14

anche bisogno di includere un wrapper per #sendRedirect, e sarebbe meglio per inizializzare lo stato di '200', piuttosto che '0'

private int httpStatus = SC_OK; 

... 

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

Sono in grado di vedere le situazioni in cui la posizione di mappatura del filtro può influire sull'attivazione del codice di override. Ad esempio, un filtro successivo potrebbe non avvolgere la tua risposta ma piuttosto sostituirla. Oltre a questi scenari, il codice di stato può essere impostato sulla risposta senza richiamare le varianti setStatus, sendError o sendRedirect? È per questo che hai inizializzato lo stato a 200? – 1in9ui5t

0

Se sei bloccato con un contenitore più vecchio allora una soluzione alternativa a David Rabinowitz che utilizza il codice di stato attuale (nel caso in cui cambia dopo che è stato impostato utilizzando l'involucro) è:

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(); 
    } 

} 

Attenzione: un sacco di ipotesi della gerarchia di classe quando si utilizza END riflessione a fuoco e introspezione per ottenere valori di dati privati.

6

Oltre alla risposta di David, si potrà anche eseguire l'override del metodo di reset:

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

... così come il deprecato setStatus (int, String)

@Override 
public void setStatus(int status, String string) { 
    super.setStatus(status, string); 
    this.httpStatus = status; 
} 
Problemi correlati