Struts2攔截器Interceptor


攔截器是Struts2框架的核心,它主要完成解析請求參數、將請求參數賦值給Action屬性、執行數據校驗、文件上傳等工作。Struts2設計的靈巧性,攔截器起了關鍵性的作用,當需要擴展Struts2功能時,只需要提供對應攔截器,并將它配置在Struts2容器中即可;如果不需要該功能時,也只需要取消該攔截器的配置即可。
Struts2內建了大量的攔截器,這些攔截器以name-class對的形式配置在struts-default. xml文件中,其中name是攔截器的名字,就是以后我們使用該攔截器的唯一標識;class則指定了該攔截器的實現類,如果我們定義的package繼承了Struts2的默認struts-default包,則可以自由使用它下面定義的攔截器,否則必須自己定義這些攔截器。


2.自定義攔截器的實現

為了實現某些操作,我們可以自定義攔截器,自定義攔截器有三種方式定義。分別為實現Interceptor接口,繼承抽象類AbstractInterceptor,繼承MethodFilterInteceptor類。

方式一,實現Interceptor接口。重寫String intercept(ActionInvocation invocation)方法。

package test002Iterceptor;

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

/**
 * Created by yangcs on 2017/2/1.
 * 通過實現Interceptor接口,重寫String intercept(ActionInvocation invocation)方法自定義一個攔截器
 */
public class Iterceptor001 implements Interceptor{
    @Override
    public void destroy() {

    }

    @Override
    public void init() {

    }

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        System.out.println("開始攔截");
        String result = actionInvocation.invoke();  //invoke()方法會把請求傳遞到下一個攔截器或者最終的action中
        System.out.println("結束攔截");
        return result;
    }
}

為了使用此攔截器,我們必須將此攔截器進行注冊,隨后再在要使用此攔截器的Action中引用。即首先在<package>中注冊,內容如下:

<interceptors>
      <interceptor name="login001" class="test002Iterceptor.Iterceptor001"></interceptor>
</interceptors>

注冊完成后,如果我們要在login.action中使用此攔截器,只需要在<action>中增加如下內容:

<interceptor-ref name="login001"></interceptor-ref>

實例流程分析:當我們為LoginAction配置了攔截器時,并且有客戶端請求此Action時,會首先被此攔截器攔住,然后執行System.out.println("開始攔截"),隨后我們調用invocation.invoke()方法,它會把請求繼續傳遞給下一個攔截器,下一個攔截器也會繼續執行相應代碼后再調用invoke方法繼續傳遞,直到請求到達最后一個攔截器,它會把請求傳遞給Action,比如,我們這里只用到了一個攔截器,當它執行完成后,會把請求直接轉交到LoginAction處理,LoginAction處理完成后,它會返回結果給MyInterceptor攔截器。

方式二、繼承AbstractInterceptor抽象類,重寫String intercept(ActionInvocation invocation)方法

package test002Iterceptor;

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

/**
 * Created by yangcs on 2017/2/1.
 * 繼承AbstractInterceptor抽象類,重寫String intercept(ActionInvocation invocation)方法實現一個攔截器
 */
public class AbsIterceptor002 extends AbstractInterceptor{
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        actionInvocation.addPreResultListener(new PreResultListenerAction(){});   //這里調用了定義好的result監聽器,則配置了此攔截器的action在發送result前,會調用監聽器中的beforeResult()方法!
        System.out.println("AbstractIntorceptor開始攔截");
        String result = actionInvocation.invoke();
        System.out.println("AbstractIntorceptor結束攔截");
        return result;
    }
}

然后注冊此攔截器,在<interceptors>元素進行進行配置,內容如下:

<interceptor name="login002" class="test002Iterceptor.AbsIterceptor002"></interceptor>

隨后再在LoginAction中引用此攔截器,即在<action name="login" ...>配置如下內容:

<interceptor-ref name="login002"></interceptor-ref>  

方式三、繼承MethodFilterInteceptor類,重寫String doIntercept(ActionInvocation invocation) 方法。

package test002Iterceptor;

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

/**
 * Created by yangcs on 2017/2/1.
 * 繼承MethodFilterInteceptor類,重寫String doIntercept(ActionInvocation invocation) 方法實現一個攔截器
 */
