Мой первый вопрос здесь, и я постараюсь быть конкретным. Я совсем новичок в 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.