在看这篇文章之后,你必须要会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:有可能会遇到使用控件时里面有中文需要替换成其它语言,那么你必须找到插件里面控制语言的位置,如日历控件。