Web开发最佳实践-Struts2之三拦截器(Interceptor)

一、拦截器

  • Struts2拦截器是在访问某个Action或Action的某个方法之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现
  • AOP:面向切面编程,其实现原理:动态代理模式
  • 拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个Action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也提供了一种可以提取Action中可重用的代码方式
  • 拦截器栈(Interceptor Stack):Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截器的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用
  • 拦截器在设计和程序结构上的优点:
    • 拦截器能把很多功能从Action中独立出来,分散到不同的拦截器里面,减少了Action的代码。拦截器和Action本身的功能都更单一了。当通用的功能代码被封装在拦截器里面(代码模块化),就可以对不同的Action,根据功能需要,来配置相应功能的拦截器了。提高了拦截器所实现的功能的重用性,也变相实现了装配式和可插拔式的体系结构,使得整个系统结构变得更灵活。

二、Struts2执行流程

Struts2执行流程.png
  • 1、客户端发送请求
  • 2、该请求经过一系列的过滤器(Filter):其中可选过滤器ActionContextCleanUp,帮助Struts2和其他框架集成。例如:SiteMesh Plugin
  • 3、接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper,来决定该请求是否需要调用某个Action
  • 4、若ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
  • 5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类
  • 6、ActionProxy创建一个ActionInvocation的实例
  • 7、ActionInvocation实例调用Action的前后,涉及到相关拦截器(Intercepter)的调用
  • 8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果是一个JSP或其他页面(也可以是其他的Action链)。JSP页面展现可使用Struts2框架中的标签(该过程会涉及ActionMapper)。

三、Struts2内置拦截器

        
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            

            
            
                
            

            
            
                
                
                
                
                
                
                
                
                
            

            
            
                
                
                
            

            
            
                
                
            

            
            
                
                
            

            
            
                
                
            

            
            
                
                
            

            
            
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                    input,back,cancel,browse
                
                
                    input,back,cancel,browse
                
            

            
            
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                    input,back,cancel,browse
                
                
                    input,back,cancel,browse
                
                
            

            
            
                
            

            
            
                
                    input,back,cancel
                
                
                
                    input,back,cancel
                
            

       

1、常见拦截器

1:params拦截器
这个拦截器偷偷的把请求参数设置到相应的Action的属性去的,并自动进行类型转换。

2.modelDriven拦截器
如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中。

3.execption拦截器
顾名思义,在抛出异常的时候,这个拦截器起作用。最好把它放在第一位,让它能捕获所有的异常。

4.validation拦截器
调用验证框架读取 *-validation.xml文件,并且应用在这些文件中声明的校验。

5.token拦截器
核对当前Action请求(request)的有效标识,防止重复提交Action请求。

6.fileUpload拦截器
用来处理文件上传

7.workflow拦截器
调用Action的validate方法,一旦有错误返回,重新定位到INPUT结果视图

8.servletConfig
通过感知接口,获取感应对象

9.store:保证在两次请求之间共享数据的.

2、servletConfig拦截器原理

  • 实现ServletRequestAware接口
package com.revanwang.servlet;


import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//1、通过让Action类去实现感知接口.
public class ActionServlet1 extends ActionSupport implements
        ServletRequestAware, //获取 HttpServletRequest 对象
        ServletResponseAware
{

    private HttpServletRequest request;
    private HttpServletResponse response;

    @Override
    public void setServletRequest(HttpServletRequest httpServletRequest) {
        this.request = httpServletRequest;
    }

    @Override
    public void setServletResponse(HttpServletResponse httpServletResponse) {
        this.response = httpServletResponse;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(this.request.getParameter("name")+"--"+this.response);
        return NONE;
    }

}
  • 从struts2-core-2.5.20.jar中struts-default.xml中

  • ServletConfigInterceptor源码
public class ServletConfigInterceptor extends AbstractInterceptor implements StrutsStatics {
    private static final long serialVersionUID = 605261777858676638L;

    public ServletConfigInterceptor() {
    }

    public String intercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();
        ActionContext context = invocation.getInvocationContext();
        HttpServletRequest request;
        if (action instanceof ServletRequestAware) {
            request = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
            ((ServletRequestAware)action).setServletRequest(request);
        }

        if (action instanceof ServletResponseAware) {
            HttpServletResponse response = (HttpServletResponse)context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");
            ((ServletResponseAware)action).setServletResponse(response);
        }

        if (action instanceof ParameterAware) {
            context.getParameters().applyParameters((ParameterAware)action);
        }

        if (action instanceof HttpParametersAware) {
            ((HttpParametersAware)action).setParameters(context.getParameters());
        }

        if (action instanceof ApplicationAware) {
            ((ApplicationAware)action).setApplication(context.getApplication());
        }

