Java for Web学习笔记:国际化i18n Locale Resolver

转载:http://blog.csdn.net/flowingflying/article/details/76758577

SessionLocaleResolver

  判断locale,采用HTTP请求的Accept-Language,如果我们希望还能通过其他途径来设定locale,需要Locale Resolver,即解析出合适的locale,这样,我们就可以允许用户变更语言,而不局限于浏览器的设置。Spring提供了org.springframework.web.servlet.i18n.SessionLocaleResolver,依次检查:

  1. 首先检查session中的SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME的值,如果有,采用此值
  2. 然后检查SessionLocaleResolver的defaultLocale属性,如果有,采用此值
  3. 返回HttpServletRequest的getLocale(),也就是HTTP请求中的Accept-Language的值。

设置Locale Resolver

  我们将Locale Resolver设置在Dispatch servlet context中,允许不同的Dispatch servlet context具有不同的解释器。
[java]  view plain  copy
  1. public class SerlvetContextConfiguration extends WebMvcConfigurerAdapter{  
  2.     ... ...  
  3.     @Bean  
  4.     public LocaleResolver localeResolver(){ //名字必须为localeResolver  
  5.         return new SessionLocaleResolver();  
  6.     }  
  7. }  

用户自定义语言的小例子

  用户设定某用语言后,我们希望用户接下来访问的页面都采用该语言的本地化方式。  采用session存放用户的Locale,小例子中该Locale的获取采用URL参数方式。
[java]  view plain  copy
  1. @RequestMapping(value = "/test", method = RequestMethod.GET)  
  2. public String test(Map<String, Object> model,HttpServletRequest request,HttpServletResponse response,  
  3.               @RequestParam(value="locale", required=false) String localeStr){          
  4.        setUserLocale(request,response,localeStr);  
  5.        ... ...  
  6. }  
  7.   
  8. //-- 【1】使用session中设置SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME属性方式  
  9. private void setUserLocale(HttpServletRequest request,String localeStr){  
  10.        Locale locale = getLocaleFromStr(localStr);  
  11.        if(locale == null)  
  12.               return;  
  13.   
  14.        HttpSession session = request.getSession(true);  
  15.        session.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);  
  16. }  
  17.   
  18. //--【方式二】使用LocaleResolver的setLocale方法进行设置。  
  19. @Inject private LocaleResolver localeresolver;  
  20.   
  21. private void setUserLocale(HttpServletRequest request,HttpServletResponse response,String localeStr){  
  22.        Locale locale = getLocaleFromStr(localStr);  
  23.        if(locale == null)  
  24.               return;  
  25.        this.localeresolver.setLocale(request, response, locale);  
  26. }  
  27.   
  28. private Locale getLocaleFromStr(String str){  
  29.        if(str == null)  
  30.               return null;  
  31.        String[] p = StringUtils.split(str, "_");  
  32.        Locale locale ;  
  33.        switch(p.length){  
  34.        case 2:  
  35.            return new Locale(p[0], p[1]);  
  36.            break;  
  37.        case 3:  
  38.            return new Locale(p[0], p[1], p[2]);  
  39.            break;  
  40.        default:  
  41.            return new Locale(p[0]);  
  42.        }    
  43. }  

  方式一等同于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的方式。
[java]  view plain  copy
  1. public class JstlLocalizationContextFilter implements Filter {  
  2.     ... ...  
  3.     /** 不采用inject是因为Filter是作为root context的bean,因此只能加载root的bean, 
  4.       * 而local resolver bean是在dispather context定义的,无法加载,所以重新生成一个来用。 */  
  5.     private LocaleResolver localeResolver= new SessionLocaleResolver();  
  6.   
  7.     @Override  
  8.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)   
  9.                          throws IOException, ServletException {  
  10.         request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, localeResolver);  
  11.         JstlUtils.exposeLocalizationContext((HttpServletRequest)request, this.jstlMessageSource );  
  12.         chain.doFilter(request, response);  
  13.     }  
  14. }  

使用拦截器:LocaleChangeInterceptor

  在上面的小例子中,我们是手动在Controller的代码中对某个url的请求进行检查,并根据sessionLocaleResolver的原理对session进行了设置。如果这个执行并不是仅限于某个url,而是任意的可以的,我们会想到filter。Spring提供了要给非常类似的概念:拦截器(Interceptor),可以拦截任何经过DispatcherServlet的请求,可以在Interceptor内直接使用Bean(想想在filter中使用的麻烦)。

  Spring提供了LocaleChangeInterceptor,如果请求中带有locale参数,就存放在session,配合sessionLocalResolver完成国际化,一般LocaleChangeInterceptor和sessionLocalResolver是一起使用的。

