我的第一个问题在这里,我会尽量具体。我对 Spring 很陌生,我正在尝试创建非常简单的预订系统(但这实际上并不重要)。重要的是我正在创建一些基本模板,然后我将用真实的网页填写。应用程序适用于 hibernate、mysql,我还设置了 i18n 和 spring 安全性。问题是我不能改变我的语言环境。唯一有效的是更改默认值。
首先,我浏览了很多 Web,我发现将 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
.我调试了它,它似乎不是为此目的而创建的(这就是我需要的)。这是从 spring 示例“联系人”中获取的,但是在此示例中,我找不到任何实际针对更改语言的代码。结果是它根本不起作用。它总是尝试将语言环境更改为我的默认语言环境。好消息是,如果在 Debug模式下,我手动将 locale-to-set 更改为其他区域设置,它运行良好,所以我心中充满希望......;-)
然后我找到了其他方法 - 通过创建我们自己的过滤器。我所做的是将找到的示例(不要记住作者)与方式合并在一起
RequestContextFilter
被 build 。毕竟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();
}
}
}
如您所见,请求参数语言环境已被解析并已设置语言环境。有2个问题:
1.发送请求后
xxxxx?locale=en
它创建没有“国家”属性的区域设置(仅设置语言)。老实说,我不知道这是否有任何问题 - 也许没有。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);
}
(...)
如果使用此方法:
LocaleContextHolder.setLocale(l, this.threadContextInheritable);
我通过语言环境'l'它根本不起作用。我的意思是即使你明确改变了语言环境也不会改变。另一方面,如果我通过了修改为德语的 Locale 'l2'(在 Debug模式下),它工作正常!
这意味着出于某种原因,来自
request.getLocale()
的 Locale 实例以某种方式受到青睐,也许稍后在代码中发生了一些我不知道/不明白的事情......请让我知道我应该如何将这个 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>
这样拦截器就不会因为某种原因被调用。
将拦截器 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。
最佳答案
- After sending request xxxxx?locale=en it creates Locale without "country" attribute (only language is set).
这是预期的行为。在java中有某种层次结构。
语言比国家更普遍。
背后的想法是,例如,您可以在更常见的语言中使用文本,但在国家/地区特定文件中使用某些单位(如货币)。
@见:http://java.sun.com/developer/technicalArticles/Intl/IntlIntro/
- The more serious problem is that it doesn't work...
它应该在没有任何手工实现的情况下工作!
需要注册Local Change Interceptor,登录页面需要设置permitAll。
<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>
要查看此示例的运行情况,请使用该 roo 脚本创建一个 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
然后您必须只更改安全过滤器 intersept-url 模式,就像我上面显示的那样 (
applicationContext-security.xml
)!现在您有一个应用程序,用户可以通过应用程序中的本地更改拦截器(当用户登录时)以及未登录时(在登录页面中)更改其本地
关于Spring security + i18n = 如何让它一起工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8478321/