Как я могу получить код статуса HTTP из ServletResponse в ServletFilter?

Я пытаюсь сообщить о каждом коде состояния HTTP, возвращенном из моего webapp. Однако код статуса не представляется доступным через ServletResponse, или даже если я передал его HttpServletResponse. Есть ли способ получить доступ к этому значению в ServletFilter?

Во-первых, вам нужно сохранить код состояния в доступном месте. Лучше всего обернуть ответ с вашей реализацией и сохранить его там:

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

Чтобы использовать эту оболочку, вам нужно добавить фильтр сервлетов, могли ли вы делать свои отчеты:

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

Начиная с сервлета 3.0 существует HttpServletResponse#getStatus() .

Итак, если есть возможность для обновления, перейдите на Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6 и т. Д.), И вам не нужна shell.

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

Также необходимо включить оболочку для #sendRedirect, и было бы лучше инициализировать статус «200», а не «0»,

 private int httpStatus = SC_OK; ... @Override public void sendRedirect(String location) throws IOException { httpStatus = SC_MOVED_TEMPORARILY; super.sendRedirect(location); } 

Одна вещь, отсутствующая в ответе Дэвида выше, заключается в том, что вы также должны переопределить другую форму sendError:

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

Напишите HttpServletResponseWrapper и переопределите все методы setStatus (), sendError () и sendRedirect (), чтобы регистрировать все. Напишите фильтр, который меняет вашу оболочку для объекта ответа при каждом запросе.

Помимо ответа Дэвида, вы также захотите переопределить метод сброса:

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

… а также устаревший setStatus (int, String)

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

Если вы застряли в старом контейнере, то альтернативное решение для Дэвида Рабиновица, которое использует фактический код состояния (в случае его изменения после его установки с помощью обертки):

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

Предупреждение: множество предположений иерархии classов при использовании скрытого отражения и самоанализа для получения частных значений данных.

Давайте будем гением компьютера.