今天学习的主要内容:国际化资源
一.首先回顾一下struts2 的搭建有三个步骤:
1.导入包;
2.配置web-inf下的xml文件;
3.把struts.xml放在src的目录下。
二.分析action和Action类
1.action:代表一个struts2 的请求。
2.Action类:能处理struts2请求的类(java文件,实质是:.class文件)
Action的特点:
》属性的名字必须遵JavaBeans属性名相同的命名规则。属性的类型可以是任意的,从字符串到非字符串(基本数据类型)之间数据转换可以自动发生。
》必带一个无参数的构造器,因为要通过反射构建需要类的实例。
》至少有一个struts在执行action时候调用的方法。
》同一个Action类可以包含多个action的方法。
》struts2会给每一个请求创建一个Action的实例,即Action不是单例的。
三.这里顺便插入一个小注意事项:
在<form action="" >中,若不写method,默认值为:method="get",所以几次出错的原因,没有改写默认的method的值。所以只要把method="post",就不会乱码。
四.Struts2国际化资源
》国际化资源的概念:为不同的国家语言提供对应的消息资源文件。
》Struts2框架会根据请求包中包含的locale加载对应的资源文件。
》通过程序代码取得资源文件指定的key对应的消息。
重点:
1.如何配置消息资源的文件?
2.页面和Action类中如何取得资源配置中的value的值?
3.如何通过超链接实现国际化资源的替换?
首先看第一点:如何配置资源文件
(1)Action范围资源文件的配置:直接可以写XXXXAction_zn_CN.properties,这里一定要注意是:Action_zn_CN.properties这样的格式必须写Action,规定的。
(2)包范围的资源文件:在包的根目录下创建。文件名也要强制:package_language_country.properties属性文件,
一旦建立,处于该包下的所有Action都可以访问该文件,注意:包范围资源文件的baseName就是package(小写的p),不是Action所在的包名。
(3)全局资源文件:命名方式:baseName_language_country.properties,这个全局的要通过常量方式配置。
在struts.xml中我们要:
<constant name="struts-custom.i18n.resources" value="baseName"/>
了解下国际化资源的加载顺序:距离当前的Action较近的将被优先加载。(只要明白这一点就可以了)
再来看下第二点:页面和Action类中如何取得资源配置中的value的值
(1)在Action类中,若Action实现了TextProvder接口,则可以调用其getText方法获取value值(通过继承ActionSupport的方式)
下面看一个例子:
在全局中写3个,一个是i18nAction.properties,一个是中文i18n_zh_CN.properties,一个是美国英文i18n_en_US.properties
Testi18nAction.properties资源文件内容如下:
username=UserName
password=PassWord
submit=Submit
time=Time:{0}
time2=Time:${date}
i18n_zh_CN.properties资源文件如下:
username=\u7528\u6237\u540D
password=\u5BC6\u7801
submit=\u63D0\u4EA4
time=\u65F6\u95F4\:{0}
time2=\u65F6\u95F4\:${date}
i18n_en_US.properties资源文件如下:
username=UserName
password=PassWord
submit=Submit
time=Time:{0}
time2=Time:${date}
然后在struts.xml中配置全局的,constant的详细配置过程:(<!---->是xml中的注释)
<!-- 配置国际化资源文件,找到i18n:路径项目中的web App Libraies>>strust2-core-2.3.28.jar>>org.apache.struts2>>
下面注意观察找到default.properties>>然后ctrl+F查找i18n找到:
“# struts.custom.i18n.resources=testmessages,testmessages2”
然后constant中:
(i18n名字随意的可以是其他的,但是要跟写的.properties文件名对应)
的name复制等号前面的:struts.custom.i18n.resources
value的值:i18n
-->
<constant name="struts.custom.i18n.resources" value="i18n"></constant>
<package name="default" extends="struts-default">
<action name="testi18n" class="com.atguigu.struts2.i18n.app.Testi18nAction">
<result>/i18n.jsp</result>
</action>
</package>
这个例子的2个页面都在webroot下
一个是:
index.jsp
内容:
<a href="testi18n">Test i18n</a>
二个是:
il8n.jsp(在下面有讲解这个jsp页面的详细内容提示在这个地方:”再看页面中获取资源文件信息:il8n.jsp“)
然后在配置好的struts2的一个web项目中的src下创建如下图的包名和名字为testi18nAction.java文件
:
仔细看下面的代码注释和内容:
mport java.util.Arrays;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class Testi18nAction extends ActionSupport {
/**
* 这里要注意2个地方
*
*
这是第一点:在建立这个类的时候 Testi18nAction可以直接去继承找到ActionSupport。
*
*
第二点:静态的常量有2个,可以写第一个,并且写execute的时候可以直接写ex之后ctrl+/提示这个execute()
* 方法的重写。
*/
private static final long serialVersionUID = 1L;
//为了是页面访问time所以定义一个字段如下:
//然后在execute方法中去实例化对象:
//date = new Date()写出这个的get与set方法;
private Date date = null;//定义一个全局变量Date类的date
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
//
@Override
public String execute() throws Exception
{
/**
* 在action中访问国际化资源文件的value值;
* 为什么能访问这个值?
* 因为这个类Testi18nAction继承ActionSupport,这个ActionSupport中有个getText(String key)方法实现国际化;
* getText方法好像实现了一个接口?
* 所以这个方法的返回值就是国际化资源的value的值;
* 占位符的time:
*
String time = getText("time", Arrays.asList(new Date()));
*/
String username = getText("username");//这一行代码就是获取资源配置中的value的值
System.out.println(username);
date = new Date();
String time = getText("time", Arrays.asList(date));//
这一行代码也是获取资源配置中的key,并赋值
System.out.println(time);
return SUCCESS;
}
}
再看页面中获取资源文件信息:il8n.jsp
首先在设置UTF-8下面一行写:
<%@taglib prefix="s" uri="/struts-tags" %>
整体页面和注释如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!-- 导入Struts2标签 -->
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'il8n.jsp' starting page</title>
</head>
<body>
<!-- 打开debug的方法在jsp页面中要加上<%@taglib prefix="s" uri="/struts-tags" %>
之后才可以
打开网页之后我们点击打开debug可以知道栈顶部有一个:DefaultTextProvider,在他里面有许多的get方法。
所以在下面的form表单下的第一个label="UserName" 可以改写成label="getText('username')"
getText('username')这个是ognl表达式
而label=“字符串值”,所以强制ognl包装解析:
小结:一·所以有2种情况(默认的theme为xml情况):
label="%{getText('username')}"(页面获取的第一种方式)
1)
用key属性 例如:<s:textfield name="username" key="username"></s:textfield>(页面获取第二种方式)
2)用label属性<s:textfield name="username" label="%{getText('username')}"></s:textfield>
下面的二·是theme是simple的情况(<s:text name="username"/>加在前面)
<s:text name="username"/>:<s:textfield name="username" label="%{getText('username')}"></s:textfield>
<s:submit key="submit" value="%{getText('submit')}"></s:submit>
-->
<s:debug></s:debug>
<!-- label方式把label写死在标签里 ,但是可以访问资源文件-->
<s:form action="" theme="simple">
<!--
二·
这里的表单主体默认是xml,若将主题换成theme="simple"
则不会出现账号,密码的文字信息提示用户输入了,所以
要加上<s:text name="username"/>,这个标签的作用也可访问国际化资源的value值
所以在<s:textfield name="username" key="username"></s:textfield>
前面,而submit也在simple的情况下也要ognl解析:
<s:submit key="submit" value="%{getText('submit')}"></s:submit>
-->
<s:text name="username"/>:<s:textfield name="username" label="%{getText('username')}"></s:textfield>
<!-- key直接上资源文件中的value的值 -->
<s:text name="username"/>:<s:textfield name="username" key="username"></s:textfield>
<s:text name="password"/>:<s:textfield name="password" key="password"></s:textfield>
<s:submit key="submit" value="%{getText('submit')}"></s:submit><!-- 因为这里是struts2标签,所以要用ognl解析才可以 -->
</s:form>
<!-- 访问值栈里面的属性值:time=Time:{0}这样的形式,要param填充占位符-->
<!-- date是值栈栈顶中的属性值,在servlet中已经获取了国际化资源Testi18nAction.java中;
在 i18n_zn_CN.properties中或者在i18n_en_US.properties中可以直接获取值栈中的date
time:${date}
-->
//这样的写发在资源文件中的样子是:time=Time{0}
<s:text name="time">
<s:param value="date"></s:param>
</s:text>
<br>
//这样写法在资源文件中
time2=${date},这个date的来历是在testi18nAction.java中定义了这个date值
<s:text name="time2"></s:text>
</body>
</html>
如此,在Action范围的情况下如下图所示在Testi18nAction.java同级别目录下写3个test开头的文件,里面内容与上面的全局资源里一样,可以测试出加载资源文件的优先级(可以在这个三个值前面加一个"^0^"的符号测试):