1. 程式人生 > >關於struts2中的攔截器和登陸驗證

關於struts2中的攔截器和登陸驗證

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                 

今天給幾個熱愛JAVA的同學們講了Struts2的一些知識,重點討論了其最具價值的攔截器。

 

不知道大家還記不記得,在《Struts2之伺服器端驗證》裡我說過這樣一句話“在到達Login Action之前,驗證已經完成了”。我很希望有人能提出這是為什麼,這樣我就可以說,這是攔截器的功勞,我們就可以研究攔截器了。 

其實,攔截器並不難,也不是十分難懂的東西。在這裡再做一些補充.

 

開啟幫助文件(struts-2.0.6\\docs\\docs\\interceptors.html)的攔截器部分。

 

能讀懂英文技術文件是程式設計師必備的基本素質之一,慢慢來吧,只要靜下心來逐字逐句的推敲,沒有什麼理解不了的。實在看不懂,那就看看[Action Lifecyle]這張圖吧。Action生命週期,Action被一些攔截器包圍著,也就是說在Action執行之前或之後,攔截器會被執行。

 

這就是攔截器,把程式看作是一個順序執行的流,在執行Action的程式碼之前或之後,攔截器會打斷Action的執行,讓程式先執行攔截器的程式碼,這也許就是為什麼把它叫做攔截器的原因。有的時候,攔截器還會阻止Action的執行,比如說在驗證失敗的情況下,應該讓程式返回到輸入介面讓使用者重新輸入。

 

從圖上還可以看出,一個Action之外不是隻有一個攔截器,那麼先執行哪個攔截器呢?Struts2把多個攔截器放在了一個棧中,我們把它叫做攔截器棧。一方面,棧可以解決攔截器的執行順序問題,另一方面,把相關的攔截器放在一個棧中,管理起來也比較方便。

 

Struts2的一個優點是它的可配置性,我們可以根據實際情況選擇需要的功能。當然也給我們帶來了一些麻煩,就拿攔截器來說吧,要想讓攔截器起作用,先要對它進行配置。配置攔截器,需要在struts.xml中加入相關配置:

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

     <interceptors>

         <interceptor name="timer" class=".."/>

         <interceptor name="logger" class=".."/>

     </interceptors>

     <action name="login"

        class="tutorial.Login">

          <interceptor-ref name="timer"/>

          <interceptor-ref name="logger"/>

           <result name="input">login.jsp</result>

           <result name="success"

              type="redirect-action">/secure/home</result>

     </action>

</package>

=====================================================================

<interceptors>和</interceptors>標記對錶示要配置一些攔截器,裡面的每一條是一個攔截器。

 

<interceptor name="timer" class=".."/>

interceptor表示這是一個攔截器,name屬性是給它起一個名字,class屬性是指出它的實現類,也是程式碼的實際位置。

 

攔截器是攔截Action的,當然也要在Action的配置里加入對它的引用,指出這個Action要使用哪個攔截器。

 

<interceptor-ref name="timer"/>這句話是告訴Struts框架,login Action需要使用前面的timer攔截器。

 

有人也許會說,我們之前並沒有配置攔截器,但剛才好像說過,不是也使用到攔截器了麼?的確,可能是Struts2的開發者怕配置起來太麻煩了,沒有人用吧:P,所以給我預先配置好了一些預設的攔截器和攔截器棧。

 

在struts-default.xml(struts-default.xml在struts2-core-2.0.6.jar包中)裡面定義了很多攔截器:

<interceptor name="alias" class="com.opensymphony.xwork.interceptor.AliasInterceptor"/>

......

裡面的validation和i18n就是我們之前用的驗證和國際化功能。

 

還有很多攔截器棧:

<!-- Basic stack -->

<interceptor-stack name="basicStack">

<interceptor-ref name="exception"/>

<interceptor-ref name="servlet-config"/>

<interceptor-ref name="prepare"/>

<interceptor-ref name="static-params"/>

<interceptor-ref name="params"/>

<interceptor-ref name="conversionError"/>

</interceptor-stack>

...

<interceptor-stack name="defaultStack">

      <interceptor-ref name="exception"/>

      <interceptor-ref name="alias"/>

      <interceptor-ref name="prepare"/>

      <interceptor-ref name="servlet-config"/>

      <interceptor-ref name="i18n"/>

      <interceptor-ref name="chain"/>

      <interceptor-ref name="model-driven"/>

      <interceptor-ref name="fileUpload"/>

      <interceptor-ref name="static-params"/>

      <interceptor-ref name="params"/>

      <interceptor-ref name="conversionError"/>

      <interceptor-ref name="validation"/>

      <interceptor-ref name="workflow"/>

</interceptor-stack>

 

<default-interceptor-ref name="defaultStack"/>

最後這條比較主要,是框架預設使用的攔截器棧,也就是說,defaultStack棧中的攔截器會預設起作用。

 

這也是我們沒有配置validation和i18n,它們就起作用的原因。

 

順便說一下,攔截器應該屬於AOP(面向方面程式設計)思想的一種實現,它的確給開發帶來了很多好處,一方面可以把一個大的問題分解成多個小問題分別處理,另一方面可以使Action專注與處理自己的事情,把相關的功能分散給各個攔截器處理。

 

在《Struts2之伺服器端驗證》中我們詳細討論了關於登陸驗證的問題,只有通過登陸驗證,拿到令牌的使用者才能進入我們的系統。為此我們建立了登陸驗證頁面和相應的Action類,登陸驗證(Login.jsp)負責提供給使用者輸入帳號和密碼的機會,Login Action負責驗證使用者輸入的帳號和密碼是否正確,驗證通過的情況下把帳號和密碼儲存到Session中,就相當於使用者拿到了一塊令牌,就是一個合法使用者了。

 

