***
***是一种可以让用户在Action执行之前和Result执行之后进行一些功能处理的机制。注意***在Action之前和Result之后的执行顺序是相反的。
预定义***
在Struts2中,有一些默认的***,负责特定的功能,我们称这些***为预定义的***。预定义***在struts-default包内的struts-default.xml文件中,里面定义了多个***,以及实现***的全类名。eg:
params***:负责把请求的参数设置到相应的Action的属性中,并进行类型转换。
modelDriven***:Action实现ModelDriven接口,它将getModel()方法取得的模型对象存入OgnlValueStack中。
exception***:当抛出异常的时候,这个***发挥功效。
logger***:在日志信息中输出要执行的Action信息,在调试的时候,就能很快的定位到这个对应的Action中。
.......
预定义***栈
当我们没有配置任何***的时候,Struts2默认引用默认的***。在Struts-default.xml中,有关***的信息,其中有以下元素标签是关于***的:
<interceptors> </interceptors>
<interceptor-stack> </interceptor-stack>
<interceptor-ref />
<default-interceptor-ref />
interceptors:用来定义一个***所存在的范围;
interceptor-stack:用来定义一个***栈,里面包含很多***;
interceptor-ref:标识各种***;
default-interceptor-ref:用来表示默认的***引用。
***的使用
在struts2.xml中的<action>元素中,使用<interceptor-ref>子元素,<interceptor-ref>子元素里面配置需要使用***的名称。
<action name="helloworld" class="com.dong.action.helloAction">
<result> /nextpage.jsp</result>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="basicStack"/>
</action>
在包上声明包内所有Action都使用的***,package元素只能有0个或1个default-interceptor-ref子元素,在配置自己的package时,Struts-default.xml文件中定义的struts-default保内,就定义了引用默认的***栈,所以在进行配置的时候,即使我们不进行任何配置,它会执行默认的***引用。
***的调用顺序:搜索范围是从小到大,先是在它自己的<action>元素内找,是否有***的设置,如果没有,则去<action>元素所在的包中寻找,如果没有,则去它的父包中寻找。
特定***的使用:action中的***的使用是在action中添加<interceptor-ref>***,使用name属性指定***的名称即可,包上的***的使用是在<package>元素下,使用<default-interceptor-ref>元素,name属性指向特定的***即可。
自定义***
自定义***只需要实现Interceptor接口即可,注意:在intercept方法中写invocation.invoke(),意思是继续运行***后续的处理,如果这个***后面还有***,则会继续运行,一直到运行Action,然后是Result,如果intercept方法中没有写invocation.invoke(),则意味着对请求的运行处理到此为止,不能继续向后运行了,在invocation。invoke()这句之前写的功能会在Action运行之前执行,在这句之后写的功能会在Result运行之后执行。
向***传入参数
⑴在struts.xml中,设置***的参数
<action name="hello" class="...">
<result>/result.jsp</result>
<interceptor-ref name="mytest">
<param name="paramtest">hello</param>
</interceptor-ref>
</action>
在mytest***实现类中设置对应属性,以及相应的get/set方法。
在初始化这个***的时候,struts2会返回调用对应的set方法,把<param>元素中匹配的值设置到paramtest属性上。
⑵在***声明的时候设置参数.
值栈
为每个请求提供公共数据存取服务,当有请求到达的时候,Struts2会为每个请求创建一个新的值栈,即值栈和请求是一一对应的,不同的请求,值栈也是不一样的。
值栈分为狭义和广义值栈之分:
狭义值栈:
实现com.opensymphony.xwork2.util.ValueStack接口的对象,用来存取动态EL运算所需要的值和结果,狭义的值栈中存放一些OGNL可以存取访问的数据,如:Action实例,OGNL表达式运算的值,OGNL表达式产生的中间变量。
广义的值栈:
通常是指ActionContext对象,ActionContext是Action运行的上下文,每个ActionContext都是一个基本的容器,ActionContext是线程安全的,每个线程都有一个独立的ActionContext,ActionContext存放的值有:Request的Parameters,Request的Attribute,Session的Attribute,Application的Attribte,Value Stack即狭义值栈等等。
在我们使用中,没有特别指明的情况下,我们多数指的是广义值栈。
ActionContext的使用
1.获取
在不能获取到ActionInvocation的地方,可以直接使用ActionContext的静态方法getContext方法,可以访问到当前的ActionContext。eg:
ActionContext context = ActionContext.getContext();
在可以获取ActionInvocation的地方,例如***里面,自定义的Result里面,可以使用ActionInvocation来获取ActionContext.eg:
ActionContext context = actionInvocation.getInvocationContext();
2.使用
ActionContext主要功能是用来存放数据的,常用的方法有:
get(String key):根据key从ActionContext当前的存储空间里获取相应的值;
put(String key,Objectvalue):把值存储在ActionContext的存储空间里;
Map<String,Object> getSession():返回HttpSession中存储的值;
Map<String,Object> getApplication():返回ServletContext中存储的值;
Map<String,Object> getContextMap():返回当前context存储的值;
Map<String,Object> getParamters():返回HttpServletRequest对象里面存储的值,
ValueStack getValueStack():获取OGNL的值栈。
3.值栈的使用
值栈ValueStack被包括在ActionContext中,用来存储对象的,主要通过OGNL表达式来访问,ValueStack有一个特点,如果访问的值栈里有多个对象,且相同的属性在 多个对象中同时出现,则值栈会按照从栈顶到栈底的顺序,寻找第一个匹配的对象。
获取值栈:通过ActionContext.getValueStack()方法即可获取;
如何使用:ValueStack用来存放数据的,常用的方法有:
Object findValue(String expr): 根据表达式在value stack ,按照默认的顺序去获取表达式对应的值;
void setValue(String expr,Object value):根据表达式在value stack,按照默认的访问顺序,向value stack中设置值;
Object peek():获取value stack中的顶层对象,不修改value stack对象;
Object pop():获取value stack中顶层对象,并把这个对象从value stack中移走;
void push(Object o):把对象放入到value stack对象中,并设置为顶层元素。
4.OGNL(对象导航图语言)
它是一种表达式语言,通过简单的语法,可以存取对象的属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。
OGNL的使用:
常量与操作符:在OGNL中,可以使用Java的常量操作和数学运算,String常量可以使用单引号或双引号括起来,但单个字符使用单引号;
访问ValueStack:在OGNL中,没有前缀代表访问了当前值栈,如<s:property value="xxx"/> 这句中的<s:property>标签的value属性的值就是使用OGNL,没有任何前缀,就表示直接访问值栈,然后按照从栈顶到栈底的顺序,寻找第一个匹配的对象。
访问ActionContext:在OGNL中,通过符号#来访问ActionContext中除了值栈外的各种值,如#parameters即当前请求中的参数,#request即请求作用域中的属性,#session即会话作用域中的属性,#application即应用程序作用域的属性。
访问静态属性和方法:在OGNL中,可以通过关键字@来访问任意类中的静态方法和静态属性,格式为“@类的全路径名@属性名称”或“@类的全路径名@方法名称”。
访问域对象:条件是需要有相应的get/set方法,dang shiyong OGNL获取相应的属性的时候,是先对应相应的get/set方法,如果get/set方法已经对应上,则就不会对应属性了,如果get/set方法没有对应上,才去访问属性,当然直接访问执行的话需要属性的权限为public。对于List和Map的访问,同理,必须有get/set方法,list的访问是通过属性名[seq].attribute来访问。Map的访问通过属性名['xxx'].attribute来访问。
ActionContext的访问:
通过使用SessionAware接口来访问存储于ActionContext中的数据,可以在页面通过#session['key']或session.getAttribute("key");同理,也可以使用其他包装接口,如RequestAware,ApplicationAware,ParameterAware;
ServletActionContext的访问:
ServletActionContext直接继承ActionContext,它可以取得的对象有:HttpServletRequest请求对象,HttpServletResponse相应对象,ServletContextServlet上下文信息,PageContext,Http页面上下文。直接通过ServletActionContext的静态方法就可以获的相应的对象。
ActionContext和ServletActionContext的使用原则:优先使用ActionContext,只有ActionContext不能满足功能要求的时候,才使用ServletActionContext.
国际化
让软件实现对多种语言的支持,可以通过简单的设置让软件支持的语言从一种切换到另一种。Struts2的国际化依赖于Java内置的国际化机制,在Java内置的国际化基础上增加了跟Struts2其他组件的融合。
Java内置的国际化
Java内置的国际化,以java.util.ResourceBundle和Java.util.Locale两个类为主,locale类负责选择合适的语言,ResouceBundle负责根据注入的Java.util.Locale对象来选择国际化信息的来源,返回国际化信息。
⑴准备阶段
国家化资源文件,一般准备的文件有以下几个,默认文件,相应的语言文件。每个文件以properties为扩展名,内容以key-value对的形式存在,其中key是如何引用这条信息,value是这条信息真正要显示的内容。则,假设我们需要两种语言,中文,英文,默认中文,则eg:
默认语言文件:message.properties
labela=labela in zh_CN
labelb=labelb in zh_CN
中文语言文件:message_zh_CN.properties,, #代表注释
#labela=labela in zh_CN
#labelb=labelb in zh_CN
英文语言文件:message_en_US.properties
labela=labela in en_US
labelb=labelb in en_US
对于不同国家的语言的命名规则,可以参考这个站点:https://wangxingguang.iteye.com/blog/1861160
⑵使用
将上面的3个文件放到src目录下,然后再类中创建相应的对象进行访问,eg:
Locale locale = Locale.SIMPLIFIED_CHINESE;
ResourceBundle bundle = ResourceBundle.getBundle("message",locale);
System.out.println("bundle=="+bundle.getString("labela");
其他的同理,只需改变locale对应的语言即可,以及绑定资源的文件名。
向国际化资源中传入参数
修改国际化信息为
labela=you are ({0}) super master
通过以下语句就可以将参数放入国际化信息中
String info = MessageFormat.format(message,"xxxx");
如果是多个参数,则主要把传入的参数改成数组就可以了,eg:
String [] params = new String[2];
params[0] = "ld";
params[1] = "19930911";
String info = MessageFormat.format(message,params);
Struts2中的国际化
国际化资源文件不变,需要在struts.xml中设置一个常量:
<constant name="struts.custom.il8n.resources" value="message" />
其中的message是资源文件的公共前缀;
在Jsp中访问资源使用Struts2的text标签:
<s:text name="labela"/>
运行的结果就是在页面上显示默认语言中Key对应的value值。
资源文件的范围级别
全局资源文件:全局资源文件只需要在struts.xml中或者在struts.properties文件中设置常量值struts.custom.il8n.resources即可。如果有多组国际化资源,则使用逗号分隔。
包级资源文件:在当前访问的Action的同包下,声明一组package.properties,如果是中文,则是package_zh_CN.properties,package_en_US.properties等,注意文件名就是package.properties,不是“包的名称.properties".注意将包资源文件必须放到Action类的同包下,如果包资源文件和全局资源文件同时存在,则包级资源文件覆盖全局资源文件中同key的信息。
类级资源文件:在当前访问的Action类的同包下,声明一组以该Action类名为前缀的国际化资源文件,eg:Action类名.properties,Action类名_en_US.properties,Action类名_zh_CN.properties.如果类级资源文件和包级资源文件同时存在,则类级别资源文件覆盖包级资源文件中的同key信息。
参考《研磨Struts2》 建议亲自阅读此书,加深理解。