Intercetor, 即为拦截器。
1) 在Struts2中,把每一个功能都用一个个的拦截器实现;用户想用struts的哪个功能的时候,可以自由组装使用。
2)Struts2中,为了方法用户对拦截器的引用,提供了拦截器栈的定义,里面可以包含多个拦截器。 文件夹(文件, 文件2) 拦截器栈(拦截器,拦截器2)
3)Struts2中,如果用户没有指定执行哪些拦截器,struts2有一个默认执行的栈,defaultStack;
一旦如果用户有指定执行哪些拦截器,默认的拦截器栈就不会被执行
拦截器的设计,就是基于组件设计的应用!
1.自定义拦截器
1.1 编写辅助测试用action
public class HelloAction extends ActionSupport{
public HelloAction() {
System.out.println("1. Action实例创建了");
}
@Override
public String execute() throws Exception {
System.out.println("3. 执行了请求处理的方法: execute");
return super.execute();
}
}
1.2 编写拦截器类
public class HelloInterceptor implements Interceptor{
// 启动时候执行
public HelloInterceptor(){
System.out.println("创建了拦截器对象");
}
// 启动时候执行
@Override
public void init() {
System.out.println("执行了拦截器的初始化方法");
}
// 拦截器业务处理方法 (在访问action时候执行? 在execute之前执行?)
@Override
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("2. 执行Action之前");
// 调用下一个拦截器或执行Action (相当于chain.doFilter(..)
// 获取的是: execute方法的返回值
String resultFlag = invocation.invoke();
System.out.println("4. 拦截器,业务处理-结束" + resultFlag);
return resultFlag;
}
@Override
public void destroy() {
System.out.println("销毁....");
}
}
1.3 进行相关配置
<struts>
<package name="hello" extends="struts-default">
<!-- 【拦截器配置】 -->
<interceptors>
<!-- 配置用户自定义的拦截器 -->
<interceptor name="helloInterceptor" class="cn.itcast.a_interceptor.HelloInterceptor"></interceptor>
<!-- 自定义一个栈: 要引用默认栈、自定义的拦截器 -->
<interceptor-stack name="helloStack">
<!-- 引用默认栈 (一定要放到第一行)-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 引用自定义拦截器 -->
<interceptor-ref name="helloInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 【执行拦截器,第一种写法: 当前包下所有的acntion都执行helloStack栈】
<default-interceptor-ref name="helloStack"></default-interceptor-ref>
-->
<!-- Action配置 -->
<action name="hello" class="cn.itcast.a_interceptor.HelloAction">
<!--执行拦截器,第二种写法: 只是在这一个Action中执行helloStack栈
<interceptor-ref name="defaultStackt"></interceptor-ref>
<interceptor-ref name="helloInterceptor"></interceptor-ref>
-->
<!--执行拦截器,第三种写法:执行用户栈(与第二种写法一样, 只在当前aciton中执行自定义栈)-->
<interceptor-ref name="helloStack"></interceptor-ref>
<result name="success">/index.jsp</result>
</action>
</package>
</struts>
当我们访问helloAction时效果如下:
可以看到,如过滤器一样,拦截器的构造方法和初始化也是在tomcat服务器启动时执行,当用户访问action时,先创建action实例,然后执行过滤器intercept方法,再执行action的execute方法,执行完后回到intercept。最扣在tomcat停止服务时会销毁拦截器对象。生命周期时序图如下:
2.国际化
对比servlet的国际化,struts里面更简单
2.1 步骤
a). 写资源文件
基础名.properties 【默认的语言环境的配置】
基础名_语言简称_国家简称.properties
b). 读取资源文件,再使用
程序:ResourceBundle (同servlet)
JSP:
1)jstl表亲啊 (同servlet)
2)struts标签获取资源文件内容
2.2 实例
1. 写资源文件
Msg.properties 默认的语言环境; 找不到配置就找它
Msg_en_US.properties 美国
2. 加载
<!-- struts.xml 通过常量加载资源文件 -->
<constant name="struts.custom.i18n.resources" value="cn.acamy.config.msg"></constant>
3. 使用: 标签name值直接写配置文件中的key
<%@taglib uri="/struts-tags" prefix="s" %>
<s:text name="title"></s:text>
推荐用法:
<s:i18n name="cn.acamy.config.msg">
<s:text> 标签必须放到标签体中。
</s:i18n>
3.Ognl表达式
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
3.1 OgnlContext 的用法
OGNL 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map 的接口。
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.junit.Test;
// OgnlContext用法
public class OgnlDemo1 {
/**
* 1. Ognl表达式语言语言取值,取非根元素的值,必须用#号
* @throws Exception
*/
@Test
public void testOgnl() throws Exception {
// 创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
// 放入数据
User user = new User();
user.setId(100);
user.setName("Jack");
// 【往非根元素放入数据, 取值的时候表达式要用"#"】
context.put("user", user);
// 获取数据(map)
// 先构建一个Ognl表达式, 再解析表达式
Object ognl = Ognl.parseExpression("#user.name");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
/**
* 2. Ognl表达式语言语言取值,取根元素的值,不用带#号
* @throws Exception
*/
@Test
public void testOgn2() throws Exception {
// 创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
// 放入数据
User user = new User();
user.setId(100);
user.setName("Jack");
// 【往根元素放入数据】
context.setRoot(user);
// 获取数据(map)
// 先构建一个Ognl表达式, 再解析表达式
Object ognl = Ognl.parseExpression("address.province");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
/**
* 3.Ognl对 静态方法调用的支持
* @throws Exception
*/
@Test
public void testOgn3() throws Exception {
// 创建一个Ognl上下文对象
OgnlContext context = new OgnlContext();
// Ognl表单式语言,调用类的静态方法
//Object ognl = Ognl.parseExpression("@Math@floor(10.9)");
// 由于Math类在开发中比较常用,所以也可以这样写
Object ognl = Ognl.parseExpression("@@floor(10.9)");
Object value = Ognl.getValue(ognl, context, context.getRoot());
System.out.println(value);
}
}
3.2 ValueStack
ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础。
ValueStack贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象.Struts2框架把 ValueStack 对象保存在名为 “struts.valueStack” 的request请求属性中。
3.2.1 ValueStack的获取
// 获取值栈对象的2种方式
private void getVs() {
// 获取值栈对象,方式1:
HttpServletRequest request = ServletActionContext.getRequest();
ValueStack vs1 = (ValueStack) request.getAttribute("struts.valueStack");
// 获取值栈对象,方式2:
ActionContext ac = ActionContext.getContext();
ValueStack vs2 = ac.getValueStack();
System.out.println(vs1 == vs2);// true
}
3.2.2 ValueStack的数据结构
通过调试可以看到:struts中的ValueStack为其实现类OgnlValueStack,核心包含了作为Map栈的OgnlContext对象和继承了ArrayList的对象栈的CompoudRood对象,其中OgnlContext还封装了CompoudRood对象。
数据结构图如下:
对象栈: Struts 把动作和相关对象压入 ObjectStack 中--List
Map栈: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中
Struts 会把下面这些映射压入 ContextMap 中
parameters: 该 Map 中包含当前请求的请求参数
request: 该 Map 中包含当前 request 对象中的所有属性
session: 该 Map 中包含当前 session 对象中的所有属性
application:该 Map 中包含当前 application 对象中的所有属性
attr: 该 Map 按如下顺序来检索某个属性: request, session, application
3.3 Ognl表达式
3.3.1 #的作用
a) 用来区分访问的是Map栈不审List栈
#号主要用于访问访问Map栈信息,不使用#号主要用于访问List(对象栈)信息。
举例:
<s:property value="#request.username"/>
<s:property value="#request.userpsw"/>
<s:property value="address"/> // 获取对象栈信息(默认从栈顶检索)
Struts2的property 标签中value属性值会特意的将其中的值以OGNL表达式的方式进行运行。
b) 在JSP页面构建Map集合
格式:#{key:value,key:value...}
举例
Struts2的radio标签主要任务是在页面中显示单选按钮
<s:radio list="#{'male':'男','female':'女'}" name="gender"></s:radio><br/>
运行结果源码:
<input type="radio" name="gender" id="gendermale" value="male"/>男
<input type="radio" name="gender" id="genderfemale" value="female"/>女
3.3.2 $号的作用
$号的作用
在国际化资源文件中,引用OGNL表达式
在Struts2配置文件中,引用OGNL表达式
举例
ognl.xml配置文件
<action name="ognlAction_*" class="cn.itcast.ognl.OgnlAction" method="{1}">
<result name="success">/ognl/ognl.jsp?username=${#request.username}</result>
</action>
在ognl.jsp中获取携带的参数:
<s:property value="%{#parameters.username[0]}"/>
3.3.3 %号的作用
$号的作用
“%”符号的作用是在当Struts2标签的属性值为OGNL表达式时OGNL表达式却被理解为字符串类型原样输出时,用于通知执行环境%{}里的是OGNL表达式。
举例
Struts2中的textfield标签主要用于在页面中显示一个文本输入框数据。类似input
<s:textfield value="#request.username"></s:textfield>
此时#request.username被理解为一个普通的字符串,因此直接显示。因为这里脱离了
运行OGNL的环境即:<s:property value="OGNL表达式"/>环境。
通知运行环境将#request.username以OGNL表达式运行:
<s:textfield value="%{#request.username}"></s:textfield>
总结
为了方便使用%{}我们可以在任何地方都直接添加%{}来确保运行OGNL表达式:
<s:property value="%{#request.username}"/>
4.Struts2标签
4.1 if/elseif/else标签
if/elseif/else 基本的流程控制.‘If’标签可单独使用也可以和‘Else If’标签和(或)一个多个‘Else’一起使用
<s:if test="#person.age<24">少年</s:if>
<s:elseif test="#person.age<26">中年</s:elseif>
<s:else>老年</s:else>
4.2 property标签
用于输出指定值:
格式:
<s:property value=“#name" default="a default value" />
default:可选属性, 如果需要输出的属性值为null,则显示该属性指定的值
escape:可选属性,指定是否格式化HTML代码。
value: 可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值。
举例:
<s:property value="#user.id"/>
<s:property/>:输出栈顶的值
4.3 debug标签
struts的调试标签:可以观测值栈数据
<s:debug></s:debug>
4.4 iterator标签
用于对集合进行迭代,这里的集合包含List、Set和数组。
<!-- list迭代 -->
<s:iterator var="user" value="#request.list" status="st">
<s:property value="#user.id"/>
<s:property value="#user.name"/>
</s:iterator>
<!-- map迭代 -->
<s:iterator var="en" value="#request.map" status="st
<s:property value="#en.key"/>
<s:property value="#en.value.name"/>
</s:iterator>
<!-- Ognl表达式可以取值,也可以动态构建集合 -->
<br/>一、.构建 list集合</br>
<s:iterator var="str" value="{'a','b'}">
<s:property value="#str"/>
</s:iterator>
<br/>一、.构建 map集合</br>
<s:iterator var="en" value="#{'cn':'China','usa':'America'}">
<s:property value="#en.key"/>
<s:property value="#en.value"/> <br/>
</s:iterator>