struts2国际化开发详细过程

来源:互联网 发布:手机编程用什么软件 编辑:程序博客网 时间:2024/06/17 01:45
在看这篇文章之后,你必须要会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 {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic 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);}}@Overridepublic 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_USF_LOGIN_TEXT_LOGIN=Log inF_LOGIN_TEXT_EMAIL=EmailF_LOGIN_TEXT_PASSWORD=PasswordF_LOGIN_TEXT_NOT_ACCOUNT=Don't have an accountF_LOGIN_JS_INPUT_YOUR_USERNAME=Please enter your user nameF_LOGIN_JS_INPUT_YOUR_PASSWORD=Please enter your password

下面是FrontMsg_zh_CN.properties

#front login model text  zh_CNF_LOGIN_TEXT_LOGIN=\u767B\u5F55F_LOGIN_TEXT_EMAIL=\u90AE\u7BB1F_LOGIN_TEXT_PASSWORD=\u5BC6\u7801F_LOGIN_TEXT_NOT_ACCOUNT=\u6CA1\u6709\u8D26\u53F7?F_LOGIN_JS_INPUT_YOUR_USERNAME=\u8BF7\u8F93\u5165\u4F60\u7684\u7528\u6237\u540DF_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\u65872,zh_TW=\u7E41\u4F533,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 parameterif ("".equals(url) || url == null) {return "?";} //?..&request_localeif (url.toLowerCase().contains("&request_locale")) {url = url.substring(0, url.toLowerCase().indexOf("&request_locale"));return "?" + url + "&";}//?request_localeif (url.toLowerCase().contains("request_locale")) {url = url.substring(0, url.toLowerCase().indexOf("request_locale"));return "?" + url;}//hava parameterreturn "?" + 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
原创粉丝点击