欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

struts2默认拦截器之i18n

程序员文章站 2022-05-28 17:32:46
...

在struts2的struts-default.xml中定义了一个name为i18n拦截器,实现类是com.opensymphony.xwork2.interceptor.I18nInterceptor,它的作用是根据用户请求设置session的语言环境。该拦截器有三个参数,parameterName,requestOnlyParameterName,attributeName;前两个是设置用户语言环境参数的name值,最后一个是设置session中保存语言环境对象的key值;三者的默认值分别为:request_locale,request_only_locale,WW_TRANS_I18N_LOCALE(后续讨论中将使用默认值)。用户请求中request_locale参数的优先级大于request_only_locale,语言环境是从request_locale参数中获得,该语言环境对象将会以key值为WW_TRANS_I18N_LOCALE保存到session中,语言环境是从request_only_locale总获得,设置值在当前请求中起效。请求中不存在request_locale和request_only_locale参数,将会从session中获取key值为WW_TRANS_I18N_LOCALE的对象,若该对象为null或者不是Locale类型,将使用ActionContext.getLocale()方法获取语言环境。当执行完以上一系列逻辑后,将会把当前上下文的语言环境设置为获取到的对象。以上逻辑的代码如下:

 

public String intercept(ActionInvocation invocation) throws Exception {
        if (LOG.isDebugEnabled()) {
            LOG.debug("intercept '"
                    + invocation.getProxy().getNamespace() + "/"
                    + invocation.getProxy().getActionName() + "' { ");
        }
        //get requested locale
        Map<String, Object> params = invocation.getInvocationContext().getParameters();
        boolean storeInSession = true;
        Object requested_locale = findLocaleParameter(params, parameterName);
        if (requested_locale == null) {
            requested_locale = findLocaleParameter(params, requestOnlyParameterName);
            if (requested_locale != null) {
                storeInSession = false;
            }
        }
        //save it in session
        Map<String, Object> session = invocation.getInvocationContext().getSession();
        Locale locale = null;
        if (requested_locale != null) {
            locale = (requested_locale instanceof Locale) ?
                    (Locale) requested_locale : LocalizedTextUtil.localeFromString(requested_locale.toString(), null);
        }
        if (session != null) {
            synchronized (session) {
                if (locale == null) {
                    storeInSession = false;
                    // check session for saved locale
                    Object sessionLocale = session.get(attributeName);
                    if (sessionLocale != null && sessionLocale instanceof Locale) {
                        locale = (Locale) sessionLocale;
                    } else {
                        // no overriding locale definition found, stay with current invocation (=browser) locale
                        locale = invocation.getInvocationContext().getLocale();
                    }
                }
                if (storeInSession) {
                    session.put(attributeName, locale);
                }
            }
        }
        saveLocale(invocation, locale);
        final String result = invocation.invoke();
        return result;
    }
 

笔者之前有个项目需要添加国际化功能,固定支持某几种语言,当系统不支持请求中的语言环境时,需要设置为项目配置的默认语言环境,因此笔者写了一个struts2的拦截器来完成,代码如下:

 

import java.util.Locale;
import java.util.Map;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.I18nInterceptor;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
import com.warning.system.Constants;
import com.warning.system.lang.WarningLogger;

/**
 * 为struts2配置语言环境
 * 
 */
@SuppressWarnings("serial")
public class DefaultLanguageInterceptor extends AbstractInterceptor {

	private static WarningLogger log = WarningLogger
			.getWarningLogger(DefaultLanguageInterceptor.class);

	@SuppressWarnings("unchecked")
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		Locale locale = null;
		// 获取request的参数列表
		Map<String, Object> params = ServletActionContext.getRequest()
				.getParameterMap();
		// 获取session
		Map<String, Object> session = invocation.getInvocationContext()
				.getSession();
		// 获取request中request_locale参数值
		Object requested_locale = findLocaleParameter(params,
				I18nInterceptor.DEFAULT_PARAMETER);
		log.debug("获取request Parameter中的" + I18nInterceptor.DEFAULT_PARAMETER
				+ "参数值");
		// 如果request中request_locale参数值为null,则获取request_only_locale参数值
		if (requested_locale == null) {
			log.debug("request Parameter中不存在"
					+ I18nInterceptor.DEFAULT_PARAMETER + "参数值");
			log.debug("获取request Parameter中的"
					+ I18nInterceptor.DEFAULT_REQUESTONLY_PARAMETER + "参数值");
			requested_locale = findLocaleParameter(params,
					I18nInterceptor.DEFAULT_REQUESTONLY_PARAMETER);
			// 如果request中request_only_locale参数值为null,则从session中获取WW_TRANS_I18N_LOCALE值,该值是struts2
			// 框架中的i18n拦截器根据request的request_locale参数值设置的语言环境
			if (requested_locale == null) {
				log
						.debug("request Parameter中不存在"
								+ I18nInterceptor.DEFAULT_REQUESTONLY_PARAMETER
								+ "参数值");
				log.debug("获取session中的"
						+ I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE + "参数值");
				requested_locale = session
						.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE);
				// 如果session中不存在WW_TRANS_I18N_LOCALE值,则获取ActionContext的语言环境
				if (requested_locale == null) {
					log
							.debug("session中不存在"
									+ I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE
									+ "参数值");
					log.debug("获取ActionContext中的Locale值");
					requested_locale = invocation.getInvocationContext()
							.getLocale();
				}
			}
		}
		// 如果requested_locale为null,则将locale设置为国际化资源文件(config.properties.language)中配置的(warning.language.default)默认语言环境;
		// 如果requested_locale类型为Locale,则直接赋值给locale;
		// 如果上述两项都不匹配,则根据requested_locale初始化一个Locale对象
		locale = (requested_locale instanceof Locale) ? (Locale) requested_locale
				: (requested_locale != null ? LocalizedTextUtil
						.localeFromString(requested_locale.toString(),
								Constants.getLanguages().getDefaultLocale())
						: Constants.getLanguages().getDefaultLocale());
		// 如果国际化资源文件中配置的语言环境不包含上述获取的语言环境,则将locale赋值为国际化资源文件中配置的默认语言环境
		if (!Constants.getLanguages().getLocales().containsValue(locale)) {
			log.info("国际化资源文件中配置的语言环境不包含 " + locale + ",将locale赋值为配置的默认语言");
			locale = Constants.getLanguages().getDefaultLocale();
		}
		// 设置ActionContext的语言环境
		log.info("将struts2的语言环境设置为:" + locale);
		invocation.getInvocationContext().setLocale(locale);
		return invocation.invoke();
	}

	/**
	 * 从Map集合中获取指定元素的值
	 * 
	 * @param params
	 * @param parameterName
	 * @return
	 */
	private Object findLocaleParameter(Map<String, Object> params,
			String parameterName) {
		Object requested_locale = params.get(parameterName);
		if (requested_locale != null && requested_locale.getClass().isArray()
				&& ((Object[]) requested_locale).length == 1) {
			requested_locale = ((Object[]) requested_locale)[0];
		}
		return requested_locale;
	}
}
 

struts2配置文件内容如下:

 

	<package name="warning-default" extends="struts-default"
		abstract="true">
		<interceptors>
			<interceptor name="defaultLanguage" class="com.warning.module.language.interceptor.DefaultLanguageInterceptor" />
			<interceptor-stack name="warningDefaultStack">
				<interceptor-ref name="defaultStack" />
				<interceptor-ref name="defaultLanguage" /> 
			</interceptor-stack>
		</interceptors>
		<default-interceptor-ref name="warningDefaultStack" />
		<global-results>
			<result name="login">/WEB-INF/jsp/sys/login.jsp</result>
		</global-results>
	</package>

 设置完成后,运行项目,将浏览器语言环境设置为系统不支持的一种,然后访问页面,奇迹出现了,页面中竟然出现了两种语言……笔者以为是上面的拦截器逻辑出现了错误,将代码审查了一遍发现没有错误,正在纠结的时候突然灵光一现,发现struts2配置中的默认拦截器defaultStack在defaultLanguage之前,

这样将会先执行默认拦截器栈中的各个拦截器,然后才会执行笔者定义的拦截器defaultLanguage,将两者位置调换

 

	<package name="warning-default" extends="struts-default"
		abstract="true">
		<interceptors>
			<interceptor name="defaultLanguage" class="com.warning.module.language.interceptor.DefaultLanguageInterceptor" />
			<interceptor-stack name="warningDefaultStack">
				<interceptor-ref name="defaultLanguage" />
				<interceptor-ref name="defaultStack" />
			</interceptor-stack>
		</interceptors>
		<default-interceptor-ref name="warningDefaultStack" />
		<global-results>
			<result name="login">/WEB-INF/jsp/sys/login.jsp</result>
		</global-results>
	</package>
 

重新运行项目,访问,奇迹再一次发生了,页面中的信息全部成为了项目的默认语言。为什么调换一下两个拦截器的位置就可以了呢,原因在于执行默认拦截器栈中的拦截器时,语言环境尚未设置为项目默认的语言环境,拦截器栈中的各拦截器会根据当前语言环境去获取国际化资源,当执行了defaultLanguage拦截器,系统语言环境变成了项目默认语言环境,

这样在页面中会根据项目默认语言环境来获取国际化资源,便出现了页面中存在两种语言的情况。

但如果用户请求中request_locale或者request_only_locale参数值对应语言环境是项目不支持的,那么页面中还会出现两种语言的情况,因此需要根据笔者上述的拦截器逻辑来重写i18n拦截器。

 

 

版权所有,转载请标明出处:http://blogwarning.iteye.com/blog/1336685