Spring security + i18n = как заставить их работать вместе?

Мой первый вопрос здесь, и я постараюсь быть конкретным. Я совсем новичок в Spring и пытаюсь создать довольно простую систему бронирования (но это на самом деле не имеет значения). Важно то, что я создаю некий базовый шаблон, который потом буду заполнять реальными веб-страницами. Приложение работает на hibernate, mysql, я также настроил i18n и spring security. Проблема в том, что я не могу изменить локаль. Единственное, что работает, это изменение локали по умолчанию. Сначала я много рылся в интернете и обнаружил, что использование i18n вместе с spring security сложнее, чем обычно. Я выяснил, что мне нужен дополнительный фильтр:

<filter>
    <filter-name>localizationFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>localizationFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Я выяснил, что этот фильтр действительно обрабатывается перед фильтром безопасности, но он не разбирает запрос в форме: http://someserver.com/bla/home?locale=en. Я отладил его и кажется, что он не создан для такой цели (а это то, что мне нужно). Это взято из весеннего примера "contacts", однако в этом примере я не смог найти никакого кода, который был бы нацелен на изменение языка. В результате это просто не работает. Он всегда пытается изменить локаль на ту, которая используется по умолчанию. Хорошая новость заключается в том, что если в режиме отладки я вручную меняю locale-to-set на какой-нибудь другой, то все работает нормально, так что я почувствовал надежду в своем сердце... ;-)

Затем я нашел другой способ - создание собственного фильтра. Что я сделал, так это объединил найденный пример (не помню автора) со способом создания RequestContextFilter. Ведь RequestContextFilter работает нормально - просто не разбирает мои запросы. Вот код нового фильтра:

public class InternationalizationFilter extends OncePerRequestFilter {

@Override
public void destroy() {
    // TODO Auto-generated method stub

}


@Override
protected void doFilterInternal(final HttpServletRequest request,
        final HttpServletResponse response, final FilterChain filterChain)
        throws ServletException, IOException {
    final String newLocale = request.getParameter("locale");
    if (newLocale != null) {
        final Locale locale = StringUtils.parseLocaleString(newLocale
                .toLowerCase());
        LocaleContextHolder.setLocale(locale);
    }
    try {
        filterChain.doFilter(request, response);
    } finally {

        LocaleContextHolder.resetLocaleContext();
    }
}

}

Как видите, параметр запроса locale разобран и локаль установлена. Есть 2 проблемы: 1. После отправки запроса xxxxx?locale=en создается Locale без атрибута "country" (установлен только язык). Честно говоря, я не знаю, является ли это проблемой - возможно, нет. 2. Более серьезной проблемой является то, что он не работает... то есть он находится в правильном месте в цепочке фильтров (перед фильтром безопасности), он создает правильную локаль и устанавливает ее точно так же, как RequestContextFilter... но он просто не работает.

Я буду очень рад, если кто-нибудь подскажет мне, как заставить i18n работать с spring-security на основе моего примера или любого другого...

Спасибо!

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Я провел несколько экспериментов, и похоже, что экземпляр Locale из запроса является каким-то специфическим.

Посмотрите на этот код (модифицирован класс RequestContextFilter):

    @Override
protected void doFilterInternal(final HttpServletRequest request,
        final HttpServletResponse response, final FilterChain filterChain)
        throws ServletException, IOException {

    final ServletRequestAttributes attributes = new ServletRequestAttributes(
            request);
    final Locale l = Locale.GERMAN;
    final Locale l2 = request.getLocale();
    LocaleContextHolder.setLocale(l,
            this.threadContextInheritable);
    RequestContextHolder.setRequestAttributes(attributes,
            this.threadContextInheritable);
    if (logger.isDebugEnabled()) {
        logger.debug("Bound request context to thread: " + request);
    }
(...)

if to this method: LocaleContextHolder.setLocale(l, this.threadContextInheritable); Я передаю локаль 'l', но это не работает вообще. То есть локаль не меняется, даже если она явно изменена. С другой стороны, если я передаю туда Locale 'l2', которая изменена на немецкую (в режиме отладки), она работает отлично!

Это означает, что по какой-то причине экземпляр Locale из request.getLocale() как-то предпочитается, возможно, что-то происходит позже в коде, чего я не знаю/не понимаю...

Пожалуйста, дайте мне знать, как я должен использовать этот i18n вместе с безопасностью, потому что я дошел до точки, где я должен признать, что я понятия не имею, что происходит...

-====-======-======--=======-====

Окончательное решение/ответ (но все еще с небольшим вопросом) Благодаря Ральфу мне удалось решить мою проблему. Ранее я шел в неправильном направлении, но сгенерированный roo проект подтолкнул меня вперед. Похоже, что я продолжал добавлять перехватчик неправильным/неточным способом (предыдущий код):

<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <property name="defaultLocale" value="pl"/>
</bean>
<bean id="handlerMapping"
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors">
        <ref bean="localeChangeInterceptor" />
    </property>
</bean>

Таким образом перехватчик никогда не вызывался по какой-то причине.

После изменения interceptor def на:

<mvc:interceptors>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
</mvc:interceptors>

<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <property name="defaultLocale" value="pl"/>
</bean>

<bean id="handlerMapping"
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
</bean>

... он стал работать нормально без каких-либо других изменений в security/web.xml.

Теперь проблема исчезла, однако я не уверен, что произошло. Насколько я понимаю, во втором примере (тот, который работает) я сделал перехватчик "глобальным". Но почему перехватчик, определенный в первом примере, не работает? Подскажите?

Еще раз спасибо за помощь! N.

6
задан Nirwan 13 December 2011 в 21:13
поделиться