zoukankan      html  css  js  c++  java
  • struts入门四之拦截器

    前言

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

    以上内容转载自https://blog.csdn.net/u011116672/article/details/50381656

  • 相关阅读:
    Delphi中多标签页面的实现
    选择排序
    关于Delphi中TRttiContext.FindType失效的问题
    Delphi中拖动无边框窗口的5种方法
    集中精力做最有价值的事情,而不必把主要精力都浪费在自我包装上(例如学位,头衔,自吹自擂)——沉痛反思:我以前还真是这样
    QModelIndex有internalPointer()函数,可以存任何数据,另有QAbstractItemModel::createIndex来创造节点
    沉没成本——无法收回的成本,但不要影响下一次决策
    使用HttpURLConnection实现多线程下载
    Delphi6/7 中XML 文档的应用
    delphiXE调用Objective-c库
  • 原文地址:https://www.cnblogs.com/chiwang/p/9371664.html
Copyright © 2011-2022 走看看