一、内容提要
1.拦截器的概念及应用
2.STRUTS2自带的拦截器
3.自定义拦截器
4.自定义拦截器的应用
二、拦截器的概念及应用
拦截器(Interceptor)是Struts2的一个重要特性。Struts2框架的大多数核心功能都是通过拦截器来实现的,像避免表单重复提交、类型转换、对象组装、验证、文件上传等,都是在拦截器的帮助下实现的。拦截器之所以称为“拦截器”,是因为它可以在Action执行之前或执行之后拦截调用。
Struts2将它的核心功能放到拦截器中实现而不是分散到Action中实现,有利于系统的解耦,使得功能的实现类类似于个人电脑的组装,变成了可插拔的。需要某个功能就“插入”一个拦截器,不需要某个功能就“拔出”。
拦截器应用:
- 为action动态添加输入验证
- 对象组装(也就是进行数据类型转换)
- 权限控制
- 日志记录等
三、STRUTS2自带的拦截器
Struts2本身提供了很多的拦截器,这些拦截器已经在struts-default.xml文件中定义,在Web应用程序中可以直接引用这些拦截器。这也是为什么struts配置文件里经常有这样一个属性extends="struts-default",加载Struts2本身提供的拦截器。
具体情况如下:
序号 |
拦截器名称 |
作用 |
1 |
alias |
在请求之间转换名字不同的相似参数 |
2 |
chain |
将所有的属性从前一个Aciotn复到当前Action中 |
3 |
params |
最基本的一个拦截器,负责解析HTTP请求中的参数,并将参数值设置成Action对应的属性值 |
4 |
cookie |
基于cookie的名/值设置Action的属性 |
5 |
conversionError |
将类型转换错误从ActionContext中取出,添加到Action字段错误中 |
6 |
createSession |
自动创建一个HttpSession对象 |
7 |
debugging |
当struts.devMode属性设置为true,才有,用于调试 |
8 |
execAndWait |
可以用于防止后台Action Http请求超时 |
9 |
exception |
提供了异常处理的核心功能 |
10 |
fileUpload |
用于对文件上传提供支持 |
11 |
i18n |
用于支持国际化 |
12 |
timer |
负责输出action的执行时间,用于分析action |
13 |
token |
检查传到Action的token值的有效性,防表单重复提交 |
四、自定义拦截器
作为“框架(framework)”,可扩展性是不可或缺的,因为世上没有放之四海而皆准的东西。虽然,Struts 2为我们提供如此丰富的拦截器实现,但是这并不意味我们失去创建自定义拦截器的能力,恰恰相反,在Struts 2自定义拦截器是相当容易的一件事。
在Struts2中编写拦截类,有如下二种方式:
实现Interceptor此接口
继承AbstractInterceptor类(一般会选择此种方式)
案例:
编写拦截器类:
注意:在编写拦截器时要注意,拦截器必顺是无状态的,换句话 说,在拦截器类中不应该有实例变量。这是因为struts2对每一个Action的请求使用的是同一个拦截器实例来处理,如果拦截器有状态,在多线程并发情况下,拦截器的状态将不可预测。
package com.silvan.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class AroundInterceptor extends AbstractInterceptor { public void init() { System.out.println("这是一个初始化方法"); } public String intercept(ActionInvocation invocation) throws Exception { String result = ""; System.out.println("我是在action的execute方法执行之前动作"); result = invocation.invoke(); System.out.println("我是在action的execute方法执行之后动作"); return result; } public void destroy() { System.out.println("这是一个清理方法"); } }
Struts.xml配置拦截器
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="InterceptorDemo" extends="struts-default"> <!--在这里定义拦截器 --> <interceptors> <interceptor name="around" class="com.silvan.interceptor.AroundInterceptor" /> </interceptors> <action name="interceptor" class="com.silvan.action.InterceptorAction"> <result>/index.jsp </result> <!--在这里使用拦截器,当使用自定义的拦截器后,默认的拦截器将失效,这样原本struts提供的拦截器功能就会失效,比如用于类型转换的params拦截器 --> <interceptor-ref name="around"/> </action> </package> </struts>
Action类
public class InterceptorAction extends ActionSupport { private int id; private String userName; @Override public String execute() throws Exception { System.out.println("执行interceptor Action……"); return SUCCESS; } //Get/set…… }
页面显示Login
<form action="interceptor"> <table> <tr><td>编号:<input type="text" name="id" value="1"></td></tr> <tr><td>姓名:<input type="text" name="userName" value="ross"></td></tr> <tr><td><input type="submit" value="submit"></td></tr> </table> </form>
返回显示index
<body> 编号:<s:property value="id"/><br/> 用户名:<s:property value="userName"/> </body>
当自定义了拦截器后,默认的拦截器将失效, index页面取不到登录的值,所以需要引入默认的拦截器。配置如下:
Struts.xml配置拦截器
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="InterceptorDemo" extends="struts-default"> <!--在这里定义拦截器 --> <interceptors> <interceptor name="around" class="com.silvan.interceptor.AroundInterceptor" /> <!-- 定义拦截器栈 --> <interceptor-stack name="myStack"> <!--引用拦截器 --> <interceptor-ref name="around"></interceptor-ref> <!-- 引入默认的拦截器 --> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <!—针对包引用拦截器,这样就不仅仅对某个action起作用 --> <!-- <default-interceptor-ref name="mystack"/> --> <action name="interceptor" class="com.silvan.action.InterceptorAction"> <result>/index.jsp </result> <!—引用拦截器栈 --> <interceptor-ref name="myStack"/> </action> </package> </struts>
Struts.xml配置多个拦截器方式:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="InterceptorDemo" extends="struts-default"> <!--在这里定义拦截器 --> <interceptors> <interceptor name="around" class="com.silvan.interceptor.AroundInterceptor" /> <interceptor name="around1" class="com.silvan.interceptor.AroundInterceptor1" /> <!-- 定义拦截器栈 --> <interceptor-stack name="myStack"> <!--引用拦截器 --> <interceptor-ref name="around"></interceptor-ref> <interceptor-ref name="around1"></interceptor-ref> <!-- 引入默认的拦截器 --> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <!-- <default-interceptor-ref name="mystack"/> --> <action name="interceptor" class="com.silvan.action.InterceptorAction"> <result>/index.jsp </result> <interceptor-ref name="myStack"/> </action> </package> </struts>
五、练习
需求分析
在一个系统中,如果用户没有选择登录系统就直接使用相应的资源,从常理上来讲这是不允许的。也就是说在当用户访问受保护资源时,拦截器截获用户请求,判断用户是否已经登录,如果没有登录,则向用户显示登录页面,请求用户登录如果用户已经登录,则向用户显示资源。
Action
public String execute() throws Exception { System.out.println("执行interceptor Action……"); if(userName!=null){ ActionContext context = ActionContext.getContext(); Map<String,Object> session = context.getSession(); session.put("userName", userName); } return SUCCESS; }
Interceptor
public String intercept(ActionInvocation invocation) throws Exception { String result = ""; System.out.println("我是在action的execute方法执行之前动作"); String user =(String) ActionContext.getContext().getSession().get("userName"); if(user!=null && "".equals(user)){ System.out.println("非法访问……"); return "error_login"; } result = invocation.invoke(); System.out.println("我是在action的execute方法执行之后动作"); return result; }
配置
<!-- <global-results name="error_login">/login.jsp</global-results> --> <!-- <default-interceptor-ref name="mystack"/> --> <action name="interceptor" class="com.silvan.action.InterceptorAction"> <result>/index.jsp </result> <result name="error_login">/login.jsp</result> <interceptor-ref name="myStack"/> </action>
思考:过滤器和拦截器的区别?