JavaWeb框架_Struts2_(三)---->Struts2的攔截器


2. Struts2的攔截器(使用攔截器實現權限控制)

 

2.1 攔截器的概述

 

  攔截器是Struts2的核心組成部分,它可以動態的攔截Action調用的對象,類似與Servlet中的過濾器。Struts2的攔截器是AOP(Aspect-Object-Programming,面向切面編程)的一種實現策略,是可插拔的,需要某一個功能時就“插入”這個功能的攔截器,不需要這個功能就“拔出”攔截器。開發者只需要提供攔截器的實現類,並將其配置在Struts.xml中即可。

 

2.1.2 攔截器的工作原理

 

  通常情況下,攔截器都是一代理的方式調用的,它在一個Action執行前后進行攔截,圍繞着Action和Result的執行而執行,其工作方式如下圖所示,

  Struts2攔截器實現原理與Servlet過濾器實現原理類似,它以鏈式執行,對真正要執行的方法(execute())進行攔截。首先執行Action配置的攔截器,在Action和Result執行之后,攔截器會再次執行(與先前調用的順序相反),在此鏈式執行的過程中,每一個攔截器都可以直接返回,從而終止余下的攔截器、Action及Result的執行。

  

2.1.3 攔截器的配置

 

(1) 攔截器

  攔截器的配置在struts.xml文件中完成的,它通常以<interceptor>標簽開頭,以</interceptor>標簽結束。定義攔截器的語法格式如下:

 <interceptor name="interceptorName" class="interceptorClass">
            <param name="paramName">paramValue</param>
 </interceptor>

  上述語法格式中,name屬性用來指定攔截器的名稱,class屬性用於指定攔截器的實現類。在定義時,使用<param>標簽傳入參數。

(2) 攔截器棧

  在實際開發中,在Action執行前同時執行多個攔截動作,如用戶登陸檢查等,這時可以把多個攔截器組成攔截器棧。在使用時,可以將棧內的多個攔截器當成一個整體來引用。當攔截器棧被附加到一個Action上時,在執行Action之前必須先執行攔截器棧中的每一個攔截器。

  定義攔截器棧使用<interceptors>和<interceptor-stack>子元素,當配置多個攔截器時,需要使用<interceptor-ref>元素來指定多個攔截器,配置語法如下:

   <interceptors>
          <interceptor-stack name="interceptorStackName">
              <interceptor-ref name="interceptorName"/>
              ...
          </interceptor-stack>
   </interceptors>

  上述語法中,interceptorStackName值表示配置的攔截器棧的名稱,interceptorName值表示攔截器的名稱。除此之外,在一個攔截器棧中還可以包含另一個攔截器棧,實例如下:

    <package name="default"namespace="/"extends="struts-default">
        <!--攔截器的聲明-->
        <interceptors>
            <interceptor name="interceptor1" class="interceptorClass"/>
            <interceptor name="interceptor2" class="interceptorClass"/>
            <!--定義一個攔截器棧mystack,該攔截器棧中包括兩個攔截器和一個攔截器棧-->
            <interceptor-stack name="mystack">
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="interceptor1"/>
            <interceptor-ref name="interceptor2"/>
            </interceptor-stack>
        </interceptors>
    </package>

  上述代碼中定義的攔截器棧是myStack,在myStack棧中,除了引用了兩個自定義的攔截器interceptor1和interceptor2外,還引用了一個內置攔截器棧defaultStack,這個攔截器是必須要引入的。

(3) 默認攔截器棧

   默認攔截器可以對其指定包中的所有Action起到攔截的作用。一旦為某個包指定了默認攔截器,並且該包中的Action未顯式地指定攔截器,則會使用默認攔截器。默認攔截器需要使用<default-interceptor-ref>元素,此元素為<package>元素的子元素。其語法格式如下:

 <default-interceptor-ref name="攔截器(棧)的名稱"/>

  上述語法格式中,name屬性的值必須是已經存在的攔截器或攔截器棧的名稱。下面用該語法格式配置一個默認攔截器,示例代碼如下:

