一、攔截器
1、攔截器小介
攔截器的功能類似於web.xml文件中的Filter,能對用戶的請求進行攔截,通過攔截用戶的請求來實現對頁面的控制。攔截器是在Struts-core-2.2.3.jar中進行配置的,原始的攔截器是在struts-default.xml中配置的,裏面封存了攔截器的基本使用方法。
Struts2攔截器功能類似於Servlet過濾器。在Action執行execute方法前,Struts2會首先執行struts.xml中引用的攔截器,如果有多個攔截器則會按照上下順序依次執行,在執行完所有的攔截器的interceptor方法後,會執行Action的execute方法。
Struts2的攔截器必須從com.opensymphoy.xwork2.interceptor.Interceptor中實現該接口,在被定義的攔截器中有下面三個方法需要被實現:
- void destroy();
- void init();
- String intercept(ActionInvocation invocation) throws Exception;
自定義的攔截器需要重寫上面三個方法。另外Struts2的攔截器配置文件struts.xml它是繼承了原始文件struts-default.xml文件的,這樣在相應的<package>中就會自動擁有struts-default.xml中的所有配置信息了。具體代碼如下:
- <package name="demo" extends="struts-default" > ... </package>
2、Demo
想要使用攔截器必須要經過配置,struts2採用的是映射的方法,所以想用使用某一個功能就必須在配置文件中配置,攔截器也不例外。所以必須在package中添加相應的攔截器元素,同時將攔截器關聯相應的class文件,這樣在執行action前纔會執行相應的攔截器,具體使用方法如下。
(1)添加配置文件struts.xml,並在該文件中添加攔截器
- <package name="testLogin" namespace="/" extends="struts-default">
- <!-- 攔截器 -->
- <interceptors>
- <interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
- </interceptors>
- <action name="demo" class="com.action.LoginAction">
- <result name="error" type="redirect">/error.jsp</result>
- <result name="success">/success.jsp</result>
- <result name="checkError">/checkSession.jsp</result>
- <interceptor-ref name="myInterceptor"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </action>
- </package>
上面的package中添加了一個名爲myInterceptor的攔截器,併爲該攔截器註冊了一個java類,該類名稱爲MyInterceptor,並被封存在com.interceptor包中。另外還在該package中添加了相應的action,在執行該action前會首先執行myInterceptor攔截器。
(2)編寫被註冊的攔截器類MyInterceptor,該類必須實現com.opensymphoy.xwork2.interceptor.Interceptor接口,並重寫相應的方法
- package com.interceptor;
- import java.util.Map;
- import com.entity.User;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.Interceptor;
- public class MyInterceptor implements Interceptor{
- private User user;
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this.user = user;
- }
- @Override
- public void destroy() {
- // TODO Auto-generated method stub
- System.out.println("----destroy()----");
- }
- @Override
- public void init() {
- // TODO Auto-generated method stub
- System.out.println("-----Init()-------");
- }
- @Override
- public String intercept(ActionInvocation invocation) throws Exception {
- // TODO Auto-generated method stub
- System.out.println("----intercept()------");
- Map<String, Object> session= invocation.getInvocationContext().getSession();
- if(session.get("username")!=null){
- System.out.println("登陸成功!");
- //session.put("username",user.getUsername());
- return invocation.invoke();
- }else{
- System.out.println("登陸失敗!");
- return "checkError";
- }
- }
- }
(3)經過前面兩步後,攔截器已經配置完成,最後一部就是使用攔截器了,在顯示頁面上添加相應的標籤,併爲標籤指定上面創建的名爲demo的action,然後執行頁面即可在控制檯中打印出相應的攔截器內容。
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <form action="demo">
- 用戶名:<input type="text" name="username"><br>
- 密 碼:<input type="text" name="password"><br>
- <input type="submit" name="ok" value="提交">
- </form>
- </body>
- </html>
打印輸出內容:
分析輸出結果,程序編譯階段首先會去讀取配置文件struts.xml,在該配置文件action中順序查找是否添加了攔截器,如果添加了攔截器則根據攔截器名稱在<interceptors>中查找是否定義了該攔截器或者攔截器棧,如果發現定義的是攔截器則根據攔截器查找對應的註冊的class,最後在包內查找註冊的class並執行相應的init()方法;程序運行階段的大致流程和編譯階段類似,用戶在前臺提交請求後,會按照註冊的action在struts.xml中查找與之相對應的,如果查找到將會查找攔截器,沒有查找到的話會相應的拋錯,最後執行攔截器註冊類的intercept方法。
3、攔截器棧
攔截器同樣有棧的概念,它是將使用的攔截器定義到共有的狀態下來實現統一管理,這樣在package中就可以做到攔截器的共享了,大大便利了攔截器的使用。在一個package中往往會用到重複的interceptor,如果每次都在Action中添加interceptor-ref的話就會很麻煩,那麼攔截器棧就是爲了解決這個問題而產生的,具體配置如下:
- <package name="testLogin" namespace="/" extends="struts-default">
- <!-- 攔截器 -->
- <interceptors>
- <interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
- <!-- 定義公共的攔截器鏈,在action標籤中只需要引用攔截器鏈 -->
- <interceptor-stack name="defaultstack1">
- <interceptor-ref name="myInterceptor"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </interceptor-stack>
- </interceptors>
- <action name="demo" class="com.action.LoginAction">
- <result name="error" type="redirect">/error.jsp</result>
- <result name="success">/success.jsp</result>
- <result name="checkError">/checkSession.jsp</result>
- <interceptor-ref name="defaultstack1"></interceptor-ref>
- </action>
- </package>
實例中使用了interceptor-stack來定義了一個名稱爲defaultstack1的攔截器棧,在該棧中添加了要執行的攔截器,把攔截器做了封裝,在Action中直接調用該攔截器棧即可,實現了攔截器棧的共享。
4、默認攔截器棧
另外可以定義默認的攔截器棧,即:如果某個Action中沒有定義攔截器,那麼它會默認執行該公共的攔截器。它和interceptors標籤屬於同一等級的,使用default-interceptor-ref定義。
- <package name="testLogin" namespace="/" extends="struts-default">
- <!-- 攔截器 -->
- <interceptors>
- <interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
- <!-- 定義公共的攔截器鏈,在action標籤中只需要引用攔截器鏈 -->
- <interceptor-stack name="defaultinter">
- <interceptor-ref name="myInterceptor"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </interceptor-stack>
- </interceptors>
- <!-- 定義默認的攔截器棧,會自動註冊到action中 -->
- <default-interceptor-ref name="defaultinter"></default-interceptor-ref>
- <action name="demo" class="com.action.LoginAction">
- <result name="error" type="redirect">/error.jsp</result>
- <result name="success">/success.jsp</result>
- <result name="checkError">/checkSession.jsp</result>
- </action>
- </package>
定義的默認的攔截器棧只是在Action沒有指定攔截器的情況下才執行自定義默認的攔截器棧的,如果在Action中重定義了攔截器,那麼它會覆蓋自定義默認的攔截器棧的。
5、不執行任何攔截器
還有一種情況是一個package中定義了默認的攔截器,但是在編寫的某個Action中並不需要執行任何攔截器,那麼此時可以在相應的Action中添加一個名稱爲defaultStack的攔截器即可,它是系統默認的攔截器,不會有任何操作。
- <package name="testLogin" namespace="/" extends="struts-default">
- <!-- 攔截器 -->
- <interceptors>
- <interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
- <!-- 定義公共的攔截器鏈,在action標籤中只需要引用攔截器鏈 -->
- <interceptor-stack name="defaultinter">
- <interceptor-ref name="myInterceptor"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </interceptor-stack>
- </interceptors>
- <!-- 定義默認的攔截器棧,會自動註冊到action中 -->
- <default-interceptor-ref name="defaultinter"></default-interceptor-ref>
- <action name="demo" class="com.action.LoginAction">
- <result name="error" type="redirect">/error.jsp</result>
- <result name="success">/success.jsp</result>
- <result name="checkError">/checkSession.jsp</result>
- <!-- 添加defaultStack保證不執行攔截器 -->
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </action>
- </package>
6、攔截方法
6.1 用法
上面的攔截器只是實現了對Action的攔截,其實攔截器的功能很強大,它也可以攔截相應Action方法。和攔截Action不同的是想要攔截方法就必須繼承類MethodFilterInterceptor,該類封存在xwork-core.jar中,又一次證明了WebWork是Struts2的核心。另外還需要在配置文件中添加相應的屬性來確定攔截的方法和不攔截的方法,具體配置方法如下:
- <package name="testLogin" namespace="/" extends="struts-default">
- <!-- 攔截器 -->
- <interceptors>
- <interceptor name="myInterceptor" class="com.interceptor.MyInterceptor"></interceptor>
- <!-- 定義公共的攔截器鏈,在action標籤中只需要引用攔截器鏈 -->
- <interceptor-stack name="defaultinter">
- <interceptor-ref name="myInterceptor"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </interceptor-stack>
- </interceptors>
- <action name="demo" class="com.action.LoginAction">
- <result name="error" type="redirect">/error.jsp</result>
- <result name="success">/success.jsp</result>
- <result name="checkError">/checkSession.jsp</result>
- <!-- 在defaultStack中配置攔截方法,參數includeMethods中添加被攔截的方法名稱,excludeMethods中添加不需要攔截的名稱 -->
- <interceptor-ref name="defaultStack">
- <param name="includeMethods">添加要攔截的方法名稱</param><!-- 攔截方法 -->
- <param name="excludeMethods">添加不需要攔截的方法名稱</param><!-- 不攔截方法 -->
- </interceptor-ref>
- </action>
- </package>
繼承MethodFilterInterceptor類的相應攔截方法的類中的代碼:
- package com.interceptor;
- import java.util.Map;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
- public class inter extends MethodFilterInterceptor {
- @Override
- public String doIntercept(ActionInvocation invocation) throws Exception {
- System.out.println("--intercept()--");
- //獲取相應的Session
- Map<String,Object> session=invocation.getInvocationContext().getSession();
- Map request=(Map)ActionContext.getContext().get("request");
- String username=(String)request.get("user.username");
- if(session.get("username") != null){
- String result=invocation.invoke();
- System.out.println("--end()--");
- return result;
- }
- }
- }
6.2 Demo
來看一個攔截方法的實例,並對結果進行分析。下面的實例演示攔截方法的輸出結果,在實例中分別創建了一個loginAction類,添加Action要執行的方法;Inter類,攔截器中重寫MethodFilterInterceptor方法,在控制檯中輸出是否對某個方法進行攔截;login.jsp文件,添加三個按鈕,分別演示三個方法的執行。
(1)struts.xml內方法攔截器的定義,在package中定義了一個名稱爲inter的攔截器,在攔截器中指定了參數,includeMethods用來攔截Method1,excludeMethods中的Method2表示不攔截Methods2方法,具體配置如下代碼:
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <constant name="struts.action.extension" value=","></constant>
- <package name="login" extends="struts-default">
- <interceptors>
- <interceptor name="inter" class="com.interceptor.inter">
- <param name="includeMethods">Method1</param> <!-- 攔截Method1方法 -->
- <param name="excludeMethods">Method2</param>
- </interceptor>
- <interceptor-stack name="myInterceptor">
- <interceptor-ref name="inter"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </interceptor-stack>
- </interceptors>
- <action name="loginaction" class="com.action.loginAction">
- <result name="success">success.jsp</result>
- <result name="error">error.jsp</result>
- <result name="cancel" type="redirectAction">Welcome</result>
- <interceptor-ref name="inter"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </action>
- </package>
- </struts>
(2)loginAction類,配置login.jsp中的action,分別在該類中添加Method1-Method3三個方法,其中Method1被攔截,Method2和Method3不被攔截,最後我們查看輸出結果。
- package com.action;
- import com.opensymphony.xwork2.ActionSupport;
- public class loginAction extends ActionSupport {
- @Override
- public String execute() throws Exception {
- if(this.username.equals("admin") && this.password.equals("admin")){
- return "success";
- }else if(this.username.equals("cancel") && this.password.equals("cancel")){
- return "cancel";
- }else{
- return "error";
- }
- }
- public void Method1(){
- System.out.println("執行方法:Method1");
- }
- public void Method2(){
- System.out.println("執行方法:Method2");
- }
- public void Method3(){
- System.out.println("執行方法:Method3");
- }
- private String username;
- private String password;
- public String getUsername(){
- return this.username;
- }
- public void setUsername(String username){
- this.username=username;
- }
- public String getPassword(){
- return this.password;
- }
- public void setPassword(String password){
- this.password=password;
- }
- }
- package com.interceptor;
- import java.util.Date;
- import java.util.Map;
- import com.action.loginAction;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
- public class inter extends MethodFilterInterceptor {
- @Override
- protected String doIntercept(ActionInvocation invocation) throws Exception {
- // TODO Auto-generated method stub
- System.out.println("攔截器在Action執行前攔截"+new Date());
- String result=invocation.invoke(); //執行Action方法
- System.out.println("攔截器在Action執行後攔截"+new Date());
- return result;
- }
- }
(4)login.jsp,在jsp頁面上添加三個按鈕,分別演示三個方法,判斷攔截器對方法的攔截情況。三個按鈕在點擊後回發的action是在javascript中動態的進行添加的,這樣做達到了一個form中執行不同的action的方法,當然還有其它的方法,將會在下篇文章中討論。
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- <script type="text/javascript">
- //方法1,定義被攔截的方法的實例
- function method1(){
- var form=document.forms[0];
- form.action="loginaction!Method1";
- form.submit();
- }
- //方法2,爲按鈕2添加不攔截的方法
- function method2(){
- var form=document.forms[0];
- form.action="loginaction!Method2";
- form.submit();
- }
- //方法3,爲按鈕3添加不攔截的方法
- function method3(){
- var form=document.forms[0];
- form.action="loginaction!Method3";
- form.submit();
- }
- </script>
- </head>
- <body>
- <form>
- 用戶名:<input type="text" name="username"><br>
- 密 碼:<input type="text" name="password"><br>
- <input type="submit" name="ok" value="按鈕1" onclick="method1()">
- <input type="submit" name="ok1" value="按鈕2" onclick="method2()">
- <input type="submit" name="ok2" value="按鈕3" onclick="method3()">
- </form>
- </body>
- </html>
運行完成後的頁面視圖:
(5)分析運行結果,分別單擊按鈕1、2、3,在控制檯中輸出結果,按鈕1是綁定的method1,該方法在struts.xml中進行了攔截如果結果正確的話會顯示被攔截的結果,而相應的按鈕2和3只輸出運行結果,因爲它們沒有被攔截。那看下面的結果圖: