Java for Web学习笔记(七四):国际化i18n(2)Locale Resolver
来源:互联网 发布:捷通华声语音合成软件 编辑:程序博客网 时间:2024/06/14 01:42
SessionLocaleResolver
判断locale,采用HTTP请求的Accept-Language,如果我们希望还能通过其他途径来设定locale,需要Locale Resolver,即解析出合适的locale,这样,我们就可以允许用户变更语言,而不局限于浏览器的设置。Spring提供了org.springframework.web.servlet.i18n.SessionLocaleResolver,依次检查:
- 首先检查session中的SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME的值,如果有,采用此值
- 然后检查SessionLocaleResolver的defaultLocale属性,如果有,采用此值
- 返回HttpServletRequest的getLocale(),也就是HTTP请求中的Accept-Language的值。
设置Locale Resolver
我们将Locale Resolver设置在Dispatch servlet context中,允许不同的Dispatch servlet context具有不同的解释器。public class SerlvetContextConfiguration extends WebMvcConfigurerAdapter{ ... ... @Bean public LocaleResolver localeResolver(){ //名字必须为localeResolver return new SessionLocaleResolver(); }}
用户自定义语言的小例子
用户设定某用语言后,我们希望用户接下来访问的页面都采用该语言的本地化方式。➤ 采用session存放用户的Locale,小例子中该Locale的获取采用URL参数方式。@RequestMapping(value = "/test", method = RequestMethod.GET)public String test(Map<String, Object> model,HttpServletRequest request,HttpServletResponse response, @RequestParam(value="locale", required=false) String localeStr){ setUserLocale(request,response,localeStr); ... ...}//-- 【1】使用session中设置SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME属性方式private void setUserLocale(HttpServletRequest request,String localeStr){ Locale locale = getLocaleFromStr(localStr); if(locale == null) return; HttpSession session = request.getSession(true); session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);}//--【方式二】使用LocaleResolver的setLocale方法进行设置。@Inject private LocaleResolver localeresolver;private void setUserLocale(HttpServletRequest request,HttpServletResponse response,String localeStr){ Locale locale = getLocaleFromStr(localStr); if(locale == null) return; this.localeresolver.setLocale(request, response, locale);}private Locale getLocaleFromStr(String str){ if(str == null) return null; String[] p = StringUtils.split(str, "_"); Locale locale ; switch(p.length){ case 2: return new Locale(p[0], p[1]); break; case 3: return new Locale(p[0], p[1], p[2]); break; default: return new Locale(p[0]); } }
方式一等同于localeResolver采用sessionLocaleResolver的情况,即如果用户设置了某种语言,就在session中设置SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME属性,用户后续的访问均采用该语言。对于其他的locale Resolver,如果是CookieLocaleResolver,则我们可以在Cookie中看到相关的设置。
我们注意到locale resolver是在Dispatcher servlet上下文的bean,如果有某些静态的jsp,不经过spring的dispatcher,就不会使用该resolver,也就是用户设置了语言后,对这些jsp无效。
不经过Dispatcher servlet处理的jsp如何使用locale resolver
这种jsp通常就是某些静态页面。在上次学习中,提及了两个方法,对于采用spring tag的方式,并没能使用locale resolver,即使我们将localeResovler设置在root context,测试也未能通过。在这种情况下,我们需要使用Filter的方式。public class JstlLocalizationContextFilter implements Filter { ... ... /** 不采用inject是因为Filter是作为root context的bean,因此只能加载root的bean, * 而local resolver bean是在dispather context定义的,无法加载,所以重新生成一个来用。 */ private LocaleResolver localeResolver= new SessionLocaleResolver(); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, localeResolver); JstlUtils.exposeLocalizationContext((HttpServletRequest)request, this.jstlMessageSource ); chain.doFilter(request, response); }}
使用拦截器:LocaleChangeInterceptor
在上面的小例子中,我们是手动在Controller的代码中对某个url的请求进行检查,并根据sessionLocaleResolver的原理对session进行了设置。如果这个执行并不是仅限于某个url,而是任意的可以的,我们会想到filter。Spring提供了要给非常类似的概念:拦截器(Interceptor),可以拦截任何经过DispatcherServlet的请求,可以在Interceptor内直接使用Bean(想想在filter中使用的麻烦)。
Spring提供了LocaleChangeInterceptor,如果请求中带有locale参数,就存放在session,配合sessionLocalResolver完成国际化,一般LocaleChangeInterceptor和sessionLocalResolver是一起使用的。
@Configuration@EnableWebMvc@ComponentScan( basePackages = "com.wrox.site", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(Controller.class))public class ServletContextConfiguration extends WebMvcConfigurerAdapter{ /* 添加连接器重写WebMvcConfigurerAdapter的方法,因此我们必须要标记@EnableWebMvc,如果没有,将不起所用。 * Interceptor有几个重要的方法: * - preHandle() : DispatcherServlet收到请求,在controller具体处理handler之前调用 * - postHandle():handler返回,但在view渲染之前 * - afterCompletion():view渲染之后,离开DispatcherServlet之前 */ @Override public void addInterceptors(InterceptorRegistry registry) { super.addInterceptors(registry); registry.addInterceptor(new LocaleChangeInterceptor()); } @Bean public LocaleResolver localeResolver(){ return new SessionLocaleResolver(); } ... ...}
将LocaleChangeInterceptor加入拦截器后,我们任意(需要经过DispatchServlet)的请求加上参数locale=en,则定位到basename_en.properties文件,如果是locale=en_US,将定位到basename_en_US.properties文件。如果我们需要对LocaleChangeInterceptor做一些定制,例如不采用缺省的locale,采用lang,代码如下:
@Configuration@EnableWebMvc@ComponentScan( basePackages = "com.wrox.site", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(Controller.class))public class ServletContextConfiguration extends WebMvcConfigurerAdapter{ @Override public void addInterceptors(InterceptorRegistry registry) { super.addInterceptors(registry); LocaleChangeInterceptor lci = new MyLocaleChangeInterceptor(); lci.setParamName("lang"); registry.addInterceptor(lci); } ... ...}
CookieLocaleResolver
使用seesion locale resovler有一个缺点,它是基于session的,而我们希望能基于登录的用户,用户设置过语言(作为用户的属性),只要佢登录,就显示想用的语言。用户的属性在登录后,常以Principal的方式携带。这时我们可以使用CookieLocaleResolver。
自定义CookieLocaleResolver
public class UserCookieLocaleResolver extends CookieLocaleResolver{ //【1】resolveLocale()修改的将是response中的Content-Language header,但不决策选择哪个资源。书中例子只给出resolveLocale(),抓包也看到返回的内容语言消息头变化,就是似乎不变更资源,这个问题查了很久,需要另外通过resolveLocaleContext()来影响资源的选择。 @Override public Locale resolveLocale(HttpServletRequest request) { Principal user = request.getUserPrincipal(); Locale locale = getLocaleFromPricipal(request); if(locale != null) return locale; else return super.resolveLocale(request); } //【2】resolveLocaleContext()处理实际选择的资源,但不修改响应的Content-Language @Override public LocaleContext resolveLocaleContext(HttpServletRequest request) { Locale locale = simulatePricipal(request.getUserPrincipal()); if(locale != null){ return new LocaleContext() { @Override public Locale getLocale() { return locale; } }; }else{ return super.resolveLocaleContext(request); } } private Locale getLocaleFromPricipal(HttpServletRequest request){ ...... }}
手动设置语言
可以通过url加上参数设置语言,如果localeResolver是CookieLocaleReslover,则我们可以看到在响应中设置Cookie。浏览器在后续的请求中Cookie会携带org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE信息。
TimeZone
转换为当地时区也是个麻烦事情,Spring没有时区相关的解析器,可以利用LocaleContextHolder来存放Timezone。
//从请求中获取TimeZone,如果没有返回nullTimeZone tz = RequestContextUtils.getTimeZone(request);//利用LocaleContextHolder来设置或者读取TimezoneLocaleContextHolder.setTimeZone(timezone);TimeZone timezone = LocaleContextHolder.getTimeZone();
在JSTL中使用TimeZone,可参见http://blog.csdn.net/flowingflying/article/details/52744823
主题 Theme
Spring提供主体的概念,主体是CCS,JS,图片等其他资源的集合。设置主题是很有帮助的,有些语言的顺序是从右到左( 我们可以使用java.awt.ComponentOrientation的getOrientation(Locale)来获取语言的方向),这些需要CSS来处理。
和locale类似,Spring提供ThemeResolvers(包含SessionThemeResolver和CookieThemeResolver)来为用户选择合适的主题,提供 ThemeChangeInterceptor ,当用户在请求参数中设置选择的主题,转变为该主题。提供ResourceBundleThemeSource和ResourceBundleMessageSource类似,使用<spring:theme>。
我们可以自定义ThemResolver,是之和locale关联,根据locale来决定使用主题。
相关文章相关链接: 我的Professional Java for Web Applications相关文章
- Java for Web学习笔记(七四):国际化i18n(2)Locale Resolver
- Java for Web学习笔记(七五):国际化i18n(3)异常显示的国际化
- Java for Web学习笔记(七三):国际化i18n(1)使用Spring框架MessageSource
- Java for Web学习笔记(七六):国际化i18n(4)其他
- Java for Web学习笔记(四七):WebSocket(4)Java Client和二进制消息
- java web学习总结31:国际化(i18n)
- Struts2学习笔记----国际化(I18N)(一)
- Java Struts2 本地化/国际化(i18n)浅析
- Java的国际化支持(I18N问题)
- Android 国际化(i18n)
- QT国际化(i18n)
- Android 国际化(i18n)
- Rails国际化(i18n)
- 应用国际化(i18n)
- 国际化(i18n)
- Java Web学习笔记(七)struts2
- Java for Web学习笔记(四):Servlet(2)HelloServlet
- Java for Web学习笔记(四四):WebSocket(1)演化历程
- C#中获取系统时间的一种方法
- WebSocket安卓客户端实现详解(二)--客户端发送请求
- 【剑指Offer】面试题57:删除链表中重复的结点
- 欢迎使用CSDN-markdown编辑器
- UILabel 详解
- Java for Web学习笔记(七四):国际化i18n(2)Locale Resolver
- iframe在ios滑动不顺畅
- 【Machine Learning】笔记:SVM
- 课程设计--简易电话簿
- 欢迎使用CSDN-markdown编辑器
- 进程之间的通信方式
- UIScrollView基础篇
- CentOS、Ubuntu、Debian三个linux比较异同
- 《机器学习》读书笔记 2 前言