public class MethodFilterInterceptor003 extends MethodFilterInterceptor{
    @Override
    protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
        System.out.println("MethodFilterInterceptor開始攔截");
        String result = actionInvocation.invoke();
        System.out.println("MethodFilterInterceptor結束攔截");
        return result;
    }
}

然后注冊此攔截器,在<interceptors>元素進行進行配置,內容如下:

<interceptor name="login003" class="test002Iterceptor.AbsIterceptor002"></interceptor>

隨后再在LoginAction中引用此攔截器,即在<action name="login" ...>配置如下內容:

<interceptor-ref name="login003"></interceptor-ref>

分析:當配置到此,實質便為LoginAction配置了三個攔截器,當我們點擊登錄時會在控制臺打印出如下語句:

開始攔截
Abs開始攔截
method開始攔截
--先執行攔截器,再執行此Action
method結束攔截
Abs結束攔截
結束攔截

攔截器的執行順序和過濾器filter一樣,取決于在action標簽中的配置順序

其實當我們點擊登錄時,本來是要訪問LoginAction,最后會把LoginAction的執行結果傳遞給訪問者。但是當我們配置了攔截器時,當我們去訪問Action時,會首先被攔截,隨后攔截器執行一些操作后才會繼續把請求傳遞下去。

下圖說明攔截流程:

:自定義攔截器需要特別注意的是不要忘記引入struts2默認的攔截器,可以使用攔截器棧(Interceptor Stack)來組合多個攔截器:

    <interceptors>
        <interceptor name="login001" class="test002Iterceptor.Iterceptor001"></interceptor>
        <interceptor name="login002" class="test002Iterceptor.AbsIterceptor002"></interceptor>
        <interceptor name="login003" class="test002Iterceptor.MethodFilterInterceptor003"></interceptor>
        <interceptor name="interceptor04" class="test002Iterceptor.MethodFilterInterceptor003"></interceptor>
        <interceptor-stack name="login">
            <interceptor-ref name="login001" ></interceptor-ref>
            <interceptor-ref name="login002" ></interceptor-ref>
            <interceptor-ref name="login003" ></interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <!--這個是struts2默認的攔截器棧,當自定義攔截器時,這個默認的攔截器就會失效,必須手動添加配置,否則就會有問題-->
        </interceptor-stack>
    </interceptors>

上面分別使用了三種方式來創建自定義的攔截器,第一種方式是最原始的實現方式(實現Interceptor接口),第二種方式的好處是我們可以不必重寫所有的方法(繼承AbstractInterceptor抽象類),較常用。第三種方式進行了擴展(繼承MethodFilterInterceptor類),可以更靈活地對action中不同的方法進行單獨的攔截:

使用來MethodFilterInterceptor靈活攔截

步驟一、建立MethodAction,代碼如下:

package com.asm;
import com.opensymphony.xwork2.ActionSupport;
public class MethodAction extends ActionSupport{
    public String m1(){
        return SUCCESS;
    }
    public String m2(){
        return SUCCESS;
    }
    public String m3(){
        return SUCCESS;
    }
}

步驟二、注冊此Action,并為此Action配置攔截器。配置內容如下:

<action name="*_*" class="com.asm.MethodAction" method="{2}">
        <result name="success">/{2}Suc.jsp</result>
        <interceptor-ref name="myMet">
        </interceptor-ref>
</action>

我們為此Action配置了前面寫的MyMethodFilterInterceptor攔截器,并在link.jsp中增加如下鏈接:

<a href="<%=request.getContextPath()%>/Method_m1.action">m1</a><br>
<a href="<%=request.getContextPath()%>/Method_m2.action">m2</a><br>
<a href="<%=request.getContextPath()%>/Method_m3.action">m3</a><br>

當點m1時會訪問到m1Suc.jsp頁面, 點m2、m3會分別訪問到m2Suc.jsp、m3Suc.jsp頁面。現在假如我們想訪問m2、m3時不被攔截,我們只需修改MyMethodFilterInterceptor注冊:修改內容為:

<interceptor name="myMet" class="com.asm.MyMethodFilterInterceptor">
    <param name="excludeMethods">m2,m3</param>
</interceptor>

它的作用和增加<param name="includeMethods">m1</param>等價。上面是指定m2,m3方法調用時不被攔截,這里是指定只攔截m1。除了這種在注冊攔截器時指定攔截外,還可以在引用攔截器時指定,即如下形式:

<interceptor-ref name="myMet">
    <param name="excludeMethods">m2,m3</param>
    <param name="includeMethods">m1</param>
</interceptor-ref>

上面的兩處<param>配置是等價的,但是如果〈param〉配置沖突,誰起作用?即如果我們對m1配置了excludeMethods同時又配置了includeMethods時,誰起作用,我們可以進行這些沖突的驗證。以下是驗證結果:

引用配置(在Action引用攔截器時配置)時,以includeMethods的配置為準。

一旦我們為攔截器使用了<param>配置,而對m1這樣的方法不配置任何,就不會被攔截。

但是如果不使用<param>,它們全部都要被攔截。

注冊配置時(在注冊攔截器時配置),情況和“引用配置”完全一樣。
引用配置和注冊配置沖突時,以引用配置為準。

使用默認的execAndWait攔截器實現查詢等待效果

當我們進行數據庫查詢等相關的操作時,如果服務器負荷過重可能不能及時把數據查詢出來,進而會在狀態攔顯示“正在打開...”,但卻一直轉不到相關的頁面,這將給客戶端帶來不便,甚于很多人會因此不愿使用網站的所有服務。對此我們可以在客戶提交時,馬上轉到一個頁面,并在該頁面顯示“您的請求已提交,服務器正在查詢,請等待...”的內容,這樣客戶將不會陷于無賴的等待中。

對于此要求,struts2可以輕松幫我們完成。

下面新建struts2wait項目演示此實例。
建立LoginAction,代碼如下:

package com.asm;
public class LoginAction extends ActionSupport {
    public String execute() throws Exception {
        Thread.sleep(5000);
        return SUCCESS;
    }
}

說明:為了模擬服務器負荷過重,查詢時間要很長。我們在使用了線程休眠的方式。
隨后配置此Action,配置的主要內容如下:

<action name="login" class="com.asm.LoginAction">
    <interceptor-ref name="defaultStack"></interceptor-ref>
    <interceptor-ref name="execAndWait"></interceptor-ref>
    <result name="wait">/wait.jsp</result>
    <result name="success">/success.jsp</result>
</action>

注意:在配置前我們先是使用了默認的攔截器,再此強調在我們為Action配置攔截器時,應該總是配上默認的攔截器。隨后我們使用了execAndWait攔截器,如需要配置此攔截器,此攔截器一定要配置在最后,否則會出現一些難預知的結果。如果使用此攔截器,我們通常還會配置wait的result結果集,因為當我們請求的Action在未執行完,就是未返回結果時,會首先把wait result返回,而在wait result所指定的頁面中通常會再次發送請求給原始的Action。所以wait.jsp的主要內容如下:

<head>
    <meta http-equiv="refresh" content="1;login.action">
</head>
<body>      查詢請求已提交,正在查詢數據,請等待...   </body>

在此頁面中,我們指定了每隔1秒便發送請求到login.action中去。這樣,客戶端便可以及時獲取查詢結果。結合此實例,我們簡要分析流程:當我們發出請求到此Login.Action中去時,首先會被exeAndWait攔截器攔截到,這樣它便跳轉到wait.jsp頁面,在wait.jsp頁面中每隔1秒我們會繼續發送此Action的請求,當再次請求到達LoginAction時,如果它已經返回,則會跳到此Action返回的頁面,如果LoginAction未返回,則繼續停留在wait.jsp中,再隔1秒又再次發送請求到LoginAction中去。

其實如果服務器能很快查詢出結果,我們則不需要用到wait.jsp頁面,我們只需在<interceptor-ref name="execAndWait"></interceptor-ref>中增加如下一段配置:

<param name="delay">6000</param>

這樣便延遲請求到達wait.jsp頁面,這樣當請求到達時它會在LoginAction中執行6秒時間再到wait.jsp,而6秒LoginAction足以執行完并返回結果,所以當攔截器
執行時首先檢查到此Action已經返回結果。則攔截器會直接用此返回頁面,如果此時發現LoginAction并未執行完,它便會把wait resutl指定的頁面返回。

使用默認的TokenInterceptor攔截器防止表單重復提交

由于某些原因,用戶在進行類似表單提交的操作后,以為表單未被提交,會進行多次的重復提交。為了避免用戶多次提交給服務器帶來負荷。我們會對表單提交這樣的操作進行一些處理,以告訴用戶不要重復提交。
下面我們建立struts2token項目,使用struts2的token攔截器來實現此案例(也可以通過自己在session中生成token令牌來實現這一效果:使用Session防止表單重復提交)。
步驟一,編寫login.jsp頁面,內容如下:

<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<html>
    <body>
        <form action="<%=request.getContextPath()%>/login.action" >
            姓名:<input type="text" name="username"><br>
            密碼:<input type="password" name="password"><br>
            <input type="submit" value="登錄">
            <s:token></s:token>
        </form>
    </body>
</html>

說明,此登錄頁面中的關鍵技術就是使用了標簽庫中的<s:token></s:token>標簽,它的作用就是在用戶訪問此頁面時會生成一個sessionId,在提交時會服務器會據此驗證表單是否已提交。“To set a token in your form, you should use the token tag. This tag is required and must be used in the forms that submit to actions protected by this interceptor”,這句話的大概意思就是我們必須要在提交的表單中使用這個token tag,這樣提交到的Action便能配置TokenInterceptor攔截器驗證表單是否重復提交。

步驟二,編寫LoginAction,主要代碼如下:

package com.asm;
public class LoginAction extends ActionSupport {
    public String execute() throws Exception {
        System.out.println("---->執行execute方法...");
        return SUCCESS;
    }
}

步驟三,struts.xml主要配置內容如下:

<struts>
    <package name="tokenTest" extends="struts-default">
        <action name="login" class="com.asm.LoginAction">
            <result name="success">/success.jsp</result>
            <result name="invalid.token">/subError.jsp</result>
            <interceptor-ref name="token"></interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
    </package>
</struts>

說明:在此Action下,我們配置了token攔截器,另注意到在此Action下我們還配置了一個“invalid.token”result,因為提交時服務器如果根據token標簽產生的sessionId判斷出表單已提交,它則返回invalid.token指向的視圖。比如這里,如果重復提交則會轉到.../subError.jsp中去。另不要忘記了引入默認的攔截器棧。補充:關于token攔截器更多細節可以訪問org.apache.struts2.interceptor.TokenInterceptor類的api說明。

步驟四,編寫配置中所用到jsp頁面,這些頁面編寫簡單,在此省去。

步驟五、發布測試,請注意訪問login.jsp頁面時,查看源文件時會發現增加了兩個隱藏域信息。

步驟六、更換攔截器:我們還可以使用tokenSession攔截器,它的功能比上面的增強,它能保證持有相同sessionId的并發請求等待第一個完成之后才能被提交處理,但是它返回的是action執行后的result.接著上例,我們只需要在配置中作如下修改:把上面的token攔截器改成

<interceptor-ref name="tokenSession"></interceptor-ref> 

即可。隨后便可以測試,測試時會發現如果我們重復提交,它總是返回到上一次的success.jsp頁面,但是它并不是經過LoginAction中的execute處理后返回(我們System.out.print語句在重復提交時并未打印出來),而是此攔截器判斷出是重復后直接返回上一次提交轉向的頁面。

使用攔截器實現權限驗證

為了說明此問題,我們建立struts2auth項目,流程圖如下:

簡短說明:當我們訪問main.jsp頁面,并試圖通過此頁面中的鏈接地址:note.action來訪問到.../WEB-INF/note.jsp頁面時,由于訪問的note.action配置了攔截器,所以會被攔截,如果攔截器判斷登錄則可以訪問,否則會跳到登錄頁面。如果我們從登錄頁面直接到main.jsp頁面,再來訪問note.action時,同樣被攔截但是由于登錄過,所以可以訪問到此action對應的內容。由這里的分析可以看出關鍵點就登錄成功時給出標志提供給攔截器判斷是否成功登錄。

步驟一,搭建好相關的開發環境,并準備好登錄頁面login.jsp,代碼如下:

<form action="<%=request.getContextPath()%>/login.action" method="post">
        姓名:<input type="text" name="username"><br>
        密碼:<input type="password" name="password"><br>
        <input type="submit" value="登錄">
</form>

步驟二,建立相應的Action:LoginAction。代碼如下:

package com.asm;
public class LoginAction extends ActionSupport {
    private String username;
    Map session;
    public String execute() throws Exception {
        if(username.equals("admin")){
            session = ActionContext.getContext().getSession();
            session.put("loginSign", "loginSuccess");
            return SUCCESS;
        }else{
            return LOGIN;
        }
}
...省略username的get/set方法
}

說明:我們這里是設定了只有登錄用戶名為admin時,此Action才設置登錄標志。另這里獲取Session對象采取的是“與Servlet解耦合的非IOC方式”。

步驟三,編寫攔截器類,代碼如下:

package com.asm.interceptor;
public class AuthInterceptor extends AbstractInterceptor {
    public String intercept(ActionInvocation invocation) throws Exception {
        Map session = invocation.getInvocationContext().getSession();
        // session=ActionContext.getContext().getSession();
        if (session.get("loginSign") == null) {
            return "login";
        } else {
            String result = invocation.invoke();
            return result;
        }
    }
}

步驟四,配置此Action相關,主要配置內容如下:

<struts>
    <package name="tokenTest" extends="struts-default">
        <interceptors>
            <interceptor name="auth"
                class="com.asm.interceptor.AuthInterceptor">
            </interceptor>
            <interceptor-stack name="authStack">
                <interceptor-ref name="auth"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref> 
            </interceptor-stack>
        </interceptors>
        <action name="login" class="com.asm.LoginAction">
            <result name="success">/main.jsp</result>
            <result name="login">/login.jsp</result>
        </action>

        <action name="note">
            <result>/WEB-INF/note.jsp</result>
            <result name="login">/login.jsp</result>
            <interceptor-ref name="authStack"></interceptor-ref>
        </action>
    </package>
</struts>

說明:結合前面的一些代碼來看,當我們為note.action配置了前面寫所的AuthInterceptor攔截器時,如果我們要訪問note.action,攔截器會首先判斷是否登錄,如果登錄則繼續把請求傳遞下去,如果沒有登錄則會返回到登錄頁面。

使用默認的AnnotationWorkflowInterceptor攔截器為action方法添加注解調用

AnnotationWorkflowInterceptor此攔截器可以調用在Action中任何有注解的方法。下面我們來演示它的使用,具體步驟如下:

步驟一,建立struts2annotationInt項目,并建立LoginAction類,代碼如下:

package com.asm;
...省略導入的包
public class LoginAction extends ActionSupport {
    private String username;
    @Before
    public String myBefore() {
        System.out.println("調用myBefore方法");
        return LOGIN;
    }
    @After
    public void myAfter() throws InterruptedException {
        Thread.sleep(5000);
        System.out.println("----調用myAfter方法");
    }
    @BeforeResult
    public void myBeforeResult() {
        System.out.println("----調用myBeforeResult方法");
    }
    public String execute() throws Exception {
        System.out.println("調用execute方法");
        return SUCCESS;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        System.out.println("---調用set方法" + username);
        this.username = username;
    }
}

說明:要想使用方法成為被攔截器監視的注解方法,只需在方法關加上@...這樣的形式并導入相關的類即可。

步驟二,編寫相關的jsp及配置該Action,主要配置內容如下:

<struts>
    <package name="ano" extends="struts-default">
        <interceptors>
            <interceptor name="anno"                class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor">
            </interceptor>
            <interceptor-stack name="annoStack">
                <interceptor-ref name="anno"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        <action name="login" class="com.asm.LoginAction">
            <result name="success">/success.jsp</result>
            <result name="login">/login.jsp</result>
            <interceptor-ref name="annoStack"></interceptor-ref>
        </action>
    </package>
</struts>

結合配置說明:當我們為LoginAction配置了AnnotationWorkflowInterceptor攔截器時,LoginAction中的所有注解方法才真正生效。下面重點是來討論這些方法的執行順序及作用。
加@Before注解的方法意思是在action的execute方法執行之前被調用,但是此方法如果返回不為空的話,它的返回結果將是真正的返回結果,比如這里我們return LOGIN,這樣無論以什么用戶名登錄,它總會返回到login result(這里為login.jsp頁面) 。但是從執前結果來看,在返回前仍執行了標記為@BeforeResult的方法:will be invoked after the action method but before the result execution。意思是在返回結果集前調用此方法。下面我們把public String myBefore()方法中的return LOGIN注釋掉,并讓修改此方法的返回類型為void。隨后登錄測試(注意要重新部署當前項目),可以發現執行結果如下:

調用myBefore方法
---調用set方法
調用execute方法
----調用myBeforeResult方法
----調用myAfter方法

從執行的順序來看,標記為@After的方法最后執行,并且可以發現:它會延時5秒執行,但是在延時執行時,瀏覽器并沒有成功跳到success.jsp頁面,而是在5秒后,控制臺打印出myArter方法中的內容同步跳轉到success.jsp頁面。@After :will be invoked after the action method and result execution。意為在execute方法執行并且返回結果后此方法被調用。但是從測試來看,標記為@After的方法是會影響到結果的返回(延時返回)。 強調:注意方法的執行順序,相關的內容可以參看AnnotationWorkflowInterceptor類的api文檔。

使用PreResultListener監聽器,實現回調

PreResultListener監聽器對象一般是綁定在攔截器上使用。

下面我們新建struts2PreResultListener項目進行測試。

步驟一,建立類,實現PreResultListener接口,主要代碼如下:

package com.asm;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.PreResultListener;
public class MyPreResultListener implements PreResultListener {
    public void beforeResult(ActionInvocation invocation, String res) {
        // System.out.println(invocation.getAction());
        // System.out.println(invocation.getResultCode());
        /**回調Action中的方法:
         * LoginAction lg = (LoginAction) invocation.getAction(); try {
         * lg.execute(); } catch (Exception e) { e.printStackTrace(); }
         */
        System.out.println("檢驗到PreResultListener被執行");
    }
}                       

步驟二,copy前面在自定義攔截器中用到的三個攔截器,并綁定MyPreResultListener對象,首先是在MyInterceptor類中,我們只需要修改intercept方法即可,代碼如下:

public String intercept(ActionInvocation invocation) throws Exception {
        invocation.addPreResultListener(new MyPreResultListener());
        System.out.println("開始攔截");
        String result = invocation.invoke();
        System.out.println("結束攔截");
        return result;
}

隨后在MyMethodFilterInterceptor類中作類似修改。為了區別,我們在MyAbstractInterceptor類中不綁定MyPreResultListener對象。

步驟三,編寫struts.xml文件,主要配置內容如下:

<struts>
    <package name="interceptor" extends="struts-default">
        <interceptors>
            <interceptor name="myIpt" class="com.asm.MyInterceptor">
            </interceptor>
            <interceptor name="myAbs"
                class="com.asm.MyAbstractInterceptor">
            </interceptor>
            <interceptor name="myMet"
                class="com.asm.MyMethodFilterInterceptor">
            </interceptor>
        </interceptors>

        <action name="login" class="com.asm.LoginAction">
            <interceptor-ref name="myIpt"></interceptor-ref>
            <interceptor-ref name="myAbs"></interceptor-ref>
            <interceptor-ref name="myMet"></interceptor-ref>
            <result name="success">/success.jsp</result>
        </action>               
    </package>
</struts>

說明:此實例的只是簡要地演示了PreResultListener的使用,所以相對簡單。對于其它相關操作,我們可以從MyPreResultListener類注釋掉的內容中找到一此端倪。強調:從執行結果來看,PreResultListener對象會在返回結果前執行,請注意結合攔截器執行的順序來看。此實例目前作為了解。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產品,是在 struts1和WebWork的...
    inke閱讀 2,269評論 0 50
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,709評論 18 399
  • spring mvc 工作機制(原理): DispatcherServlet主要用作職責調度工作,本身主要用于控制...
    java大濕兄閱讀 1,907評論 5 24
  • 傷感是一顆流彈,抽不冷被擊中。抑或是在最沒防備的時候,穿著新鞋踩了一腳屎。事實證明,人為制造高潮是行不通的。事實還...
    picspin閱讀 521評論 0 2