这一步做好后,我们开始要做自定义国际化切换的功能。这个功能网上搜到的内容都是错误,所以特此在此记录下,以方便后来人。
网上很多说自定义国际化切换只要修改保存在session中的struts2国际化常量的值“WW_TRANS_I18N_LOCALE”就行了。
实际上时完全错误,我们先看看struts2国际化的步骤:
1、判断struts.locale属性(在struts.properties)是否有值,如果有值,将这个值转换为Locale对象保存到ActionContext中。
2、如果没有设置struts.locale,从浏览器发送的请求报头里获得语言信息,创建Locale对象,保存到ActionContext中。
3、I18nInterceptor拦截器获取名为request_locale请求参数的值,如果这个值存在则创建以这个值的Locale对象,然后将这个对象作为session的属性(WW_TRANS_I18N_LOCALE)保存,并保存到ActionContext中。
在修改session的WW_TRANS_I18N_LOCALE值和request_locale等无效之后,发现程序始终是只会读取浏览器发送过来的区域信息。估计这是struts2国际化得BUG了。
知道了struts2的原理后,就好解决,我们现在要做的就是用用户自定义切换的国际化区域信息来替代浏览器请求报头里的语言信息。
先写一个过滤器,代码如下:
public class I18nFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest r = (HttpServletRequest) req; MyRequestWrapper request = new MyRequestWrapper(r); filterChain.doFilter(request, resp); } }
配置为拦截所有请求
<filter> <filter-name>i18nFilter</filter-name> <filter-class>com.xxx.common.filter.I18nFilter</filter-class> </filter> <filter-mapping> <filter-name>i18nFilter</filter-name> <url-pattern>*</url-pattern> </filter-mapping>
这个拦截器的关键就是使用httpRequestWrapper,保装request。
这个包装器代码如下:
public class MyRequestWrapper extends HttpServletRequestWrapper { private Locale locale = null; public MyRequestWrapper(HttpServletRequest request) { super(request); HttpSession session = request.getSession(); locale = (Locale) session.getAttribute("WW_TRANS_I18N_LOCALE"); } /** * struts2的BUG,如果重定向的话,国际化默认取HTTP请求头中的参数 替换HTTP请求参数 **/ @Override public String getHeader(String name) { String value = super.getHeader(name); if ("Accept-Language".equals(name) && locale != null) { value = locale.getLanguage() + "_" + locale.getCountry() + value.substring(6, value.length()); } return value; } @Override public Locale getLocale() { if (locale != null) { return locale; } return super.getLocale(); } }
这个request包装器主要作用就是从session里获得区域对象,并修改请求报头,从而实现了自定义国际化切换。
如果本方法有问题或者各位有更好的方法,请告知。谢谢