<package name="default" namespace="/" extends="struts-default">

        <!--攔截器的聲明-->
        <interceptors>
        <default-interceptor-ref name="攔截器棧的名稱"/>
        <interceptors>
            <interceptor name="interceptor1" class="interceptorClass"/>
            <interceptor name="interceptor2" class="interceptorClass"/>
            <!--定義一個攔截器棧mystack,該攔截器棧中包括兩個攔截器和一個攔截器棧-->
            <interceptor-stack name="mystack">
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="interceptor1"/>
            <interceptor-ref name="interceptor2"/>
            </interceptor-stack>
        </interceptors>
        <!-- 配置該包下的默認攔截器,既可以是攔截器,也可以是攔截器棧 -->
        <default-interceptor-ref name="mystack"/>
        <action name="login"class="cn.itcast.action.LoginAction">
            <result name="input">/login.jsp</result>
        </action>

    </package>

  上述代碼中,指定了包下的默認攔截器是一個攔截器棧,該攔截器棧將會作用於包下所有的Action。

  Notice:一個包下只能定義一個默認攔截器,如果需要多個攔截器作為默認攔截器,則可以將這些攔截器定義為一個攔截器棧,再將這個攔截器棧作為默認攔截器即可。

 

2.2 Struts2的內建攔截器

 

2.2.1 內建攔截器的介紹

  只要自定義的包繼承了Struts2的struts-default包,就可以使用默認包中的攔截器,否則需要自己定義攔截器。在Struts-default.xml中每一個攔截器都具有不同的意義(具體攔截器說明--->省略)。

2.2.2 內建攔截器的配置

  前面2.1已經介紹過相關配置,此處不再贅述。

 

2.3 Struts2自定義攔截器

   

  struts2的內置攔截器可以實現大部分的攔截任務,但是一些與系統邏輯相關的通用功能(如權限的控制、用戶登陸控制等),則需要通過自定義攔截器來實現。本節詳講如何自定義攔截器。

 

2.3.1 實現自定義攔截器

 

  在程序開發過程中,如果需要開發自己的攔截器類,就需要直接或間接地實現com.opensymphony.xwork2. interceptor. Interceptor接口,具體代碼如下:

import com.opensymphony.xwork2.DefaultActionInvocation;
import java.io.Serializable;
public interface Interceptor extends Serializable { void init(); void destroy(); String interceptor (DefaultActionInvocation)throws Exception; }

  該接口提供一下三個方法:

  • void init():該方法在攔截器被創建后會立即被調用,它在攔截器的生命周期只有內只被調用一次。可以在該方法中對相關的資源進行必要的初始化;
  • void destroy():該方法與init()方法相對應,在攔截器實例被銷毀之前,將調用該方法來釋放與攔截器相關的資源。它在攔截器的生命周期內也只被調用一次。
  • Spring intercept(ActionInvocation invocation)throws Exception:該方法是攔截器的核心方法,用來真正執行攔截工作的代碼,實現具體的攔截工作。

 

2.3.2 應用案例-----使用攔截器實現權限控制

 

  通過之前對攔截器學習,可以將自定義攔截器的使用分為一下三個步驟:

  1. 用戶自定義攔截器類,必須實現Interceptor接口或者繼承AbstractInterceptor類;
  2. 需要在struts.xml中,定義自定義攔截器;
  3. 在struts.xml中的Action中使用攔截器。

 

具體步驟如下:

 