        if (action instanceof SessionAware) {
            ((SessionAware)action).setSession(context.getSession());
        }

        if (action instanceof RequestAware) {
            ((RequestAware)action).setRequest((Map)context.get("request"));
        }

        if (action instanceof PrincipalAware) {
            request = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
            if (request != null) {
                ((PrincipalAware)action).setPrincipalProxy(new ServletPrincipalProxy(request));
            }
        }

        if (action instanceof ServletContextAware) {
            ServletContext servletContext = (ServletContext)context.get("com.opensymphony.xwork2.dispatcher.ServletContext");
            ((ServletContextAware)action).setServletContext(servletContext);
        }

        return invocation.invoke();
    }
}
  • 执行过程
        Object action = invocation.getAction();
        ActionContext context = invocation.getInvocationContext();
        HttpServletRequest request;
        if (action instanceof ServletRequestAware) {
            request = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
            ((ServletRequestAware)action).setServletRequest(request);
        }

1:通过invocation.getAction()来获取自定义Action类,然后在判断该Action类是否实现ServletRequestAware接口,如果实现ServletRequestAware接口,就会调用自定义Action类中的setServletRequest方法

四、在Struts2中自定义拦截器
通过(登录检查拦截器,访问某一个页面时必须要先登录,登录之后才能访问)例子来实现自定义拦截器

  • login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    注册界面


    
用户名:
密码 :
  • welcome.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    登录成功


        欢迎${sessionScope.user.userName}


  • User
package com.revanwang.interceptor;

import lombok.Data;

@Data
public class User {
    private String userName;
    private String passWord;
}
  • Action类
package com.revanwang.interceptor;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import lombok.Getter;
import lombok.Setter;

public class LoginAction extends ActionSupport {

    @Setter
    @Getter
    private User user;  //获取请求参数

    @Override
    public String execute() throws Exception {
        System.out.println("Login....." + this.user);
        //保存user数据到 session 中
        ActionContext.getContext().getSession().put("user", this.user);
        return SUCCESS;
    }
}
  • struts.xml






    
        
            /login/welcome.jsp
        
    


  • 上面的缺点就是无论是否登陆成功都可以访问到welcome.jsp,这显然不符合需求。为了只能在登录成功后才能访问welcome.jsp.

    • 1、直接判断Action中的请求参数,但是这种方法存在硬编码
    • 2、自定义拦截器(checkLoginInterceptor)
  • CheckLoginInterceptor

package com.revanwang.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

import java.util.Map;

public class CheckLoginInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {

        Map sessionMap = invocation.getInvocationContext().getSession();
        User user = (User) sessionMap.get("user");
        System.out.println("CheckLoginInterceptor. . . ." +  sessionMap + "\n" + user);
        if (user == null || user.getUserName().equals("".trim())) {
        System.out.println("CheckLoginInterceptor. . . .empy");
            return "login";
        }
        return invocation.invoke();
    }
}
  • struts.xml






    
        
        
            
            

            
            
                
                
            

        


        
        

        
        
            
                /login/login.jsp
            
        

        
        
        
            
            
            checkAction
        

        
        
            /login/welcome.jsp
        

    


3、拦截器设置参数

  • CheckLoginInterceptor
package com.revanwang.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

import java.util.Arrays;
import java.util.Map;

public class CheckLoginInterceptor extends AbstractInterceptor {

    //需要放行的action名称
    private String[] unCheckedActionNames = {};

    //通过拦截器设置对应参数
    public void setActionNames(String actionNames) {
        if (actionNames != null) {
            this.unCheckedActionNames = actionNames.split(",");
        }
    }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {

        //拦截器放行
        String actionName = invocation.getProxy().getActionName();
        System.out.println("unCheckedActionNames:===" + actionName);
        if (Arrays.asList(this.unCheckedActionNames).contains(actionName)) {
            System.out.println("unCheckedActionNames:===" + actionName);
            return invocation.invoke();
        }

        Map sessionMap = invocation.getInvocationContext().getSession();
        User user = (User) sessionMap.get("user");
        if (user == null || user.getUserName().equals("".trim())) {
            System.out.println("CheckLoginInterceptor. . . .empy");
            return "login";
        }
        return invocation.invoke();
    }
}
  • struts.xml






    
        
        
            
            
                
                lt,dl
            

            
            
                
                
            

        

        
        

        
        
            
                /login/login.jsp
            
        

        
        
        
            
            
            checkAction
        

        

            
            /WEB-INF/JSP/list.jsp
        

        
            /login/welcome.jsp
        

        
            
                /login/welcome.jsp
            
        

        
        
            /login/welcome.jsp
        

    


你可能感兴趣的:(Web开发最佳实践-Struts2之三拦截器(Interceptor))