struts2学习_06
1、拦截器概述
- Struts2框架中提供的许多功能都是使用拦截器实现的,包括异常处理,文件上传,生命周期回调和验证等。事实上,由于Struts2将其大部分功能基于拦截器,因此不太可能为每个action分配7个或8个拦截器。
- 拦截器在概念上与servlet过滤器或JDK代理类相同。拦截器允许横切功能,把action以及框架分开实现。你可以使用拦截器实现以下操作:
在调用action之前提供预处理逻辑。
在调用action后提供后处理逻辑。
捕获异常,以便可以执行备用处理。
拦截器在action对象创建之后,action的方法执行之前执行
默认执行的拦截器
<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="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<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-ref name="debugging"/>
<interceptor-ref name="deprecation"/>
</interceptor-stack>
2、拦截器底层原理
拦截器底层使用两个原理
aop思想和责任链模式
1 aop思想
Aop是面向切面编程,是一种编程思想,没有具体的实现代码,简单来说就是不通过修改源代码方式扩展功能
2 责任链模式
- 在java中有很多的设计模式,责任链模式是其中的一种
- 责任链模式和过滤链很相似的
- 责任链模式:
要执行多个操作,有添加、修改、删除三个操作。
首先执行添加操作,添加操作执行之后 做类似于放行操作,再执行修改操作,修改操作执行之后做类似于放行操作,再执行删除操作 - 过滤链:
一个请求可有多个过滤器进行过滤,只有通过当前过滤器才能到达下一个过滤器
3 aop思想和责任链模式如何应用到拦截器里面
- 拦截器在action对象创建之后,action的方法执行之前执行
- 在action方法执行之前执行默认拦截器,执行过程使用aop思想,在action没有直接调用拦截器的方法,使用配置文件方式进行操作
- 在执行拦截器时候,执行很多的拦截器,这个过程使用责任链模式。只有通过当前过滤器才能到达下一个过滤器,通过了所有的过滤器才会执行方法
过程:
- 执行action
execute.executeAction(request, response, mapping);
- 创建action对象,使用动态代理方式
ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false);
- 执行action的方法
proxy.execute();
- 执行很多的拦截器,遍历执行
if ( interceptors .hasNext()) {
- 执行类似放行操作的方法
return invocation.invoke();
3、过滤器和拦截器区别
- 拦截器是基于java的反射机制的,而过滤器是基于函数回调
- 拦截器不依赖于servlet容器,过滤器依赖于servlet容器
- 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用(包括action、servlet、jsp、html等等)
- 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问
- 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时初始化一次。
4、Servlet和action区别
- servlet默认第一次访问时候创建,创建一次,单实例对象
- action每次访问时候创建,创建多次,多实例对象
5、自定义拦截器
- 在struts2里面有很多的拦截器,这些拦截器是struts2封装的功能,但是在实际开发中,struts2里面的拦截器中可以没有要使用的功能,这个时候需要自己写拦截器实现功能
- 拦截器结构
(1)查看源代码拦截器结构
继承AbstractInterceptor
类
class ModelDrivenInterceptor extends AbstractInterceptor
打开AbstractInterceptor
类
class AbstractInterceptor implements Interceptor
有三个方法:
void init()
初始化方法
void destroy()
销毁方法
String intercept(ActionInvocation invocation) throws Exception
拦截逻辑操作
(2)开发中,建议使用另外一种方式
写类,继承 MethodFilterInterceptor类实现
让action里面某个的方法不进行拦截
(3)让拦截器和action产生关联
不是在action调用拦截器的方法,而是通过配置文件方式让建立关系
6、自定义登陆拦截器
- 需求:在项目中,有很多的action的超链接,需要实现只有在登录的状态下,才可以点击action的超链接实现功能,如果不是登录状态,点击action超链接则返回到登录页面
- 登录的状态:使用session域对象实现
(1)登录成功之后,把数据放到session里面
(2)判断session是否有值,可以知道是否是登录状态 - 实现登录的基本功能
public String login() {
//得到request对象
HttpServletRequest request = ServletActionContext.getRequest();
String userName = request.getParameter("userName");
String passWord = request.getParameter("passWord");
//判断用户名和密码是否正确(示例,没有连接数据库操作)
if(userName.equals("admin") && passWord.equals("123456")) {
//验证成功向session放值
request.getSession().setAttribute("userName", userName);
return "loginSuccess";
}else {
//失败,回到登陆页面
return "loginUI";
}
}
- 添加登录拦截器功能
(1)判断是否登录:判断session里面是否有名称是username的值
(2)拦截器实现过程
第一步 创建类,继承MethodFilterInterceptor类
第二步 重写MethodFilterInterceptor类里面的方法写拦截器逻辑
public class Loginintercept extends MethodFilterInterceptor {
//在这个方法里写拦截器逻辑
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
//判断session中是否有userName值
//得到session
HttpServletRequest request = ServletActionContext.getRequest();
Object object = request.getSession().getAttribute("userName");
//判断
if(object != null) {
//session中有值,登录状态
//告诉struts2可以继续执行下面的方法
return invocation.invoke();
}else {
//session中没有值,未登录
//不继续执行下面的action,返回登录页面
//到struts.xml中result标签中,把返回值配置到登录页面或其他提示页面
return "loginUI";
}
}
}
第三步 配置action和拦截器关系(注册拦截器)
(1)在要拦截的action标签所在的package标签里声明拦截器
<!-- 声明拦截器 -->
<interceptors>
<interceptor name="loginIntercept" class="cn.com.action.Loginintercept"></interceptor>
</interceptors
(2)在具体的action中使用声明的拦截器
<!-- 使用自定义拦截器 -->
<interceptor-ref name="loginIntercept"></interceptor-ref>
(3)struts2里面执行很多的默认拦截器,但是如果在action里面配置自定义拦截器
默认拦截器就不会执行
需要手动启用默认拦截器
<!-- 手动启用默认拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
- 配置拦截器,对action里面方法进行拦截
(1)在action里面有login的登录的方法,这个方法不需要拦截,如果这个方法都拦截,问题是,永远登录不进去了(拦截器默认拦截action中所有方法)
(2)让login方法不进行拦截
<!-- 使用自定义拦截器 -->
<interceptor-ref name="loginIntercept">
<!-- 配置action中某些方法不进行拦截 -->
<!-- neme属性:excludeMethods -->
<!-- 值为不进行拦截的方法名 -->
<param name="excludeMethods">login</param>
</interceptor-ref>
注:如果出现嵌套的页面,在提交表单的form标签中加上target="_parent"