(1)在intellij idea中創建Struts2的項目(可參考之前的博客 http://www.cnblogs.com/Mairr/p/7846747.html)

(2)web.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--首頁(這一塊兒是自己加進來的)-->
    <welcome-file-list>
        <welcome-file>main.jsp</welcome-file>
    </welcome-file-list>
</web-app>

(3)在src目錄下創建java包,如下

(4)User.java

package cn.Mairr.domin;

public class User {
    private String username;
    private String password;
    public String getUsername(){
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

(5)LoginAction.java

package cn.Mairr.action;

import cn.Mairr.domin.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class LoginAction extends ActionSupport implements ModelDriven <User> {
    private static final long serialVersionUID = 1L;
    private User user = new User();

    public User getModel() {
        return user;
    }

    @Override
    public String execute() throws Exception {
        //獲取ActionContext
        ActionContext actionContext = ActionContext.getContext();

        if ("Mairr".equals(user.getUsername()) && "123".equals(user.getPassword())) {
            actionContext.getSession().put("user", user);
            return SUCCESS;
        } else {
            actionContext.put("msg", "用戶名或者密碼不正確");
            return INPUT;
        }
    }
}

(6) BookAction.java

package cn.Mairr.action;

import com.opensymphony.xwork2.ActionSupport;

public class BookAction extends ActionSupport {
    public String add(){
        System.out.println("book add");
        return SUCCESS;
    }
    public String del(){
        System.out.println("book del");
        return SUCCESS;
    }
    public String update(){
        System.out.println("book update");
        return SUCCESS;
    }
    public String find(){
        System.out.println("book find");
        return SUCCESS;
    }
}

(7)PrivilegeInterceptor.java

package cn.Mairr.interceptor;

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

public class PrivilegeInterceptor extends AbstractInterceptor{
    private static final long serialVersionUID = 1L;
    public String intercept(ActionInvocation invocation)throws Exception{
        //得到ActionContext
        ActionContext actionContext = invocation.getInvocationContext();
        //獲取user對象
        Object user = actionContext.getSession().get("user");
        if(user != null){
            return invocation.invoke();
        }else {
            actionContext.put("msg","您還未登錄,請先登陸");
            return Action.LOGIN;       //用戶如果不存在,返回login直
        }
    }
}

(8) main.jsp

<%--
  Created by IntelliJ IDEA.
  User: mairr
  Date: 17-11-28
  Time: 下午5:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>main.jsp</title>
</head>
<body>
    <a href="success.jsp">book del</a><br>
    <a href="success.jsp">book add</a><br>
    <a href="success.jsp">book update</a><br>
    <a href="success.jsp">book find</a><br>

</body>
</html>

(9) login.jsp

<%--
  Created by IntelliJ IDEA.
  User: mairr
  Date: 17-11-28
  Time: 下午5:17
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陸</title>
</head>
<body>
   <center>
        ${requestScope.msg}<br>
        <form action="login.action" method="post">
            <table>
                <tr>
                    <td><label style="text-align: right;">用戶名:</label></td>
                    <td><input type="text" name="username"></td>
                </tr>
                <tr>
                    <td><label style="text-align: right;">密碼:</label></td>
                    <td><input type="password" name="password"></td>
                </tr>
                <tr>
                    <td align="right" colspan="2">
                        <input type="submit" value="登陸">
                    </td>
                </tr>
            </table>
        </form>
   </center>
</body>
</html>

(10)success.jsp

<%--
  Created by IntelliJ IDEA.
  User: mairr
  Date: 17-11-28
  Time: 下午5:42
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功頁面</title>
</head>
<body>
用戶${user.username}操作成功
</body>
</html>

(11) struts.xml配置:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
    <package name="struts2" namespace="/" extends="struts-default">
        <!--聲明攔截器-->
        <interceptors>
            <interceptor name="privilege" class="cn.Mairr.interceptor.PrivilegeInterceptor"/>
            <interceptor-stack name="mystack">
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="privilege"/>
            </interceptor-stack>
        </interceptors>
        <!--用戶登陸操作-->
        <action name="login" class="cn.Mairr.action.LoginAction">
            <result>/main.jsp</result>
            <result name="input">/login.jsp</result>
        </action>
        <!--關於book操作-->
        <action name="book_*" class="cn.Mairr.action.BookAction" method="{1}">
            <result>/success.jsp</result>
            <result name="login">/login.jsp</result>
            <!--在action中使用自定義攔截器-->
            <interceptor-ref name="mystack"/>
        </action>
    </package>
</struts>

 

 

  完成上述程序之后,發布程序,登錄本機http端口,查看攔截器實現功能;(http://localhost:8080/login.jsp)

  • 登錄界面如下:

 

--------->(登陸失敗)

 

  • 登陸成功(用戶名:Mairr   密碼:123 )

----------->(登陸成功,頁面跳轉到操作界面)

 

-------->(選擇操作)

 

  上面的案例中,創建了一個方法過濾攔截器PrivilegeInterceptor,然后在Struts.xml中配置了該攔截器,如果用戶沒有登陸,則無法對頁面進行相應的操作,只有登陸后才有權操作頁面的相應功能。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM