原文地址:http://blog.csdn.net/zhutulang/article/details/38351629 尊重原創,請訪問原地址
一般,我們的web應用都是只有在用戶登錄之后才允許操作的,也就是說我們不允許非登錄認證的用戶直接訪問某些頁面或功能菜單項。我還記得很久以前我的做法:在某個jsp頁面中查看session中是否有值(當然,在用戶登錄邏輯中會將用戶名或者用戶對象存入session中),如果session中用戶信息為空,那么redirect 到登錄頁面。然后在除了登錄頁面外的其它所有需要驗證用戶已登錄的頁面引入這個jsp 。
比如,我們將檢查用戶是否登錄的代碼放入一個jsp頁面中,如 checkUser.jsp
- <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
- <%
- Object username = session.getAttribute("username");
- if(null == username){
- response.sendRedirect("login.jsp");
- }
- %>
登錄頁面為 login.jsp
- <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>登錄頁面</title>
- </head>
- <body>
- <h1>用戶登錄</h1>
- 用戶名:<input type="text" name="username" /><br />
- 密碼:<input type="text" name="pwd" />
- </body>
- </html>
假設登錄成功后跳轉到菜單頁面 menu.jsp
- <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <%@ include file="checkUser.jsp" %>
- <title>菜單頁</title>
- </head>
- <body>
- <h1>菜單1</h1> <br />
- <h1>菜單2</h1> <br />
- <h1>菜單3</h1> <br />
- <h1>菜單4</h1> <br />
- </body>
- </html>
在其中引入了 checkUser.jsp ,這樣當用戶沒有經過登錄而試圖訪問menu.jsp 頁面時就會被強制轉到 login.jsp 頁面。
以上這種方法當然是可行的,可是太過丑陋和麻煩。后來,我學到可以把除了登錄頁面外的 jsp 或html 頁面放到 WEB-INF 目錄下, 這樣用戶就無法直接在瀏覽器中敲url 來訪問頁面了。可是,如果有人通過某種方式得知我們的action 名和方法名了呢?難道我們要在action的每個方法中,檢查用戶是否登錄嗎?這樣子做光是想一想就覺得很蠢。好在我們有struts2 攔截器。
先來看看怎樣實現。
我們寫一個攔截器類,讓它繼承 MethodFilterInterceptor。
- /**
- * @Title: LoginInterceptoe.java
- * @Description: 攔截非登錄用戶請求
- * @author ThinkPad
- * @version 1.0
- * @date 2014年8月2日
- */
- package com.exam.interceptor;
- import com.exam.utils.Constants;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionInvocation;
- import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
- /**
- * @author ThinkPad
- *
- */
- public class LoginInterceptor extends MethodFilterInterceptor{
- /**
- *
- */
- private static final long serialVersionUID = -4409507846064552966L;
- /* (non-Javadoc)
- * @see com.opensymphony.xwork2.interceptor.MethodFilterInterceptor#doIntercept(com.opensymphony.xwork2.ActionInvocation)
- */
- @Override
- protected String doIntercept(ActionInvocation invoker) throws Exception {
- // TODO Auto-generated method stub
- Object loginUserName = ActionContext.getContext().getSession().get(Constants.USERNAME);
- if(null == loginUserName){
- return Constants.VIEW_LOGIN; // 這里返回用戶登錄頁面視圖
- }
- return invoker.invoke();
- }
- }
在struts.xml 文件中 填入:
- <interceptors>
- <interceptor name="loginInteceptor" class="com.exam.interceptor.LoginInterceptor" />
- <interceptor-stack name="loginStack">
- <interceptor-ref name="loginInteceptor">
- <param name="excludeMethods">goLogin,login</param>
- </interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref>
- </interceptor-stack>
- </interceptors>
- <default-interceptor-ref name="loginStack" />
其中,<param name="excludeMethods">goLogin,login</param> 配置的過濾方法,意思是攔截器對其中的方法不起作用。在我這里, goLogin 是跳轉到登錄頁面的方法。login 是驗證用戶名和密碼的方法,在其中會將通過驗證的用戶名放入session中。沒錯,這就是我們需要做的全部事情了,是不是很方便呢?
關於 struts2 攔截器的詳細介紹,可以參考這篇文章:http://wenku.baidu.com/link?url=GPQkMm2UkyFeRPMWH7RMTqJD1xVV2DWU90b5FwuNzDQjuAnx300jMePNb1IVgxMkM3dek3Irixm-kuTOmClbSQ8vdyEjRPwmAdXqZOlG_GK
我在這里稍微總結下:
1、在struts2 中,所有的攔截器都會繼承 Interceptor 這個接口。
2、攔截器寫好之后要在 struts.xml 文件中配置,如果該攔截器是用來攔截某個action的,那么,就在該action 的result 后面放入該攔截器。如(注:來自以上參考文章):
- <struts>
- <package name="struts2" extends="struts-default">
- <interceptors>
- <interceptor name="myinterceptor" class="com.interceptor.MyInterceptor">
- <param name="hello">world</param>
- </interceptor>
- </interceptors>
- <action name="register" class="com.test.action.RegisterAction" >
- <result name="input">/register.jsp</result>
- <result name="success">/success.jsp</result>
- <interceptor-ref name="myinterceptor"></interceptor-ref>
- </action>
- </package>
- <struts>
3、如果我們沒有添加攔截器,struts2 會為我們添加默認攔截器。而如果我們指定了攔截器,我們自己的攔截器就會取代默認的攔截器,那么我們就不能享受默認攔截器提供的一些功能。所以,一般我會把默認攔截器也加上。例如,在以上配置項中,action 里面再加上<interceptor-ref name="defaultStack"></interceptor-ref>
4、Interceptor 接口有三個方法:init 、 destroy、intercept 。但一般我們不關心 init 和 destroy 方法。所以struts2 為我們提供了一個簡化的攔截器類:AbstractInterceptor ,它實現了init 和 destroy 方法,我們只需實現 intercept 方法。
5、關於攔截器棧。可以把攔截器棧看成是一個“大”攔截器,里面由若干個攔截器組成。把它當成一個攔截器一樣的引用。
6、方法過濾攔截器,需要繼承 MethodFilterInterceptor 類(也就是我們這里示例使用的攔截器類的做法)。你可以指定該攔截器攔截哪些方法(使用<param name="includeMethods">method1,method2</param>
),也可以指定該攔截器不去攔截哪些方法(<param name="excludeMethods">method1,method2</param>)