HttpServletResponse, содержащийся в фильтре сервлета, не выполняет перенаправление

Я использую Spring 4.0.6 в приложении сервлета. У меня есть абстрактный базовый контроллер с некоторыми общими методами для всех моих контроллеров.

Одним из таких методов является редирект. Я хочу иметь метод с подписью

redirect(String path)

Чтобы отправить перенаправление, я использую

response.sendRedirect(response.encodeRedirectURL(path));

Поскольку я хотел бы, чтобы сигнатуры методов были короткими и чистыми, мне нужно получить доступ к объекту ответа внутри метода суперкласса.

Чтобы сделать это, я последовал предложению, найденному в Интернете, и определил фильтр сервлета с помощью ThreadLocal HttpServletResponse.

public class ResponseFilter extends OncePerRequestFilter {

    private static final ThreadLocal<HttpServletResponse> responses = new ThreadLocal<HttpServletResponse>();

    public static HttpServletResponse getResponse() {
        return responses.get();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            responses.set(response);
        } finally {
            try {
                filterChain.doFilter(request, response);
            } finally {
                responses.remove();
            }
        }
    }
}

Поскольку я использую безопасность Spring с конфигурацией Java, я добавляю этот фильтр в свой подкласс WebSecurityConfigurerAdapter:

.addFilterAfter(rf, SwitchUserFilter.class)

Обратите внимание, что я также попытался добавить фильтр первым в цепочке фильтров и вместо этого попытался использовать Interceptor. Все с теми же результатами.

Я сравнил хэш-коды на объектах ответа, и, насколько я могу судить, хэш-коды совпадают, но перенаправление, похоже, игнорируется. Я также просмотрел идентификаторы объектов в точках останова в Eclipse, и снова у меня есть совпадение. Симптом заключается в том, что Spring DispatcherServlet входит в processDispatchResult и, кажется, думает, что ему нужно разрешить представление. Это представление не существует, так как я ожидаю перенаправления:

javax.servlet.ServletException: File &quot;/WEB-INF/views/application/redirecttest.jsp&quot; not found

Я заметил, что если я добавлю объект ответа обратно в сигнатуру метода контроллера сопоставления запросов, перенаправление суперкласса, похоже, работает (хотя я вообще не использую объект ответа метода контроллера).

К сожалению, такое поведение воспроизводится как на Mac, так и на Linux. Я использую Tomcat 7 в качестве контейнера.


person Marceau    schedule 26.07.2014    source источник
comment
Это поведение контролируется ModelAndViewContainer.setRequestHandled(), но я не понимаю, как вы можете получить к нему доступ за пределами HandlerMethodArgumentResolver (так это работает, когда вы добавляете объект ответа в подпись) или HandlerMethodReturnValueHandler.   -  person axtavt    schedule 26.07.2014
comment
Можете ли вы показать нам контроллер и его родительский класс?   -  person Sotirios Delimanolis    schedule 26.07.2014


Ответы (1)


Ваш фильтр должен работать нормально, но вы столкнулись с другой проблемой. Если вы используете представления (как вы, кажется, делаете в примере), вам нужно вернуть представление перенаправления из вашего контроллера, чтобы принудительно перенаправить; просто указание объекту ответа на перенаправление не сработает, потому что инфраструктура Spring MVC попытается выполнить свою задачу (т.е. разрешение просмотра) до того, как ответ будет возвращен в контейнер сервлетов.

Например, если вы используете соглашение для возврата имени представления в виде строки из метода вашего контроллера, вам нужно сделать следующее в вашем контроллере:

@RequestMapping("/redirectTest")
public String redirectTest() {
  return "redirect:http://www.example.com";
}
person marthursson    schedule 26.07.2014