前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[ SSH框架 ] Struts2框架学习之四(自定义拦截器)

[ SSH框架 ] Struts2框架学习之四(自定义拦截器)

作者头像
Kevin_Zhang
发布2018-05-22 17:06:59
1.1K0
发布2018-05-22 17:06:59
举报
文章被收录于专栏:Kevin-ZhangCGKevin-ZhangCG

一、Struts2的拦截器

1.1 拦截器概述

   拦截器,在AOP( Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。

  在 Webwork的中文文档的解释为—拦截器是动态拦截 Action调用的对象。它提供了一种机制可以使开发者可以定义在一个 action执行的前后执行的代码,也可以在一个 action执行前阻止其执行。同时也是提供了一种可以提取 action中可重用的部分的方式。

  谈到拦截器,还有一个词大家应该知道—拦截器链( Interceptor Chain,在 Struts2中称为拦截器栈 Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

1.2 拦截器实现原理

  大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达 Struts2的ServletDispatcher时, Struts2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

  Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时, Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

1.3 Struts2的执行流程

1.4 自定义拦截器

在程序开发中,如果需要开发自己的拦截器类,就需要直接或间接的实现 com.opensymphony.xwork2.interceptor.MethodFilterInterceptor接口,自定义代码如下:

代码语言:javascript
复制
public interface Interceptor extends Serializable{

        void init();
    void destory();
    String intercept(ActionInvocation invocation) throws Exception;

}    

该接口提供了三个方法,其具体介绍如下。

●  void init( ):该方法在拦截器被创建后会立即被调用,它在拦截器的生命周期内只被调用次.可以在该方法中对相关资源进行必要的初始化。

●  void destroy( ):该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内,也只被调用一次。

●  String intercept( ActionInvocation invocation) throws Exception;该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求,该方法就会被调用一次。该方法的 ActionInvocation参数包含了被拦截的 Action的引用,可以通过该参数的 invoke方法,将控制权转给下一个拦截器或者转给 Action的 execute( )方法。

  如果需要自定义拦截器,只需要实现 interceptor接口的三个方法即可。然而在实际开发过程中除了实现 Interceptor接口可以自定义拦截器外,更常用的一种方式是继承抽象拦截器类AbstractIntercepter该类实现了 Interceptor接口,并且提供了ini( )方法和 destroy( )方法的空实现。使用时,可以直接继承该抽象类,而不用实现那些不必要的方法。拦截器类 AbstractInterceptor中定义的方法如下所示:

代码语言:javascript
复制
public abstract class Abstractinterceptor implements Interceptor{

    public void init();

    public void destroy();

    public abstract String intercept(ActionInvocation invocation);

    throws Exception;
}

  从上述代码中可以看出, AbstractInterceptor类已经实现了 Interceptor接口的所有方法,一般情况下,只需继承 AbstractInterceptor类,实现 interceptor方法就可以创建自定义拦截器。

  只有当自定义的拦截器需要打开系统资源时,才需要覆盖 AbstractInterceptor类的 init( )方法和destroy( )方法。与实现 Interceptor接口相比,继承 AbstractInterceptor类的方法更为简单。

1.5 拦截器的配置

●  拦截器

要想让拦截器起作用,首先要对它进行配置。拦截器的配置是在 struts. xml文件中完成的,它通常以< Interceptor>标签开头,以</ interceptor>标签结束。定义拦截器的语法格式如下:

代码语言:javascript
复制
<interceptor name=interceptorName" class="interceptorclass"">

    <param name="paramname">paramvalue</param>

</interceptor>

上述语法格式中,name属性用来指定拦截器的名称, class属性用于指定拦截器的实现类。有时在定义拦截器时需要传入参数,这时需要使用< param>标签,其中name属性用来指定参数的名称,paramvalue表示参数的值。

●  拦截器栈

在实际开发中,经常需要在 Action执行前同时执行多个拦截动作,如:用户登录检查、登录日志记录以及权限检查等,这时,可以把多个拦截器组成一个拦截器栈。在使用时,可以将栈内的多个拦截器当成一个整体来引用。当拦截器栈被附加到一个 Action上时,在执行 Action之前必须先执行拦截器栈中的每一个拦截器定义拦截器栈使用< . interceptors>元素和< Interceptor- stack>子元素,当配置多个拦截器时,需要使用< kinterceptor-ref>元素来指定多个拦截器,配置语法如下:

代码语言:javascript
复制
<interceptors>

    <interceptor-stack name="interceptorstackname">

        <interceptor-ref name="interceptorname"/>

    </interceptor-stack>

</interceptors>

在上述语法中, interceptorstackname值表示配置的拦截器栈的名称;interceptorName值表示拦截器的名称。除此之外,在一个拦截器栈中还可以包含另一个拦截器栈。

1.6 编写自定义拦截器

下面用一个添加登录拦截器功能的实例展示自定义拦截器的使用。

●  第一步:创建类,继承MethodFilterInterceptor类并重写MethodFilterInterceptor类里的方法写拦截器逻辑

代码语言:javascript
复制
package com.Kevin.interceptor;
/**
 * 给登录判断写一个自定义拦截器
 */

import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

public class LoginInterceptor extends MethodFilterInterceptor{

    //编写拦截器逻辑
    protected String doIntercept(ActionInvocation invocation) throws Exception {                
        //判断session里是否有username的值
        //得到session
        HttpServletRequest request=ServletActionContext.getRequest();
        Object obj=request.getSession().getAttribute("username");
        //判断
        //登录状态
        //做放行操作,执行action方法
        if(obj!=null)            
            return invocation.invoke();    
        //不是登录状态
        //不到登录,不执行action方法,返回登录页面
        //到result标签里找到login的值,到配置路径里
        else            
            return "login";    
    }

}

●  第二步:配置action和拦截器关系(注册拦截器)

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
    
<struts>
    <constant name="struts.i18n.encoding" value="UTF-8"></constant>
    
    <package name="strutsdemo" extends="struts-default" namespace="/">
    
        <!-- 1.声明拦截器 -->
        <interceptors>
            <interceptor name="loginintercept" class="com.Kevin.interceptor.LoginInterceptor"></interceptor>
        </interceptors>
    
        <action name="customer_*" class="com.Kevin.action.LoginAction" method="{1}">
            <!-- 2.使用自定义拦截器 -->
            <interceptor-ref name="loginintercept">
                <!-- 配置action中某些方法不进行拦截
                    name属性值:excludeMethods
                    值:action不拦截的方法名称
                 -->
                 <param name="excludeMethods">login</param>
            </interceptor-ref>
            
            <interceptor-ref name="defaultStack"></interceptor-ref>
            
            <!-- 登录失败 -->
            <result name="login">/login.jsp</result>
            <!-- 登录成功 -->
            <result name="loginsuccess">/welcome.jsp</result>
            <result name="menu">/menu.jsp</result>
            
        </action>
        
        <action name="welcome" class="com.Kevin.action.TestAction">
            <result name="success">/welcome.jsp</result>
        </action>    
        
    </package>
    
</struts>

Tips:struts2里有很多默认的拦截器,但是如果在action里配置了自定义拦截器,默认拦截器就不会在执行。       解决办法:将默认拦截器手动使用,如代码<interceptor-ref name="defaultStack"></interceptor-ref>

判断登录action编写:

代码语言:javascript
复制
package com.Kevin.action;
/**
 * 登录判断Action
 */
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport{
    
    //登录的方法
    public String login(){
        //1.得到request对象
        HttpServletRequest request=ServletActionContext.getRequest();
        String username=request.getParameter("username");
        String password=request.getParameter("password");
        //2.判断用户名和密码
        if("admin".equals(username) && "admin".equals(password)){
            //登陆成功
            request.getSession().setAttribute("username", username);
            return "loginsuccess";
        }
        
        else
            //登录失败
            return "login";
    }
    
    //测试拦截器进入menu页面时,是否进行登录拦截
    public String menu(){
        return "menu";
    }  
    @Override
    public String execute() throws Exception {
        
        return null;
    }

}

Tips:拦截器和过滤器的区别:(重要概念)     1.过滤器:理论上可以过滤任意内容,比如html、jsp、servlet、图片路径;     2.拦截器:拦截器可以拦截action。

Tips:Servlet和Action的区别:     1.servlet默认第一次访问时候创建,创建一次,单实例对象;     2.action每次访问时侯创建,创建多次,多实例对象。

二、Struts2的标签库

2.1 Struts2标签库概述

 对于一个MVC框架而言,重点是实现两部分:业务逻辑控制器部分和视图页面部分。 Struts2作为一个优秀的MVC框架,也把重点放在了这两部分上。控制器主要由 Action来提供支持,而视图则是由大量的标签来提供支持。接下来将针对 Struts2标签库的构成和常用标签的使用进行详细的讲解。

2.2 Struts2标签库分类

  早期的JSP页面需要嵌入大量的Java脚本来进行输出,这样使得一个简单的JSP页面加入了大量的代码,不利于代码的可维护性和可读性。随着技术的发展,逐渐的采用标签库来进行JSP页面的开发,这使得JSP页面能够在很短的时间内开发完成,而且代码通俗易懂,大大的方便了开发者Struts2的标签库就是这样发展起来的。

  Struts2框架对整个标签库进行了分类,按其功能大致可分为两类,如图所示。

由图中可以看出, Struts2标签库主要分为两类:普通标签UI标签。普通标签主要是在页面生成时,控制执行的流程。UI标签则是以丰富而可复用的HTML文件来显示数据。

  普通标签又分为控制标签( Control Tags)和数据标签( Data Tags)。控制标签用来完成条件逻辑、循环逻辑的控制,也可用来做集合的操作。数据标签用来输出后台的数据和完成其他数据访问功能。

  UI标签又分为表单标签( Form Tags)、非表单标签( non-form Tags)和Ajax标签。表单标签主要用来生成HTML页面中的表单元素,非表单标签主要用来生成HTML的<div>标签及输出 Action中封装的信息等。Ajax标签主要用来提供Ajax技术支持。

2.3 Struts2标签的使用

  Struts2标签库被定义在 struts-tags tld文件中,我们可以在 struts-core-2.3.24jar中的META-INF目录下找到它。要使用 struts2的标签库,一般只需在JsP文件使用 taglib指令导入 Struts2标签库,具体代码如下:

代码语言:javascript
复制
<%@taglib prefix="s" uri="/struts-tags" %>

在上述代码中, taglib指令的uri属性用于指定引入标签库描述符文件的URI, prefix属性用于指定引入标签库描述符文件的前缀。需要注意的是,在JSP文件中,所有的 Struts2标签库的使用“s”前缀。

2.4 Struts2的控制标签

●  <s:if>、<s: elseif>、<s:else>标签

与多数编程语言中的if、 elseif和else语句的功能类似,<s:if>、<s: elseif>、<s:else>这三个标签用于程序的分支逻辑控制。其中,只有<s:if>标签可以单独使用,而< s elseif>、<s:else>都必须与<sf>标签结合使用,其语法格式如下所示:

代码语言:javascript
复制
<s: if test="表达式1">

    标签体

</s: if>

<s:elseif test="表达式2">

    标签体

</s: elseif>

<s:e1se>

    标签体

</s :else>

上述语法格式中,<s:if>、和<s: elseif>标签必须指定test属性,该属性用于设置标签的判断条件,其值为 boolean型的条件表达式。

●  < s:iterator>标签

< s:iterator>标签主要用于对集合中的数据进行迭代,它可以根据条件遍历集合中的数据。<s:iterator>标签的属性及相关说明如表所示:

在表中,如果在< s:Iterator>标签中指定 status属性,那么通过该属性可以获取迭代过程中的状态信息,如:元素数、当前索引值等。通过 status属性获取信息的方法如表所示(假设其属性值为st):

2.5 Struts2的数据标签

●  < s:property>标签

<s:property>标签用于输出指定的值,通常输出的是 value属性指定的值,< s:property>标签的属性及属性说明如下所示:

●  id:可选属性,指定该元素的标识。

●  default:可选属性,如果要输出的属性值为nul,则显示 default属性的指定值

●  escape:可选属性,指定是否忽略HTM代码。

●  value:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出 Valuestack栈顶的值。

●  <s:a>标签

<s:a>标签用于构造HTML页面中的超链接,其使用方式与 HTML中的<a>标签类似。<s:a>标签的属性及相关说明如表所示:

●  <s:debug>标签

<s:debug>标签用于在调试程序时输出更多的调试信息,主要输出 ValueStack和 StackContext中的信息,该标签只有一个id属性,且一般不使用在使用 debug标签后,网页中会生成一个[ Debug]的链接,单击该链接,网页中将输出各种服务器对象的信息,如图所示:

2.6 Struts2的表单标签

  Struts2的表单标签用来向服务器提交用户输入的信息,绝大多数的表单标签都有其对应的HTML标签,通过表单标签可以简化表单开发,还可以实现HTM江中难以实现的功能。大家可以结合HTML的标签对比学习 Struts2的表单标签。

● 表单标签的公共属性

Struts2的表单标签用来向服务器提交用户输入信息,在 org. apache struts2 components包中都有个对应的类,所有表单标签对应的类都继承自 Uibean类。 Uibean类提供了一组公共属性,这些属性是完全通用的。如表所示:

  除了这些常用的通用属性外,还有很多其它属性。由于篇幅有限,这里就不一一列举。需要注意的是,表单标签的name和 value属性基本等同于HTML组件的name和 value,但是也有些不同的地方:表单标签在生成HTML的时候,如果标签没有设置 value属性的话,就会从值栈中按照name获取相应的值,把这个值设置成的HTML组件的 value。简单的说,就是表单标签的 value在生成HTML的时候会自动设置值,其值从值栈中获取。

●  <s:form>标签

<s:form>标签用来呈现HTML语言中的表单元素,其常用属性如表所示:

在使用< s: form>标签时,一般会包含其它的表单元素,如 textfield, radio等标签,通过这些表单元素对应的name属性,在提交表单时,将其作为参数传入 Struts2框架进行处理。

●  <s:submit>标签

  < s: submit>标签主要用于产生HTML中的提交按钮,该表单元素中,可以指定提交时的 Action对应的方法。通常与< s: forn>标签一起使用,该标签的常用属性如表所示:

●  <s:textfield>和<s:textarea>标签

<s: textfield>和<s: textarea>标签的作用比较相似,都用于创建文本框,区别在于<s:textfield>创建的是单行文本框,而< s:textarea>创建的是多行文本框。二者使用也比较简单,一般指定其 label和name属性即可。两个标签的用法如下所示

<s:textfield>标签的用法:

代码语言:javascript
复制
<s:textfield label="用户名" name="username"/>

< s:textarea>标签的用法:

代码语言:javascript
复制
<s:textarea label="Message"  name="message"/>

  name属性用来指定单行/多行文本框的名称,在 Action中,通过该属性获取单行/多行文本框的值。其 value属性用来指定单行/多行文本框的当前值。此外,< textarea>标签可以通过使用cols和rows属性分别指定多行文本框的列数和行数。

●  <s:password>标签

<s:password>标签用于创建一个密码输入框,它可以生成HTML中的<input type="password"/>标签,常用于在登录表单中输入用户的登录密码。<s:password>标签的常用属性说明如表所示:

  需要注意的是 Struts2的 password标签与HTML的< input type="password"/>标签有小小的不同,< input type= "password">标签只要设置 value属性就可以将 value属性的值作为默认显示值;而 Struts2的< s:password>标签除了要设置 value属性,还要设置 showPassword属性为true。

●  <s:radio>标签

  < s:radio>标签用于创建单选按钮,生成HTML中的< cinput type= radio”个>标签。< s:radio>标签的常用属性说明如表所示:

●  <s:checkboxlist>标签

   <s:checkboxlist>标签用于一次性创建多个复选框,用户可以选创建零到多个,它用来产生一组<input type="checkbox"/>标签,常用属性说明如表示:

●  <s:select>标签

   <s:select>标签用于创建一个下拉列表,生成HTML中的<select>标签,常用属性说明如表所示:

  在表中, headerkey和header value属性需要同时使用,可以在所有的真实选项之前加一项作为标题项。比如选择省份的时候,可以在所有的具体省份之前加一项“请选择”,这个项不作为备选的值。

  multiple属性和size属性类似于HTML的< select>标签,size属性可以让下拉框同时显示多个值multiple属性让用户同时选择多个值,只是在后台的 Action接收下拉框值的时候,不能使用 String类型,而应该使用 String[ ]或者List<String>。

●  <s:hidden>标签

  < s:hidden>标签用于创建隐藏表单元素,生成HTML中的隐藏域标签< input type=" hidden”>。该标签在页面上没有任何显示,可以保存或交换数据。其使用也比较简单,通常只设置其name和 value属性即可。其一般用法如下所示:

代码语言:javascript
复制
<s: hidden name="id" value="%{id}"/>

该标签主要用来需要提交的表单传值时使用,比如需要提交表单时,要传一个值到请求参数中去,就可以使用该标签。

●  <s:reset>标签

  < s:reset>标签用来创建一个重置按钮,会生成HTML中的< input type= "reset"}>标签,该标签的使用比较简单,其常用属性为name和 value。其中name属性用于指定重置按钮的名称,在 Action中,可以通过name属性来获取重置按钮的值,value属性用于显示按钮的值。该标签的用法如下所示:

代码语言:javascript
复制
<s:reset value="Reset"/>

 下面通过一个综合JSP页面示例来展示form表单标签的用法:

代码语言:javascript
复制
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<html>
  <head>
    <title>My JSP 'form.jsp' starting page</title>
  </head>
  <body>
    <!-- form标签 -->
    <s:form>
        <!-- 1.普通输入项 -->
        <s:textfield name="username" label="Username"></s:textfield>
        
           <!-- 2.密码输入项 -->
        <s:password name="password" label="Password"></s:password>
        
           <!-- 3.单选输入项 -->    
        <!-- value属性值与显示值一样 -->
        <s:radio list="{'Male','Female'}" name="gender" label="Gender"></s:radio>
        <!-- value属性值与显示值不一样 -->
        <s:radio list="#{'M':'男','F':'女'}" name="gender2" label="Gender"></s:radio>
        
        <!-- 4.复选输入项 -->
        <!-- value属性值与显示值一样 -->
        <s:checkboxlist list="{'Basketball','Football','Baseball','PingPang'}" name="hobby" label="Hobby"></s:checkboxlist>
        <!-- value属性值与显示值不一样 -->
        <s:checkboxlist list="#{'Basketball':'BSKTball','Football':'FTball','Baseball':'BSball','PingPang':'PP' }" name="hobby2" label="Hobby"></s:checkboxlist>
        
        <!-- 5.下拉输入框 -->
        <s:select list="{'C','C++','Java','Python'}" name="language" label="Programming"></s:select>
        
        <!-- 6.隐藏项 -->
        <s:hidden name="hid" label="hidden"></s:hidden>
        
        <!-- 文件上传 -->
        <s:file name="file" value="Upload"></s:file>
        
        <!-- 7.文本域 -->
        <s:textarea rows="30" cols="60" name="message" label="Message"></s:textarea>
        
        <!-- 8.提交按钮-->
        <s:submit value="Submit"></s:submit>
        
        <!-- 9.重置按钮 -->
        <s:reset value="Reset"></s:reset>
    </s:form>

  </body>
</html>

显示如下:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-05-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档