我們的目的是限制非法使用者,也就是沒有拿到令牌的使用者,不能訪問我們的系統。但是我們只進行了登陸驗證和儲存令牌的工作,並沒有做限制非法使用者的工作。現在不守規矩的使用者就可以直接在瀏覽器的位址列裡輸入:http://localhost:8080/Success.jsp

訪問我們的Success.jsp頁面,這當然是不能容忍的。

 

在沒有學習攔截器之前,我們當然可以在Success.jsp頁面里加程式碼進行限制,先從Session中取出使用者名稱和密碼,如果取到了則說明使用者已經登陸系統了,否則讓瀏覽器顯示Login.jsp讓使用者登陸系統,這樣做一點問題也沒有,就相當於我們在每一個房間門口都安排了一個檢查令牌的人一樣,萬無一失。不過,如果系統的受限制資源多起來的時候,比如說像Success.jsp或Action很多,幾十個,幾百個的時候,這樣的程式碼我們就要寫很多遍,這當然也是聰明的我們所不能容忍的:P

 

顯然,讓攔截器來做這項工作再合適不過了。我們可以新增一個攔截器,讓它在這些受限制的資源被執行之前先執行,在攔截器裡我們檢查使用者是否登陸了系統,如果登陸了才讓他們訪問,否則送給使用者一個Login.jsp讓使用者登陸。這樣我們的檢查程式碼只需要寫一次就一勞永逸了。

 

明白了原理之後還需要做幾項具體的工作:

1,自己寫一個攔截器,實現檢查使用者是否登陸的功能。

2,新增攔截器的配置,讓我們自己寫的攔截器起作用。

 

首先我們來完成第一個任務,開啟:

struts-2.0.6docsdocsguides.html裡面的

struts-2.0.6docsdocswriting-interceptors.html幫助。

從這個幫助裡我們可以看出,攔截器必須實現com.opensymphony.xwork2.interceptor.Interceptor介面。根據經驗,init()方法應該是初始化攔截器的方法,可以把一些初始化工作的程式碼放在它裡面,destroy()方法與之相反,在攔截器被銷燬之前,讓我們有機會執行一些善後工作。

 

顯然intercept()方法,是新增真正執行攔截工作的程式碼的地方,如果我們不需要初始化和清理的操作,可以直接繼承com.opensymphony.xwork2.interceptor.AbstractInterceptor類,覆蓋它的intercept()方法。這個方法有個ActionInvocation型別的引數,可以用它取得Session或轉發請求等操作。

 

先在src下建立一個包:tutorial.interceptor

在這個包下建立一個類LogonInterceptor繼承於AbstractInterceptor,覆蓋intercept()方法:

 

package tutorial.interceptor;

import java.util.Map;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

 

public class LogonInterceptor extends AbstractInterceptor {

      public String intercept(ActionInvocation invocation) throws Exception {

          // 取得請求的Action名

          String    name = invocation.getInvocationContext().getName();

 

          if (name.equals("Login")) {

              // 如果使用者想登入,則使之通過

              return invocation.invoke();

          } else {

              // 取得Session。

              ActionContext ac = invocation.getInvocationContext();

              Map session =    (Map)ac.get(ServletActionContext.SESSION);

  

              if (session == null) {

                  // 如果Session為空,則讓使用者登陸。

                  return "login";

              } else {

                  String username = (String)session.get("username");

                  if (username == null) {

                      // Session不為空,但Session中沒有使用者資訊,

                      // 則讓使用者登陸

                      return "login";

                  } else {

                      // 使用者已經登陸,放行~

                      return invocation.invoke();

                  }

              }

          }

      }

}

 

今天的內容有點多,接下來還要對這個攔截器進行配置:

關於怎樣配置一個攔截器使之對所有的Action起作用請參考:

struts-2.0.6docsdocshow-do-we-configure-an-interceptor-to-be-used-with-every-action.html

修改struts.xml,

1,自定義攔截器

2,重定義預設攔截器堆疊

3,新增一個global-results,使用者在驗證失敗的情況下跳轉到登陸驗證頁面

struts.xml的完整內容:

<!DOCTYPE struts PUBLIC

      "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

      "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts><!-- Configuration for the default package. -->

<constant name="struts.custom.i18n.resources" value="globalMessages" />

 

<include file="struts-validation.xml" />

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

 

    <!-- 自定義攔截器 -->

    <interceptors>

     <interceptor name="logon" class="tutorial.interceptor.LogonInterceptor"/>

     <!-- 自定義攔截器堆疊 -->

     <interceptor-stack name="myStack">

      <interceptor-ref name="logon"/>

      <!-- 引用預設的攔截器堆疊 -->

      <interceptor-ref name="defaultStack"/>

     </interceptor-stack>

    </interceptors>

 

    <!-- 重定義預設攔截器堆疊 -->

    <default-interceptor-ref name="myStack"/>

 

    <global-results>

     <result name="login" type="redirect-action">Login!input.action</result>

    </global-results>

 

        <action name="HelloWorld" class="tutorial.HelloWorld">

               <result>/HelloWorld.jsp</result>

           </action>

        

           <action name="Login" class="tutorial.Login">

              <result>/Success.jsp</result>

              <result name="input">/Login.jsp</result>

           </action> 

</package>

</struts>

 

儲存修改並佈署專案到Tomcat下,啟動Tomcat

在瀏覽器的位址列中輸入:

http://localhost:8080/tutorial/HelloWorld.action

系統會自動轉到Login頁面。           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述