二、 Struts 2 的国际化入门
Struts 2 国际化是建立在 Java 国际化的基础之上,一样也是通过提供不同国家/语言环境的消息资源,然后通过 ResourceBundle 加载指定 Locale 对应的资源文件,再取得该资源文件中指定 key 对应的消息。整个过程与 Java 程序的国际化完全相同,只是 Struts 2 框架对 Java 程序国际化进行了进一步封装,简化。
2.1 加载全局资源文件
Struts 2 提供了很多加载国际化资源文件的方法,最简单、最常用的就是加载全局的国际化资源文件 ,这种方式是通过配置常量来实现 。不管在 struts.xml ,还是在 struts.properties 文件中配置常量,只需要配置 struts.custom.i18n.resources 常量即可 。
假设系统需要加载的国际化资源文件的 baseName 为 messageResource,则:
struts.properties
struts.custom.i18n.resources=messageResource
struts.xml
<constant name="struts.custom.i18n.resources" value="messageResource"/>
通过这种方式加载国际化资源文件后,Struts 2 应用就可以在所有地方取出这些国际化资源文件了,包括 JSP 和 Action
2.2 访问国际化消息
Struts 2 既可以在 JSP 页面中通过标签输出国际化消息,也可以在 Action 类中输出国际化消息。
Struts 2 访问国际化消息主要有如下 3 种方式:
● JSP 页面,可以使用 Struts 2 的 <s:text .../> 标签,该标签可以指定一个 name 属性,该属性指定了国际化资源文件中的 Key
● Action 类中,可以使用 ActionSupport 类的 getText() 方法,该方法接受一个 name 参数,该参数指定了国际化资源文件中的 Key
● 表单元素 的 Label 里输出国际化信息 ,可以为该表单标签指定一个 key 属性,该 key 指定了国际化资源文件中的 Key
messageResource_en_US.properties
#资源文件的内容就是key-value对 loginPage=Login Page errorPage=Error Page succPage=Welcome Page failTip=Sorry,You can't log in! succTip=welcome,you has logged in! user=User Name pass=User Pass login=Login
messageResource_zh_CN.properties
loginPage=登录页面 errorPage=错误页面 succPage=成功页面 failTip=对不起,您不能登录! succTip=欢迎,您已经登录! user=用户名 pass=密 码 login=登录
上面 messageResource_zh_CN.properties 文件必须使用 native2ascii 工具处理。
提供上面 2 份资源文件后,通过上一节所介绍的方式加载国际化资源文件,系统会根据浏览者所在的 Locale 来加载对应的语言资源文件。
login.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><s:text name="loginPage"/></title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
<s:form action="login">
<s:textfield name="username" key="user"/>
<s:textfield name="password" key="pass"/>
<s:submit key="login"/>
</s:form>
</body>
</html>
上面 JSP 用 <s:text .../> 标签直接输出国际化信息,也通过表单元素中指定 key 属性来输出国际化消息 。通过这种方式,就可以完成 JSP 中普通文本、表单元素标签的国际化。
如果在 Action 中,可以用 ActionSupport 的 getText() 方法
LoginAction.java
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ActionContext;
public class LoginAction extends ActionSupport
{
//封装两个请求参数的属性
private String username;
private String password;
//username属性的setter和getter方法
public void setUsername(String username)
{
this.username = username;
}
public String getUsername()
{
return this.username;
}
//password属性的setter和getter方法
public void setPassword(String password)
{
this.password = password;
}
public String getPassword()
{
return this.password;
}
//定义处理用户请求的execute方法
public String execute()throws Exception
{
ActionContext ctx = ActionContext.getContext();
//用户登录成功
if (getUsername().equals("crazyit")
&& getPassword().equals("leegang") )
{
ctx.getSession().put("user" , getUsername());
//调用getText方法取出国际化消息
ctx.put("tip" , getText("succTip"));
return SUCCESS;
}
else
{
//调用getText方法取出国际化消息
ctx.put("tip" , getText("failTip"));
return ERROR;
}
}
}
通过这种方式,即使 Action 需要设置在下一个页面显示的信息,也无需直接设置字符串常量,而是使用国际化消息的 key 来输出,从而实现程序的国际化。
struts.xml
<?xml version="1.0" encoding="GBK"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <constant name="struts.custom.i18n.resources" value="messageResource"/> <constant name="struts.i18n.encoding" value="GBK"/> <package name="lee" extends="struts-default"> <action name="login" class="lee.LoginAction"> <result name="error">/error.jsp</result> <result>/welcome.jsp</result> </action> <action name=""> <result>.</result> </action> </package> </struts>
welcome.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><s:text name="succPage"/></title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
${requestScope.tip}
</body>
</html>
error.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><s:text name="errorPage"/></title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
${requestScope.tip}
</body>
</html>
2.3 输出带占位符的国际化消息
Java 中使用 MessageFormat 类,完成填充占位符
Struts 2 更方便,提供 2 种方式 来填充消息字符串中的占位符
● JSP 页面中,则可以通过 <s:text .../> 标签中使用多个 <s:param ...> 标签来填充消息中的占位符。第一个 <s:param ...> 指定第一个占位符值,第二个 <s:param ...> 指定第二个占位符值,依此类推
● Action 中,则可以通过在调用 getText(String aTextName , List args) 或 getText(String key , String[] args) 方法来填充占位符。
例如:
messageResource_zh_CN.properties
loginPage=登陆页面 errorPage=错误页面 succPage=成功页面 failTip={0},对不起,您不能登录! succTip={0},欢迎,您已经登录! welcomeMsg={0},您好!现在时间是{1}! user=用户名 pass=密 码 login=登陆
messageResource_en_US.properties
loginPage=Login Page errorPage=Error Page succPage=Welcome Page failTip={0},Sorry,You can't log in! succTip={0},Welcome,you has logged in! welcomeMsg={0},Hello!Now is {1}! user=User Name pass=User Pass login=Login
LoginAction.java
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ActionContext;
public class LoginAction extends ActionSupport {
// 定义两个属性,username和password,用于封装两个请求参数
private String username;
private String password;
// username属性的setter和getter方法
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return this.username;
}
// password属性的setter和getter方法
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return this.password;
}
// 下面省略了两个属性的setter和getter方法
// ...
// 定义处理用户请求的execute方法
public String execute() throws Exception {
ActionContext ctx = ActionContext.getContext();
// 用户登录成功
if (getUsername().equals("crazyit") && getPassword().equals("leegang")) {
ctx.getSession().put("user", getUsername());
// 调用getText方法取出国际化信息,使用字符串数组为占位符设置值
ctx.put("tip", getText("succTip", new String[]{username}));
return SUCCESS;
} else {
// 调用getText方法取出国际化信息,使用字符串数组为占位符设置值
ctx.put("tip", getText("failTip", new String[]{username}));
return ERROR;
}
}
}
welcome.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><s:text name="succPage"/></title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
${requestScope.tip}<br/>
<jsp:useBean id="d" class="java.util.Date" scope="page"/>
<s:text name="welcomeMsg">
<s:param><s:property value="username"/></s:param>
<s:param>${d}</s:param>
</s:text>
</body>
</html>
上面页面 使用 ${requestScope.tip} 输出 Action类 中取出的国际化消息,通过 <s:text .../> 取出另一个国际化消息,使用 2 个 <param .../> 指定 2 个占位符的值
login.jsp
<head>
<title><s:text name="loginPage"/></title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
<s:form action="login">
<s:textfield name="username" key="user"/>
<s:textfield name="password" key="pass"/>
<s:submit key="login"/>
</s:form>
</body>
struts.xml
<?xml version="1.0" encoding="GBK"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <constant name="struts.custom.i18n.resources" value="messageResource"/> <constant name="struts.i18n.encoding" value="GBK"/> <package name="lee" extends="struts-default"> <action name="login" class="lee.LoginAction"> <result name="error">/error.jsp</result> <result>/welcome.jsp</result> </action> <action name=""> <result>.</result> </action> </package> </struts>
除此之外,Struts 2 还提供了对占位符的一种替代方式
这种方式可以避免在使用国际化消息时还需要为占位符传入参数值,如下:
#在消息资源中使用表达式 failTip=${username},对不起,您不能登录! succTip=${username},欢迎,您已经登录!
在上面的消息资源中,通过使用表达式,可以从 ValueStack 中取出该 username 属性值。 自动填充到该消息资源中。
这种方式,当需要 Action 中使用该消息资源时,无需为该消息资源传入参数,即当使用 getText() 方法获取国际化消息时,无需为消息资源中的占位符传入参数
三、 加载资源文件的不同方式
前面介绍了最常见的方式,除此之外,Struts 2 还提供了多种方式来加载国际化资源文件,包括指定包范围资源文件 、类范围资源文件 、临时指定资源文件 等。
3.1 包范围资源文件
把所以国际化资源都放在同一个全局文件里,文件会过大。为了更好地体现软件工程里 分而治之 的原则,Struts 2 允许针对不同模块、不同 Action 来组织国际化资源文件。
包范围资源文件: 在包的根路径下建立多个文件名为 package_language_country.properties 的文件,一旦建立了这个系列的国际化资源文件,应用中处于该包下的所有 Action 都可以访问该资源文件。
注意: 上面的包范围资源文件的 baseName 就是 package ,不是 Action 所在包名。该文件通常只需放在该包的根路径下即可
lee.action 包 下 有 LoginAction.java
package lee.action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ActionContext;
public class LoginAction extends ActionSupport
{
//下面定义了两个属性,用于封装请求参数
private String username;
private String password;
//此处省略了各属性的setter和getter方法
//username属性的setter和getter方法
public void setUsername(String username)
{
this.username = username;
}
public String getUsername()
{
return this.username;
}
//password属性的setter和getter方法
public void setPassword(String password)
{
this.password = password;
}
public String getPassword()
{
return this.password;
}
//处理用户请求的execute方法
public String execute() throws Exception
{
ActionContext ctx = ActionContext.getContext();
if (getUsername().equals("crazyit")
&& getPassword().equals("leegang"))
{
ctx.getSession().put("user" , getUsername());
//取出国际化消息
ctx.put("tip" , getText("succTip"));
return SUCCESS;
}
else
{
//取出国际化消息
ctx.put("tip" , getText("failTip"));
return ERROR;
}
}
}
struts.xml
<?xml version="1.0" encoding="GBK"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <constant name="struts.custom.i18n.resources" value="messageResource"/> <constant name="struts.i18n.encoding" value="GBK"/> <package name="lee" extends="struts-default"> <action name="login" class="lee.action.LoginAction"> <result name="error">/error.jsp</result> <result>/welcome.jsp</result> </action> <action name=""> <result>.</result> </action> </package> </struts>
lee 包 下 有:package_en_US.properties
failTip=Package Scope:Sorry,You can't log in! succTip=Package Scope:welcome,you has logged in!
lee 包 下 有:package_zh_CN.properties
failTip=包范围消息:对不起,您不能登录! succTip=包范围消息:欢迎,您已经登录!
注意: 这 2 份资源文件保存在 WEB-INF/classes/lee 路径下,该资源文件就可以被位于 lee 包 及 lee 包下所有子包内的 Action 访问了
结论: Action 将优先使用包范围的资源文件 ,虽然也提供了全局范围的资源文件,但是 Action 优先使用包范围的资源文件
3.2 Action 范围资源文件
Struts 2 还允许为 Action 单独指定一份国际化资源文件。
为 Action 单独指定国际化资源文件的方法 是:
在 Action 类文件所在的路径建立多个文件名为 ActionName_language_country.properties 的文件,一旦建立了这个系列的国际化资源文件 ,该 Action 将可以访问该 Action 范围的资源文件。
还是使用前一节的 Action 类,该 Action 类的类文件位于 WEB-INF/classes/lee/action 路径下,于是我们建立如下 2 份资料文件
LoginAction_en_US.properties
failTip=Action Scope:Sorry,You can't log in! succTip=Action Scope:welcome,you has logged in!
LoginAction_zh_CN.properties
failTip=Action范围消息:对不起,您不能登录! succTip=Action范围消息:欢迎,您已经登录!
一旦建立了这 2 份资源文件,lee.action.LoginAction 将优先加载 Action 范围的资源文件。
通过使用这种 Action 范围的资源文件,就可以在不同的 Action 里使用相同的 key 名来表示不同的字符串值 。例如,在 ActionOne 中 title 为 “动作一”,而同样用 title 在 ActionTwo 中则可以表示 “动作二” ,这样就可以简化 key 的命名,无需像 Struts 1 中使用 loginForm.title、registForm.title 来以示区分了。
提示: 当 Action 范围的资源文件和包范围的资源文件同时存在时,系统将优先使用 Action 范围的资源文件
3.3 临时指定资源文件
临时指定资源文件的方式: 可以在 JSP 页面中输出国际化消息时临时指定国际化资源的位置。
在这种方式下,需要借助 Struts 2 的另外一个标签:<s:i18n .../>
如果把 <s:i18n .../> 标签作为 <s:text .../> 标签的父标签,则 <s:text .../> 标签将会直接加载 <s:i18n .../> 标签里指定的国际化资源文件;如果把 <s:i18n .../> 标签当成表单标签的父标签,则表单标签的 key 属性将会从国际化资源文件中加载该消息。
WEB-INF/classes 路径下,假设包含如下 2 份资源文件:
tmp_zh_CN.properties
#在JSP页面使用的临时资源文件 loginPage=临时消息:登录页面 errorPage=临时消息:错误页面 succPage=临时消息:成功页面 failTip=临时消息:全局消息:对不起,您不能登录! succTip=临时消息:全局消息:欢迎,您已经登录! user=临时消息:用户名 pass=临时消息:密 码 login=临时消息:登录
tmp_en_US.properties
#在JSP页面临时使用的资源文件 loginPage=Temp Message:Login Page errorPage=Temp Message:Error Page succPage=Temp Message:Welcome Page failTip=Temp Message:Global Message:Sorry,You can't log in! succTip=Temp Message:Global Message:welcome,you has logged in! user=Temp Message:User Name pass=Temp Message:User Pass login=Temp Message:Login
login.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
<s:i18n name="tmp">
<s:text name="loginPage"/>
</s:i18n>
</title>
<meta name="website" content="http://www.crazyit.org" />
</head>
<body>
<!-- 使用i18n作为s:text标签的父标签,临时指定国际化资源文件的baseName为tmp -->
<s:i18n name="tmp">
<s:form action="login">
<s:textfield name="username" key="user"/>
<s:textfield name="password" key="pass"/>
<s:submit key="login"/>
</s:form>
</s:i18n>
</body>
</html>
3.4 加载资源文件的顺序
Struts 2 提供了如此多的方式来加载国际化资源文件,这些加载国际化资源文件的方式有自己的优先顺序。假设需要在 ChildAction 中访问国际化消息,则系统加载国际化资源文件的优先级 是:
① 优先加载系统中保存在 ChildAction 的类文件相同位置,且 baseName 为 ChildAction 的系列资源文件。
② 如果在 ① 中找不到指定 key 对应的消息,且 ChildAction 有父类 ParentAction ,则加载系统中保存在 ParentAction 的类文件相同位置,且 baseName 为 ParentAction 的系列资源文件。
③ 如果在 ② 中找不到指定 key 对应的消息,且 ChildAction 有实现接口 IChildAction ,则加载系统中保存在 IChildAction 的类文件相同位置,且 baseName 为 IChildAction 的系列资源文件。
④ 如果在 ③ 中找不到指定 key 对应的消息,且 ChildAction 有实现接口 ModelDriven (即使用模型驱动模式),则对于 getModel() 方法返回的 model 对象,重新执行第 ① 步 操作。
⑤ 如果在 ④ 中找不到指定 key 对应的消息,则查找当前包下 baseName 为 package 的系列资源文件。
⑥ 如果在 ⑤ 中找不到指定 key 对应的消息,则沿着当前包上溯,直到最顶层包来查找 baseName 为 package 的系列资源文件。
⑦ 如果在 ⑥ 中找不到指定 key 对应的消息,则查找 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件。
⑧ 如果经过上面步骤一直找不到该 key 对应的消息,将直接输出该 key 的字符串值;如果在上面的步骤 ① ~ ⑦ 的任一步中,找到指定 key 对应的消息,系统将停止搜索,直接输出该 key 对应的消息
对于在 JSP 中访问国际化消息,则简单得多,分成 2 种形式
● 对于使用 <s:i18n .../> 标签作为父标签的 <s:text .../> 标签、表单标签的形式:
① 将从 <s:i18n .../> 标签指定的国际化资源文件中加载指定 key 对应的消息。
② 如果在 ① 中找不到指定 key 对应的消息,则查找 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件
③ 如果经过上面步骤一直找不到该 key 对应的消息,将直接输出该 key 的字符串值;如果在上面的步骤 ①~② 的任一步中,找到指定 key 对应的消息,系统停止搜索,直接输出该 key 对应的消息。
● 如果 <s:text .../> 标签、表单标签没有使用 <s:i18n.../> 标签作为父标签:
直接加载 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件。如果找不到该 key 对应的消息,将直接输出该 key 的字符串值;否则,则输出该 key 对应的国际化消息。
四、允许用户自行选择程序语言
在很多成熟的商业软件中,可以让用户自由切换语言,当用户进入系统时,可以出现一个下拉列表框,让用户选择语言。
struts 2 也可以允许用户自行选择语言。而且 更加简单!
4.1 Struts 2 国际化的运行机制
Struts 2 中,通过 ActionContext.getContext().setLocale(Locale arg) 设置用户的默认语言,不过这种方式完全是一种手动方式,而且需要编程实现。
为了简化设置用户默认语言环境, Struts 2 提供了一个名为 i18n 的拦截器 (Interceptor ),并将其注册在默认的拦截器栈中(defaultStack ) 。
struts2-core-2.2.1.jar 的 struts-default.xml 中有如下片段:
<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="debugging"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"> <param name="excludeParams">dojo\..*,^struts\..*</param> </interceptor-ref> <interceptor-ref name="conversionError"/> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> </interceptor-stack>
★ i18n 拦截器在执行 Action 方法前,自动查找请求中一个名为 request_locale 的参数。如果该参数存在,拦截器就将其作为参数转换成 Locale 对象,并将其设为用户默认的 Locale 。
除此之外,i18n 拦截器还会将上面生成的 Locale 对象保存在用户 Session 的名为 "WW_TRANS_I18N_LOCALE " 属性中。一旦用户 Session 中存在 "WW_TRANS_I18N_LOCALE " 属性,该属性指定的 Locale 会作为浏览者的默认 Locale
4.2 创建下拉列表框、选择程序语言
实现用户自行选择程序语言功能,只需提供一个下拉框列表,并且当用户选择下拉框中某一项时,系统将该下拉项的值作为 request _locale 参数提交给 Struts 2 .
定义一个 javabean 保存系统支持的全部语言:
Locales.java
import java.util.*;
//该JavaBean存放了系统所支持的全部语言
public class Locales {
// 使用current保存用户当前选择的Locale
private Locale current;
public void setCurrent(Locale cur) {
this.current = cur;
}
// 取得本系统所支持的全部语言
public Map<String, Locale> getLocales() {
// 将当前系统支持的全部语言保持在Map对象中
Map<String, Locale> locales = new Hashtable<String, Locale>();
ResourceBundle bundle = ResourceBundle.getBundle("messageResource",
current);
// 添加当前系统支持的语言,key是系统支持语言的显示名字,
// value是系统支持语言的Locale实例
locales.put(bundle.getString("enus"), Locale.US);
locales.put(bundle.getString("zhcn"), Locale.CHINA);
return locales;
}
}
上述,Map 的 key 是所支持语言的显示名字,value 是所支持语言的 Locale 实例
selectlanguage.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<script type="text/javascript">
function langSelecter_onChanged()
{
document.getElementById("langForm").submit();
}
</script>
<!-- 将HTTP Session中的"WW_TRANS_I18N_LOCALE"
属性值设置成SESSION_LOCALE -->
<s:set name="SESSION_LOCALE" value="#session['WW_TRANS_I18N_LOCALE']"/>
<!-- 使用lee.Locales创建locales实例 -->
<s:bean id="locales" name="lee.Locales">
<!-- 为locales实例传入current参数值 -->
<s:param name="current"
value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"/>
</s:bean>
<form action="<s:url/>" id="langForm"
style="background-color:#bbbbbb; padding-top: 4px; padding-bottom: 4px;">
<s:text name="language"/>
<s:select label="Language" list="#locales.locales"
listKey="value" listValue="key"
value="#SESSION_LOCALE == null ? locale : #SESSION_LOCALE"
name="request_locale" id="langSelecter"
οnchange="langSelecter_onChanged()" theme="simple"/>
</form>
注意: 使用 <s:set .../> 将用户 Session 的 " WW_TRANS_I18N_LOCALE " 属性值设置成 SESSION_LOCALE ,并创建了 lee.Locales 类的 locales 实例,并为该实例传入 current 参数值,先判断 SESSION_LOCALE 是否为 null ,如果为 null 则返回 ValueStack 中的 locale 属性值(即用户浏览器设置的 Locale );如果不为 null ,则返回 SESSION_LOCALE 的值(即用户选择的 Locale )
messageResource_en_US.properties
loginPage=Login Page errorPage=Error Page succPage=Welcome Page failTip=Sorry,You can't log in! succTip=welcome,you has logged in! user=User Name pass=User Pass login=Login language=Select Lanuage enus=American English zhcn=Simplified Chinese
messageResource_zh_CN.properties
loginPage=登陆页面 errorPage=错误页面 succPage=成功页面 failTip=对不起,您不能登录! succTip=欢迎,您已经登录! user=用户名 pass=密 码 login=登陆 language=选择语言 enus=美式英语 zhcn=简体中文
本例 JSP 都放在 WEB-INF/jsp 下,从而避免直接访问 JSP 页面,让所有 JSP 页面都能得到 Struts 2 处理
struts.xml
<?xml version="1.0" encoding="GBK"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <constant name="struts.custom.i18n.resources" value="messageResource"/> <constant name="struts.i18n.encoding" value="GBK"/> <package name="lee" extends="struts-default"> <action name="login" class="lee.LoginAction"> <result name="error">/WEB-INF/jsp/error.jsp</result> <result name="success">/WEB-INF/jsp/welcome.jsp</result> </action> <action name="*"> <result>/WEB-INF/jsp/{1}.jsp</result> </action> <action name=""> <result>.</result> </action> </package> </struts>
<action name="*"> <result>/WEB-INF/jsp/{1}.jsp</result> </action>
上面代码 请求 selectlanguage.action
login.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><s:text name="loginPage"/></title>
</head>
<body>
<s:include value="selectlanguage.jsp"/>
<s:form action="login">
<s:textfield name="username" key="user"/>
<s:textfield name="password" key="pass"/>
<s:submit key="login"/>
</s:form>
</body>
</html>
通过如下标签来选择语言
<s:include value="selectlanguage.jsp"/>
成功和失败 jsp :
welcome.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><s:text name="succPage"/></title>
</head>
<body>
${requestScope.tip}
</body>
</html>
error.jsp
<%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><s:text name="errorPage"/></title>
</head>
<body>
${requestScope.tip}
</body>
</html>
原理 : 用户选择了语言后,系统将用户选择设置成了 HTTP Session 的 "WW_TRANS_I18N_LOCALE " 属性值,该 Session 属性值直接决定 Struts 2 系统的语言环境。