SSH框架之旅-struts2(4)

SSH框架之旅-struts2(4)_第1张图片
struts.jpg

1.Struts2 拦截器


1.1 AOP 思想

AOP 是 Aspect Objected Prograing(面向切面编程)的缩写。struts2 中的拦截器就是这种编程策略的一种实现,AOP 思想是在基本功能上,不通过修改源代码就可以扩展功能,提高代码的重用性。

1.2 拦截器概述

struts2 框架的许多功能都是基于拦截器的,struts2 中有很多拦截器,默认的拦截器每次都执行。说到拦截器,还有一个种重要的概念——拦截器链(在 struts2 中称为是拦截器栈)。拦截器链就是将一堆拦截器按照一定顺序联结成一条链,在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其定义的顺序调用。

1.3 struts2 拦截器原理

struts2 的拦截是通过 xml文件的配置实现的,默认的拦截器在 struts2-core-*.jar 包中的 struts-default.xml 文件,可以查看源代码。当收到一个请求时,struts2 会先查找xml配置文件,并根据配置来实例化拦截器对象,然后串成一条链,请求要通过每一个拦截器,才能执行 Action 中的方法,最终才能得到想要的结果。这么多拦截器,使用一个代理对象对它们进行动态调用。当 action 的请求到来时,创建 Action 的代理对象,这个代理对象在 Action 方法执行之前执行默认的拦截器和其他拦截器(用户自定义的拦截器),最后才是 Action 对应方法的调用,这里面是数据结构栈的思想。代理对象调用栈的最底层才是 Action 方法的调用,然后在返回给上一个拦截器,层层退出。

struts2 拦截器结构的设计是一个典型的责任链模式的应用,首先将整个执行的过程划分为若干相同类型的元素,每个元素具备不同的逻辑责任,并将这些元素放到一个栈式的数据结构中,每个元素又有责任负责下一个元素的执行调用。将一个复杂的系统,分而治之,从而将每个部分的逻辑能够高度重用并具备高度扩展性,拦截器在 struts2 中的设计实乃精彩。

SSH框架之旅-struts2(4)_第2张图片
实现原理

查看源代码

找到 web.xml 文件中配置拦截器类的位置 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter,找到这个类中的 execute.executeAction(request, response, mapping) 方法,进入这个方法查看,dispatcher.serviceAction(request, response, mapping),在进入这个方法找到 ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false) ,这个方法就会创建 action 的代理对象,不是直接 new 出来的,继续往下找到 proxy.execute() 方法,进入方法查看,会发现这是一个接口,所以找到这个方法的实现类 StrutsActionProxy,在这个类中找到 execute() 方法,该方法的返回值是 invocation.invoke(),表示执行 Action 中的方法,进入方法查看也是一个接口,找到这个方法的实现类 DefaultActionInvocation,在这个类的 invoke() 方法中有一个遍历拦截器的操作 if (interceptors.hasNext()),一个拦截器执行完后执行下一个拦截器,最后返回invocation.invoke(),执行 Action 中的方法。

1.4 拦截器和过滤器的区别

  • 过滤器理论上可以过滤任意内容,比如 jsp页面,html页面,servlet,图片路径等等
  • 拦截器只能拦截 Action,每次访问时就会创建一个 Action,多个 Action 的对象。

1.4 自定义拦截器

在 struts2 中有很多默认的拦截器,打开 struts2-core-*.jar 包中的 struts-default.xml 文件,在 标签中的拦截器就是 struts2 的默认拦截器。在实际的开发中,如果想使用是 struts2 中没有的拦截器功能,这时就要自己写自定义的拦截器。

查看源代码查看拦截器类的结构

在 struts-default.xml 文件中,有很多拦截器,在 标签中有拦截器的包名,可以找一个进入查看,这些默认的拦截器类都继承自抽象的拦截器类 AbstractInterceptor,抽象拦截器类中有 init(),destroy(),intercept() 三个方法。init() 方法执行拦截器的初始化操作,destroy() 方法执行拦截器的销毁操作,intercept() 方法执行拦截器具体的逻辑操作。但在开发中建议继承 MethodFilterInterceptor 类来实现自定义的拦截器,这样可以对 Action 中的某些方法不进行拦截。

拦截器和 Action 建立关系不是直接在 Action 中调用拦截器的方法,而是通过配置文件的方式让两者建立关系的。

拦截器实现的步骤:

    1. 创建拦截器类,继承 MethodFilterInterceptor 类
    1. 重写 MethodFilterInterceptor 类中的 doIntercept() 方法,在这个方法写拦截器的逻辑

拦截器配置的步骤:

    1. 在要拦截的 action 标签所在的 package 标签中声明拦截器
    1. 在具体的 action 标签中使用声明的自定义拦截器
    1. 手动配置 struts2 的默认拦截器

下面就通过一个用户登陆的案例来说明自定义拦截器的使用。

在 Web 应用中,用户需要在登录之后才能使用主页面的功能,如果用户没有登录,则在使用主页面的功能之前先让其登录,用户登录成功,在 session 中保存用户名。

示例代码如下:

拦截器类

package cc.wenshixin.interceptor;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

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

public class LoginInteceptor extends MethodFilterInterceptor{

    @Override
    //在这个方法中写拦截器的逻辑
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        //判断 session 中是否有用户名,也即是判断用户是否登录
        HttpServletRequest request = ServletActionContext.getRequest();
        Object obj = request.getSession().getAttribute("username");
        if(obj != null)
        {
            //已经登录,则执行 Action 中的方法
            return invocation.invoke();
        }else
        {
            //未登录,则返回值使其跳转到登录页面
            return "login";
        }
    }
    
}

Action 类

package cc.wenshixin.action;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class ActionDemo extends ActionSupport{
    public String login()
    {
        //获取表单数据
        HttpServletRequest request = ServletActionContext.getRequest();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //这里为了简单就直接写死判断了,实际开发中要在数据库查询
        if("admin".equals(username) && "123".equals(password))
        {
            //登录成功,设置session值,并挑转到主页面
            request.getSession().setAttribute("username", username);
            return "success";
        }else
        {
            //用户名密码错误,则跳转回登录页面
            return "login";
        }
    }
    
    public String add()
    {
        //跳转到添加页面
        return "add";
    }
    
    public String delete()
    {
        //跳转到删除页面
        return "delete";
    }
}

struts2 配置文件

注意:如果在配置文件中配置自定义的拦截器,默认的 struts2 拦截器就不会执行了,所以要把默认的拦截器手动使用一下。



  

  
    
    
      
    
    
      
      
        
        login
      
      
      
      
      /index.jsp
      /login.jsp
      /add.jsp
      /delete.jsp
    
  

jsp 页面

    1. 登录页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here


  

登录页面

用户名:
密码:
    1. 主页页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here


  

欢迎 ${sessionScope.username} 主页面

跳转到添加页面 跳转到删除页面
    1. 添加页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here


  

这是添加页面

    1. 删除页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here


  

这是删除页面

2.struts2 标签库


2.1 普通标签

  • :和 OGNL 表达式一起使用在 jsp 页面中获取值栈中的数据
  • :获取值栈 list 集合的数据,遍历 list 集合中的值
  • :查看值栈结构和数据

2.2 表单标签

2.2.1 HTML 表单相关标签回顾

form 表单

输入项

普通输入项:
密码输入项:
单选输入项:
复选输入项:
文件上传项:
隐藏输入项:
普通按钮:
提交按钮:
图片按钮:
重置按钮:
下拉输入项:
文本域:

2.2.2 struts2 中对应的表单标签(知道即可)

注意要在 jsp 中引入 struts2 的标签库。

  
    
    
    
    
    
      
    
      
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  

页面效果如下图所示

SSH框架之旅-struts2(4)_第3张图片
效果图

页面源码如下图所示

查看网页源代码,可以发现,struts2 的 form 标签里面是通过 table 来布局的,这并不符合现在的网页布局方式(Div 布局),也不利于页面的美化,所以 struts2 的 form 标签基本不用。

SSH框架之旅-struts2(4)_第4张图片
页面源码

你可能感兴趣的:(SSH框架之旅-struts2(4))