struts2国际化开发详细过程

在看这篇文章之后,你必须要会struts2,否则 不建议继续看下去

struts2-core.jar下面的struts2-default.xml中的拦截器可以看到有一个拦截器"i18n",这个就是对当前语言环境进行拦截的。

   <interceptors>
            <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
            <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
            <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
            <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
            <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
            <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
            <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
            <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
            <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
            <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
            <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
            <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
            <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
            <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
            <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>

而且默认的defaultStack 也包含"i18n"这个拦截器的

   <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>

struts2只需要你在参数后面加上 ?request_locale=  相应的语言,在页面中通过

<s:property value="%{getText('B_HOME_TEXT_MAINPAGE')}"/> 

即可。

下面就来讲解一个实际开发的具体过程以及遇到的问题。


1.直接访问.jsp  不通过struts拦截器,那么你即使设置了语言,当前访问的页面还是原来的语言。因为你未通过“i18n”这个拦截器。

有的网站,在web.xml中配置了有默认的访问页面。一般是.jsp页面。

解决办法:让所有的访问必须通过struts2拦截器

a.打开web.xml

 <welcome-file-list>
    <welcome-file>index.action</welcome-file>
  </welcome-file-list>

改成index.action.

b.在webapp(或者webroot)目录下面建立一个空的名字叫做index.action的文件。至于为什么建立这个空的文件,因为web会去寻找这个文件,没有则报错(未研究过)

c.打开struts.xml

	<action name="index">
			<result>/index.jsp</result>
<!-- 			<interceptor-ref name="defaultStack" /> -->
		</action>

添加index.action.

上面三个步骤即完成了首页是通过action访问的,而不是通过.jsp访问的。

d.配置过滤器,让所有的访问必须是通过action形式,其它的访问,使其拒绝访问

package com.adcorp.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class ResourcesForbidFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest res = (HttpServletRequest) request;
		
		String url = res.getRequestURL().toString();
		if(url.endsWith(".jsp") || url.endsWith(".html") ){
			return;
		} else{
			chain.doFilter(request, response);
		}
	}

	@Override
	public void destroy() {
		
	}

}
e.在web.xml中配置过滤器

<filter>    
   <filter-name>Resources</filter-name>    
   <filter-class>com.adcorp.filter.ResourcesForbidFilter</filter-class>      
  </filter>    
 <filter-mapping>       
    <filter-name>Resources</filter-name>    
    <url-pattern>/*</url-pattern>    
  </filter-mapping>  

上面5步就解决了这个问题。

2.在js中不能使用struts2标签。

解决办法:通过自定义el表达式,在js中使用el表达式。(前提是js不是单独引入jsp中的,这个问题下面再讲)

自定义el表达式过程

a:编写java类,里面的方法必须是静态的。

package com.adcorp.tag;

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

import com.opensymphony.xwork2.ActionContext;

/**
 * 自定义el标签${myFn:getLanguage('F_LOGIN_JS_INPUT_YOUR_USERNAME', '1')} 的java实现类
 * js中使用
 * @author Administrator
 *
 */
public class HanldingLanguage {
	/**
	 * 根据语言环境,由key获取到对应的value
	 * @param key
	 * @param type  為1,代表從FrontMsg中尋找,為2,代表通過ajax,從System中尋找,3 代表从 BackMsg中寻找
	 * @return
	 */
	public static String getLanguage(String key, String type) {
		Map<String, Object> session = ActionContext.getContext().getSession();<span style="font-family: Arial, Helvetica, sans-serif;">//<strong>注意第一次访问网站时,是没有session的,因此这里需要做判断</strong></span>
		Locale currentLocale = (Locale) session.get("WW_TRANS_I18N_LOCALE");
		Locale defaultLocale = Locale.getDefault();
		ResourceBundle resource = null;
		String value = null;
		
		if ("1".equals(type)) {
		
			if (currentLocale == null) {
				
				resource = ResourceBundle.getBundle("FrontMsg_" + defaultLocale);
			} else {
				
				resource = ResourceBundle.getBundle("FrontMsg_" + currentLocale);
			}
		} else if ("2".equals(type)) {
			
			if (currentLocale == null) {
				
				resource = ResourceBundle.getBundle("System_" + defaultLocale);
			} else {
				
				resource = ResourceBundle.getBundle("System_" + currentLocale);
			}
		} else if ("3".equals(type)) {
			
			if (currentLocale == null) {
				
				resource = ResourceBundle.getBundle("BackMsg_" + defaultLocale);
			} else {
				
				resource = ResourceBundle.getBundle("BackMsg_" + currentLocale);
			}
		}
		
		value = resource.getString(key);
		
		
		return value;
	}
	
}
 b:编写tld文件 

在WEB-INF下面建立tld/myTag.tld 文件

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
  version="2.0"> 
  <description>JSTL 1.1 functions library</description>
  <display-name>JSTL functions</display-name>
  <tlib-version>1.2</tlib-version>
  <short-name>myFn</short-name>
  <uri>/myFn</uri>
  <function>
    <description>lj</description>
    <name>getLanguage</name>
    <function-class>
		com.adcorp.tag.HanldingLanguage
    </function-class>
    <function-signature>
       java.lang.String getLanguage(java.lang.String, java.lang.String)
    </function-signature>
  </function>
   <function>
    <description>lj</description>
    <name>getURL</name>
    <function-class>
		com.adcorp.tag.HanldingLanguage
    </function-class>
    <function-signature>
       java.lang.String getURL(java.lang.String)
    </function-signature>
  </function>
</taglib>

c:在web.xml中添加.tld文件的位置

<jsp-config>  
        <taglib>  
            <!-- 配置标签的引用地址 JSP页面中引用时使用-->  
            <taglib-uri>/eltag</taglib-uri>  
            <!-- 配置标签的TLD文件地址 -->  
            <taglib-location>tld/myTag.tld</taglib-location>  
        </taglib>  
    </jsp-config> 

d:在页面中添加标签

<%@taglib prefix="myFn" uri="/eltag"%>

e:在js中使用这个自定义el表达式。

if (result.success) {// 表示登录成功
					alert("${myFn:getLanguage('TIPS_LOGIN_SUCCESS', '2')}");
					top.location = 'dashBoard_index.action';

				}

3.解决在jsp中引入外部js文件,el表达式不起效问题。至于为什么是因为jsp文件最终会被解析为java代码,当它解析到有自定义的el表达式时,它会立即去执行这个方法。假如是js文件,它是不会被解析的。。。

解决办法:

将外部js文件改成.jsp后缀,并且在引入js的jsp页面中 将这个改成jsp后缀的js文件 包含进来。

详细步骤:

a:将要引入的js文件后缀名改成jsp

如下面的index.js 文件改成index.jsp文件。添加相应的标签

<%@taglib prefix="myFn" uri="/eltag"%>
<script>
function changeSign() {
	$("#regUser").attr("status", "true");
}
function login() {
	var username = $.trim($("#j_username").val());

	var password = $.trim($("#j_password").val());
<span style="white-space:pre">	</span>if (username == null || username == "") {
	<span style="white-space:pre">	</span>layer.tips("${myFn:getLanguage('F_LOGIN_JS_INPUT_YOUR_USERNAME', '1')}", document.getElementById("mzp_msg"), {


b:在页面中将jsp页面包含进来。
<%@taglib prefix="s" uri="/struts-tags" %>
<%@taglib prefix="myFn" uri="/eltag"%>
<%@include file="js/index.jsp" %>

包含方式有两种,这里我选取其中一种,这里特别注意引入.jsp文件在jsp中引入的位置顺序。(有可能会遇到,这里提出来)

这样就解决了上面的问题。


下面来讲解整个项目的具体过程。

1:建立相应的国际化资源语言文件。

如:FrontMsg_en_US.properties,FrontMsg_zh_CN.properties,BackMsg_en_US.properties,BackMsg_zh_CN.properties

System_en_US.properties,System_zh_CN.properties.

下面是FrontMsg_en_US.properties

#front login model text   en_US
F_LOGIN_TEXT_LOGIN=Log in
F_LOGIN_TEXT_EMAIL=Email
F_LOGIN_TEXT_PASSWORD=Password
F_LOGIN_TEXT_NOT_ACCOUNT=Don't have an account

F_LOGIN_JS_INPUT_YOUR_USERNAME=Please enter your user name
F_LOGIN_JS_INPUT_YOUR_PASSWORD=Please enter your password

下面是FrontMsg_zh_CN.properties

#front login model text  zh_CN
F_LOGIN_TEXT_LOGIN=\u767B\u5F55
F_LOGIN_TEXT_EMAIL=\u90AE\u7BB1
F_LOGIN_TEXT_PASSWORD=\u5BC6\u7801
F_LOGIN_TEXT_NOT_ACCOUNT=\u6CA1\u6709\u8D26\u53F7?

F_LOGIN_JS_INPUT_YOUR_USERNAME=\u8BF7\u8F93\u5165\u4F60\u7684\u7528\u6237\u540D
F_LOGIN_JS_INPUT_YOUR_PASSWORD=\u8BF7\u8F93\u5165\u4F60\u7684\u5BC6\u7801


这里我是分成前台FrontMsg,以及后台BackMsg,以及System 注意后面的en_US.properties,zh_CN.properties必须是固定的。


2:在struts2.xml中配置默认的语言环境,以及国际化资源名字前缀

	<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
	<constant name="struts.locale" value="zh_CN"/>
	<constant name="struts.custom.i18n.resources" value="System,FrontMsg,BackMsg"><!-- 国际化资源文件也即System_zh_CN.properties -->
	</constant>

3:建立用户可以切换的语言种类配置文件 languageResources.properties 建立这个文件的目的是为了后期可以方便的添加其它的语言。

如果后期需要添加其它语言,只需要在文件下面加上即可,然后再编写对应的国际资源文件即可。

1,zh_CN=\u4E2D\u6587
2,zh_TW=\u7E41\u4F53
3,en_US=English

至于为什么以这种形式写,是方便控制在前台语言排列显示的顺序


4:在.jsp页面中添加可以选择的语言种类

<s:bean id="locales" name="com.adcorp.common.LocaleUtils">
				<!-- 给lee.Locales的参数current注入值SESSION_LOCALE -->
</s:bean>
				
下面是LocaleUtils.java的代码
package com.adcorp.common;

import java.util.*;

import com.opensymphony.xwork2.ActionContext;

/**
 * 
 * @author Administrator
 *
 */
public class LocaleUtils {

	public List<Language> getLocales() {
		List<Language> locales = new ArrayList<Language>();
        ResourceBundle bundle = ResourceBundle.getBundle("languageResources");
        //查询出所有的Keys
        Enumeration<String> en = bundle.getKeys();
        
        List<String> keys = new ArrayList<String>();
        
        //查询出所有的Keys
        while(en.hasMoreElements()) {
        	String key = en.nextElement();
        	
        	keys.add(key);
        	
        }
        
        //对keys进行排序
        Collections.sort(keys);
        
        for (String key : keys) {
        	String value = bundle.getString(key);
        	Language language = new Language();
        	language.setLanguage(key.split(",")[1]);
        	language.setCountry(value);
        	locales.add(language);
        }
        
		return locales;
	}
	
	
	/**
	 * 得到当前系统语言<s:property>,在日历中,WdatePicker.js中,根据当前语言,将Lang属性设置成相应的环境,返回en或者zh-cn或者zh-tw在lang目录下面
	 * 有对应的语言
	 * @return
	 */
	public static String getCurrentLanguageInWdatePicker() {
		Map<String, Object> session = ActionContext.getContext().getSession();
		Locale currentLocale = (Locale) session.get("WW_TRANS_I18N_LOCALE");
		Locale defaultLocale = Locale.getDefault();
		String language = null;
		String country = null;
		if (currentLocale == null) {
			
			language = defaultLocale.getLanguage();
			country = defaultLocale.getCountry();
		} else {
			language = currentLocale.getLanguage();
			country = currentLocale.getCountry();
		}	
		
		return language + "_" + country;
		
		
	}
}

下面是Language.java这个实体类

package com.adcorp.common;

public class Language {
	private String language;
	
	private String country;

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}
	
	
}
下面完整的贴出在页面中显示所有可以选择语言的代码

<s:bean id="locales" name="com.adcorp.common.LocaleUtils">
				<!-- 给lee.Locales的参数current注入值SESSION_LOCALE -->
				</s:bean>
				<s:iterator value="#locales.locales" id="loca" status="st">
				<span class="sp_sig">
					
					<a href="<s:property value="#request['struts.request_uri']"/><s:property value="@com.adcorp.tag.HanldingLanguage@getURL(#request['javax.servlet.forward.query_string'])"/>request_locale=<s:property value='#loca.language'/>"><s:property value="#loca.country"/></a>
				</span>
				</s:iterator>	

其中最为复杂的是a标签里面的。下面一一讲解

a:首先是

<s:property value="#request['struts.request_uri']"/>是为了得到当前访问页面根路径后面的action地址,比如页面地址是http://localhost:8080/test/index.action,那么这个地址就是index.action,
这样在用户切换语言时,还是在当前页面下面。

 

b:如果页面访问地址存在参数  ?id=1007,这样的形式,那么还通过上面这种形式,那么参数将会丢掉。

解决办法:通过struts2访问静态方法的形式。至于说request里面的参数是哪里来的,可以将<s:debug>打开,看里面的参数即可

<s:property value="@com.adcorp.tag.HanldingLanguage@getURL(#request['javax.servlet.forward.query_string'])"/> 其中#request['javax.servlet.forward.query_string就可以得到url后面的参数。
而函数getURL就是解决有url参数的情况以及url中是否存在request_local这个参数的情况(如果有request_local参数,那么就需要舍弃掉这个参数,因为我们后面已经添加了request_locale这个参数,因为这个参数才是我们用户现在可能需要的语言)

 下面我贴出getURL的代码 

	public static String getURL(String url) {
		
		//no parameter
		if ("".equals(url) || url == null) {
			
			return "?";
		} 
		
		//?..&request_locale
		if (url.toLowerCase().contains("&request_locale")) {
			
			url = url.substring(0, url.toLowerCase().indexOf("&request_locale"));
			
			return "?" + url + "&";
		}
		
		//?request_locale
		if (url.toLowerCase().contains("request_locale")) {
			
			url = url.substring(0, url.toLowerCase().indexOf("request_locale"));
			
			return "?" + url;
		}
		
		//hava parameter
		return "?" + url + "&";
		
		
	}

c:
request_locale=<s:property value='#loca.language'/>"><s:property value="#loca.country"/>

前面的即是需要选择的语言环境(zh_CN,en_US等等),后面即是value值

d:在页面中显示如下


注意:

1:如果是ajax提交到struts的话,如果你在action中使用getText(),那么可能得到的结果不是当前语言环境下的value,解决办法,调用上述的getLanguage()方法。

2:有可能会遇到使用控件时里面有中文需要替换成其它语言,那么你必须找到插件里面控制语言的位置,如日历控件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值