messagesource - Spring security+i18n=¿cómo hacer que funcione junto?
spring mvc message properties (2)
Mi primera pregunta aquí y trataré de ser específico. Soy bastante nuevo en Spring y estoy intentando crear un sistema de reservas bastante simple (pero esto en realidad no importa). Lo que importa es que estoy creando una plantilla básica que luego completaré con páginas web reales. La aplicación funciona en hibernate, mysql, también configuro i18n y seguridad de primavera. El problema es que no puedo cambiar mi configuración regional. Lo único que funciona es cambiar el predeterminado. Primero busqué Web MUCHO y descubrí que el uso de un i18n junto con la seguridad de primavera es más complicado que habitualmente. Lo que descubrí es que necesito tener un filtro adicional:
<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>
Lo que descubrí es que este filtro se procesó antes que el de seguridad, sin embargo, no analiza la solicitud en un formulario: http://someserver.com/bla/home?locale=en
. Lo depuré y parece que no fue creado para tal fin (y eso es lo que necesito). Esto se toma de los "contactos" de la muestra de primavera, sin embargo, en este ejemplo, no pude encontrar ningún código que realmente estuviera destinado a cambiar el idioma. El efecto es que simplemente no funciona. Siempre trata de cambiar la configuración regional a la predeterminada. La buena noticia es que si en el modo de depuración manualmente cambiaba la configuración regional a otra, funcionaba bien, así que sentí la esperanza en mi corazón ... ;-)
Entonces he encontrado otra forma: creando nuestro propio filtro. Lo que hice fue fusionar el ejemplo encontrado (no recuerdo al autor) junto con la forma en que se crea RequestContextFilter
. Después de todo, RequestContextFilter
funciona bien, simplemente no analice mis solicitudes. Ese es el código del nuevo filtro:
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();
}
}
}
Como puede ver, la configuración regional del parámetro de solicitud se analiza y se establece la configuración regional. Hay 2 problemas: 1. Después de enviar la solicitud xxxxx?locale=en
, crea la xxxxx?locale=en
regional sin el atributo "país" (solo se establece el idioma). Para ser honesto, no sé si hay algún problema, tal vez no. 2. El problema más grave es que no funciona ... quiero decir que está en el lugar correcto en la cadena de filtros (antes de la de seguridad), produce la configuración regional correcta y la configura de la misma manera que RequestContextFilter
. .pero simplemente no funciona.
Estaría muy feliz si alguien me dejara saber cómo hacer que i18n trabaje con seguridad de primavera basado en mi ejemplo dado o cualquier otro ...
¡Gracias!
INFORMACIÓN ADICIONAL: Hice algunos experimentos y parece que la instancia de Locale de la solicitud es de alguna manera específica.
Mire este código (modificó la clase 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);
}
(...)
si a este método: LocaleContextHolder.setLocale(l, this.threadContextInheritable);
Paso el locale ''l'' no funciona en absoluto. Quiero decir que la configuración regional no cambia aunque haya cambiado explícitamente. Por otro lado, si paso allí Locale ''l2'' que está modificado para alemán (en modo de depuración) ¡funciona bien!
Esto significa que, por alguna razón, la instancia de Locale de request.getLocale()
es favorecida de alguna manera, tal vez algo esté sucediendo más adelante en el código que no entiendo ...
Por favor, hágamelo saber cómo debo usar este i18n junto con la seguridad porque llegué al punto en el que debo admitir que no tengo idea de lo que está pasando ...
- ==== - ====== - ====== - ======= - ====
SOLUCIÓN / RESPUESTA FINAL (pero aún con poca pregunta) Gracias a Ralph logré solucionar mi problema. Anteriormente iba en la dirección equivocada, pero el proyecto generado por roo me empujó hacia adelante. Parece que seguí agregando el interceptor de una manera incorrecta / no precisa (código anterior):
<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>
De esta forma, el interceptor nunca fue invocado por alguna razón.
Después de cambiar la def del interceptor a:
<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>
... comenzó a funcionar bien sin ningún otro cambio en security / web.xml.
Ahora el problema se ha ido, sin embargo, no estoy seguro de qué pasó. Por lo que entiendo en el segundo ejemplo (el que funciona) hice el interceptor "global". Pero ¿por qué el interceptor definido en el primer ejemplo no funcionó? ¿Alguna pista?
Gracias de nuevo por la ayuda! NORTE.
- Después de enviar la solicitud xxxxx? Locale = en, crea la configuración regional sin el atributo "país" (solo se establece el idioma).
Es el comportamiento esperado. En java hay algún tipo de jerarquía. El lenguaje es más general que el país.
La idea detrás es que puede tener, por ejemplo, el texto en el lenguaje más común pero algunas unidades (como la moneda) en los archivos específicos del país.
@see: http://java.sun.com/developer/technicalArticles/Intl/IntlIntro/
- El problema más serio es que no funciona ...
¡Debería funcionar sin ninguna implementación hecha a mano!
Debe registrar el Interceptor de cambio local y debe establecer permitAll para la página de inicio de sesión.
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/>
</mvc:interceptors>
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
Para ver este ejemplo en ejecución, crea un proyecto roo con ese script roo:
// Spring Roo 1.1.5.RELEASE [rev d3a68c3] log opened at 2011-12-13 09:32:23
project --topLevelPackage de.humanfork.test --projectName localtest --java 6
persistence setup --database H2_IN_MEMORY --provider HIBERNATE
ent --class ~.domain.Stuff
field string --fieldName title
controller all --package ~.web
security setup
web mvc language --code de
web mvc language --code es
¡Entonces solo debe cambiar los filtros de seguridad de los patrones intersept-url como los que he mostrado arriba ( applicationContext-security.xml
)!
Ahora tiene una aplicación donde el usuario puede cambiar su local a través del interceptor de cambio local en la aplicación (cuando el usuario está conectado) y cuando no está conectado (en la página de inicio de sesión)
Tuve un problema similar con la localización cuando estaba trabajando con la aplicación GWT. El problema que noté fue que cuando mapeamos
<filter-mapping>
<filter-name>localizationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
para el filtro, las solicitudes de imágenes pares se enrutan al filtro. En ocasiones, estas solicitudes omiten el parámetro de configuración regional y, por lo tanto, cuando varias solicitudes llegan al filtro, el parámetro Configuración regional no. Por lo tanto, tan pronto como recibí el parámetro locale, lo puse en una sesión. Registre todos los encabezados de solicitud y los valores, y puede encontrar la causa raíz.