[java]  view plain  copy
  1. @Configuration  
  2. @EnableWebMvc  
  3. @ComponentScan(  
  4.        basePackages = "com.wrox.site",  
  5.        useDefaultFilters = false,  
  6.        includeFilters = @ComponentScan.Filter(Controller.class))  
  7. public class ServletContextConfiguration extends WebMvcConfigurerAdapter{  
  8.     /* 添加连接器重写WebMvcConfigurerAdapter的方法,因此我们必须要标记@EnableWebMvc,如果没有,将不起所用。 
  9.      * Interceptor有几个重要的方法: 
  10.      *  - preHandle() : DispatcherServlet收到请求,在controller具体处理handler之前调用 
  11.      *  - postHandle():handler返回,但在view渲染之前 
  12.      *  - afterCompletion():view渲染之后,离开DispatcherServlet之前 */  
  13.     @Override  
  14.     public void addInterceptors(InterceptorRegistry registry) {          
  15.         super.addInterceptors(registry);  
  16.         registry.addInterceptor(new LocaleChangeInterceptor());  
  17.     }  
  18.   
  19.     @Bean  
  20.     public LocaleResolver localeResolver(){  
  21.         return new SessionLocaleResolver();  
  22.     }  
  23.     ... ...  
  24. }  

  将LocaleChangeInterceptor加入拦截器后,我们任意(需要经过DispatchServlet)的请求加上参数locale=en,则定位到basename_en.properties文件,如果是locale=en_US,将定位到basename_en_US.properties文件。如果我们需要对LocaleChangeInterceptor做一些定制,例如不采用缺省的locale,采用lang,代码如下:

[java]  view plain  copy
  1. @Configuration  
  2. @EnableWebMvc  
  3. @ComponentScan(  
  4.        basePackages = "com.wrox.site",  
  5.        useDefaultFilters = false,  
  6.        includeFilters = @ComponentScan.Filter(Controller.class))  
  7. public class ServletContextConfiguration extends WebMvcConfigurerAdapter{  
  8.     @Override  
  9.     public void addInterceptors(InterceptorRegistry registry) {      
  10.         super.addInterceptors(registry);  
  11.         LocaleChangeInterceptor lci = new MyLocaleChangeInterceptor();  
  12.         lci.setParamName("lang");  
  13.         registry.addInterceptor(lci);  
  14.     }  
  15.   
  16.      ... ...  
  17. }  

CookieLocaleResolver

  使用seesion locale resovler有一个缺点,它是基于session的,而我们希望能基于登录的用户,用户设置过语言(作为用户的属性),只要佢登录,就显示想用的语言。用户的属性在登录后,常以Principal的方式携带。这时我们可以使用CookieLocaleResolver。

自定义CookieLocaleResolver

[java]  view plain  copy
  1. public class UserCookieLocaleResolver extends CookieLocaleResolver{  
  2.     //【1】resolveLocale()修改的将是response中的Content-Language header,但不决策选择哪个资源。书中例子只给出resolveLocale(),抓包也看到返回的内容语言消息头变化,就是似乎不变更资源,这个问题查了很久,需要另外通过resolveLocaleContext()来影响资源的选择。  
  3.     @Override  
  4.     public Locale resolveLocale(HttpServletRequest request) {  
  5.         Principal user = request.getUserPrincipal();  
  6.         Locale locale = getLocaleFromPricipal(request);  
  7.    
  8.         if(locale != null)  
  9.             return locale;  
  10.         else  
  11.             return super.resolveLocale(request);  
  12.     }  
  13.   
  14.     //【2】resolveLocaleContext()处理实际选择的资源,但不修改响应的Content-Language  
  15.     @Override  
  16.     public LocaleContext resolveLocaleContext(HttpServletRequest request) {  
  17.         Locale locale = simulatePricipal(request.getUserPrincipal());          
  18.         if(locale != null){  
  19.             return new LocaleContext() {  
  20.   
  21.                 @Override  
  22.                 public Locale getLocale() {  
  23.                     return locale;  
  24.                 }  
  25.             };  
  26.   
  27.         }else{          
  28.             return super.resolveLocaleContext(request);  
  29.         }  
  30.     }  
  31.   
  32.     private Locale getLocaleFromPricipal(HttpServletRequest request){  
  33.          ......  
  34.     }  
  35. }  

手动设置语言

可以通过url加上参数设置语言,如果localeResolver是CookieLocaleReslover,则我们可以看到在响应中设置Cookie。浏览器在后续的请求中Cookie会携带org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE信息。

TimeZone

  转换为当地时区也是个麻烦事情,Spring没有时区相关的解析器,可以利用LocaleContextHolder来存放Timezone。

[java]  view plain  copy
  1. //从请求中获取TimeZone,如果没有返回null  
  2. TimeZone tz = RequestContextUtils.getTimeZone(request);  
  3.   
  4. //利用LocaleContextHolder来设置或者读取Timezone  
  5. LocaleContextHolder.setTimeZone(timezone);  
  6. 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相关文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值