在看这篇文章之后,你必须要会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>
上面三个步骤即完成了首页是通过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>
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>
<jsp-config> <taglib> <!-- 配置标签的引用地址 JSP页面中引用时使用--> <taglib-uri>/eltag</taglib-uri> <!-- 配置标签的TLD文件地址 --> <taglib-location>tld/myTag.tld</taglib-location> </taglib> </jsp-config>
<%@taglib prefix="myFn" uri="/eltag"%>
if (result.success) {// 表示登录成功 alert("${myFn:getLanguage('TIPS_LOGIN_SUCCESS', '2')}"); top.location = 'dashBoard_index.action'; }
解决办法:
将外部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"), {
<%@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
#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; } }
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:首先是
<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 + "&"; }
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:有可能会遇到使用控件时里面有中文需要替换成其它语言,那么你必须找到插件里面控制语言的位置,如日历控件。