2009-08-19 9 views

Respuesta

80

En primer lugar, tiene que guardar el código de estado en un lugar accesible. La mejor manera de envolver la respuesta con su puesta en práctica y mantenerlo allí:

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

} 

Para utilizar este contenedor, es necesario agregar un filtro de servlet, fuera usted puede hacer su reporte:

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

en el caso alguien no lee hasta el final de la página, ten cuidado con el comentario de Joel a continuación para establecer el estado predeterminado = 200 y también anular el envío de sendRedirect (..) –

+1

Esto fue sumamente útil para una versión anterior de Tomcat que está en la especificación de Servlet 2.4. ¡Gracias! – user3621633

+0

response.sendRedirect() está dando illegalStateExcpetion. He cancelado SendRedirect también como comentario de Joel –

6

Escribir una HttpServletResponseWrapper y anular todas las setStatus (sendError),(), métodos y sendRedirect() para registrar todo. Escriba un filtro que intercambia el contenedor para el objeto de respuesta en cada solicitud.

11

una cosa que falta de la respuesta de David anterior es que también se debe anular la otra forma de sendError:

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

Gracias William, lo he agregado a mi muestra –

59

desde Servlet 3.0, hay una HttpServletResponse#getStatus().

Por lo tanto, si hay espacio para la actualización, actualice a Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, etc.) y no necesita un contenedor.

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

que es bueno tener. ¡gracias Señor! – asgs

+0

¿Qué hay de Tomcat 6? la versión del servlet está debajo de 3 –

+0

@Sam: esta no es la única respuesta a la pregunta. La respuesta actualmente aceptada es tan antigua que todavía se aplica a Tomcat 6. – BalusC

14

también tienen que incluir un contenedor para #sendRedirect, y sería mejor para inicializar el estado a '200' en lugar de '0'

private int httpStatus = SC_OK; 

... 

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

Veo situaciones en las que su ubicación de asignación de filtros puede afectar si se activa su código de anulación. Por ejemplo, un filtro sucesivo puede no envolver su respuesta, sino reemplazarla. Además de esos escenarios, ¿se puede establecer el código de estado en la respuesta sin invocar las variantes setStatus, sendError o sendRedirect? ¿Es por eso que has inicializado el estado a 200? – 1in9ui5t

0

Si le pegan con un recipiente viejo entonces una solución alternativa a David Rabinowitz que utiliza el código de estado actual (en caso de que cambia después de que se ajusta con la envoltura) es:

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

} 

de advertencia: porciones de supuestos de la jerarquía de clases cuando utilizando SNE reflexión aky e introspección para llegar a los valores de datos privados.

6

Además de la respuesta de David, también querrá reemplazar el método de reset:

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

... así como la obsoleta setStatus (int, String)

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