Struts2框架学习之六:理解并使用拦截器

来源:互联网 发布:彩卡网络下单系统 编辑:程序博客网 时间:2024/05/19 17:48

前言

拦截器是Struts2框架的核心功能,理解并使用拦截器有助于更灵活使用Struts2。拦截器与Servlet中的过滤器有些类似却又不尽相同。因为在Struts2中拦截器更像一个可插拔的组件,围绕Action和Result进行,可以在方法调用之前、之后使用。通过Struts2的工作流程(后面还会看到一个请求在Struts2中详细的执行流程)可以发现调用一个Action之前之后有许多的拦截器,这些拦截器都通过后才执行具体的action。对于每一个拦截器来说,可以直接返回,从而终止余下的拦截器。

从Struts2的工作流程说起

首先请看截取自官方的一张图:

struts2工作流程

从图中可以看到,从一个具体的请求到Action需要经过多个拦截器,action处理完毕之后,后续的拦截器会继续执行,最终到浏览器中。Struts2的工作流程如下:

  1. 请求发送给StrutsPrepareAndExecuteFilter
  2. StrutsPrepareAndExecuteFilter判断该请求是否是一个Struts2请求,如果是则进入第3步
  3. 如果是Struts2请求,则把请求交给ActionProxy,是Action的代理类
  4. ActionProxy创建一个ActionInvocation实例,并进行初始化
  5. 在执行具体的Action之前,ActionProxy会涉及相关拦截器的调用
  6. Action调用结束之后,会根据struts.xml文件中action的result配置对象得到对应的返回结果。调用execute方法之后,对返回结果进行渲染
  7. 执行后面的拦截器
  8. 把结果返回给浏览器

从整个请求处理过程来看,拦截器是处理的关键。ok,通过以上请求处理过程,我们知道了一个拦截器在Struts2中的工作方式。下面从编写一个简单的拦截开始,学习使用拦截器。

一个简单的拦截器

主要有两种方式:

  • 实现Interceptor接口
  • 继承AbstractInterceptor抽象类

编写自己的拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口,该接口有三个方法:init()、destroy()、intercept()。init方法在拦截器实例创建之后,intercept方法之前调用,主要用于初始化拦截器所需要的资源;destroy方法在拦截器实例销毁之前调用,用于销毁init初始化分配的资源;intercept方法则是在Action执行之前调用,可以通过invocation对象获取Action的状态,从而根据状态的不同进行需要的拦截操作。

下面以实现Interceptor接口为例,编写一个计算Action执行execute方法的时间的拦截器。代码如下:

package interceptor;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.Interceptor;public class TimeIntercptor implements Interceptor {    private static final long serialVersionUID = 1L;    @Override    public void destroy() {    }    @Override    public void init() {    }    @Override    public String intercept(ActionInvocation invocation) throws Exception {        long start = System.currentTimeMillis();        //执行action的execute方法        String result = invocation.invoke();        long end = System.currentTimeMillis();        System.out.println("执行execute方法的时间是" + (end - start));        return result;    }}

在编写一个action并在struts.xml配置文件中进行配置,在浏览器中进行测试就可以得到执行execute方法的具体时间了。在编写拦截器类的时候需要注意:在拦截器中不应该有实例变量,因为拦截器是无状态的,无状态的解释是如果拦截器有状态,那么在多线程同时访问拦截器实例的时候,拦截器的状态是不可预知的。

至此,我们已经学会了如何编写一个简单的拦截器,下面介绍在拦截器中自带的拦截器哟哪些。

Struts2中自带的拦截器

自带的拦截器可以在struts-default.xml文件中得到,主要有:

  • execAndWait(该拦截器可以让需要运行较长时间的action在后台运行,并向用户显示进度信息)
  • exception(主要用于异常处理)
  • fileUpload(用于文件上传)
  • i18n(国际化的支持)
  • logger(日志,记录action的开始于结束日志)
  • modelDriven(支持模型驱动的拦截器)
  • validation(定义自己的验证器)

开发安全验证功能的拦截器

在日常开发中,进行登录验证是很常见的。这里开发的拦截器主要实现的功能是:如果用户没有登录则提示没有登录的信息,并返回到登录页面。如果用户已经登录,则显示资源。这里主要介绍实际开发中拦截器的开发步骤。

步骤1:编写基本页面

登录页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s" %><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <base href="<%=basePath%>">    <title>登录</title>    <s:head/>  </head></html><s:form action="login2">    <s:actionerror/>    <s:textfield label="用户名" name="user.username"></s:textfield>    <s:password label="密码" name="user.password"></s:password>    <s:submit value="登录"></s:submit></s:form>

登录成功页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="/struts-tags" prefix="s" %><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <base href="<%=basePath%>">    <title>登录 | 成功</title>  </head>  <body>    <h3>        <s:property value="user.username"/>,欢迎访问struts2官方网站!    </h3>  </body></html>

资源页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <base href="<%=basePath%>">    <title>绝密资源</title>  </head>  <body>    <strong>这是绝密资源!</strong>  </body></html>

步骤二:编写Action
LoginAction2.java:

package action;import java.util.Map;import org.apache.struts2.interceptor.SessionAware;import bean.User;import com.opensymphony.xwork2.ActionSupport;public class LoginAction2 extends ActionSupport implements SessionAware {    private static final long serialVersionUID = 1L;    private User user;    private Map<String, Object> session;    //通过login!input来访问login.jsp    public String input() throws Exception{        return INPUT;    }    @Override    public String execute() throws Exception {        if("admin".equals(user.getUsername()) && "admin".equals(user.getPassword())){            System.out.println(user.getUsername()+"=" + user.getPassword());            session.put("user", user);            return SUCCESS;        }else{            addActionError("登录失败!");            return INPUT;        }    }    @Override    public void setSession(Map<String, Object> session) {        this.session = session;    }    public User getUser() {        return user;    }    public void setUser(User user) {        this.user = user;    }}

步骤四:编写拦截器

代码如下:

package interceptor;import java.util.Map;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class AuthenticationInterceptor extends AbstractInterceptor {    private static final long serialVersionUID = 1L;    /**     * 对登录与否进行拦截验证     */    @Override    public String intercept(ActionInvocation invocation) throws Exception {        ActionContext context = ActionContext.getContext();        Map<String, Object> session = context.getSession();        Object user = session.get("user");        if(user == null){            //如果用户未登录,则返回登录页面,并添加错误信息            ActionSupport action = (ActionSupport) invocation.getAction();            action.addActionError("您还没有登录,请先登录!");            return action.LOGIN;        }else{            //如果用户已经登录,则执行后面的拦截器方法            return invocation.invoke();        }    }}

步骤五:在struts.xml中进行配置

    <interceptors>         <interceptor name="auth" class="interceptor.AuthenticationInterceptor" />             <interceptor-stack name="securityStack">                 <interceptor-ref name="defaultStack" />                 <interceptor-ref name="auth" />             </interceptor-stack>     </interceptors>         <global-results>            <result name="login">/WEB-INF/pages/login.jsp</result>        </global-results>    <action name="login2" class="action.LoginAction2">            <result name="input">/WEB-INF/pages/login.jsp</result>            <result>/WEB-INF/pages/success.jsp</result>    </action>        对于受保护的资源引用上面的拦截器即可    <action name="resource" class="action.ResourceAction">            <result>/WEB-INF/pages/resource.jsp</result>            <interceptor-ref name="annotatedStack" />    </action>

步骤六:在浏览器中输入http:localhost:8090/struts2/login2!input进行测试。

至此,一个安全验证的拦截器就开发完毕。

拦截器小结

从开发过程可以看待,拦截器的作用是Action的某个状态进行拦截操作,使用拦截器可以更方便处理业务逻辑。除了以上方式的开发拦截器外还有注解方式,不过注解方式的一个明显缺点是不利于代码的复用,而且注解的底层使用反射的方式完成的,所以使用注解开发,性能是一个值得考虑的问题。

0 0
原创粉丝点击