基於SSH實現員工管理系統登入許可權的過濾器與攔截器的綜合使用
需要實現的功能:判斷使用者是否已登入,未登入使用者禁止訪問任何頁面或action,自動跳轉到登入頁面。
過程很艱辛,雖然是挺簡單的應用,但是自己也弄了好久才有些許弄明白,結合網上搜索到的內容寫下這篇總結,待日後可回頭檢視。
剛開始是先搜了攔截器如何攔截未登入使用者的操作的,正是初生牛犢不怕虎,找到一篇文章就死懟,懟到後面發現不大對,雖然action是攔截掉了,但是jsp怎麼樣都攔截不到,直接輸入.jsp的url還是能訪問到網頁。苦思冥想,想不出如何做才行。後面發現攔截器本就不能攔截jsp頁面、圖片等其他資源,攔截器由spring管理,只對action起作用。
於是搜尋過濾器的內容,發現過濾器則能過濾所有內容,過濾器的範圍要大於攔截器。那就把兩者結合起來用吧,反正攔截器已寫好,只需寫過濾jsp頁面的過濾器即可。
過濾器filter實現:
配置web.xml
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>xu.ssh.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter -mapping>
程式碼:
package xu.ssh.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import xu.ssh.domain.Employee;
public class LoginFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 獲得在下面程式碼中要用的request,response,session物件
HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse) response;
HttpSession session = servletRequest.getSession();
// 獲得使用者請求的URI
String path = servletRequest.getRequestURI();
// System.out.println(path);
// 從session裡取員工工號資訊
Employee employee = (Employee) session.getAttribute("existEmployee");
/*
* 建立類Constants.java,裡面寫的是無需過濾的頁面 for (int i = 0; i <
* Constants.NoFilter_Pages.length; i++) { if
* (path.indexOf(Constants.NoFilter_Pages[i]) > -1) {
* chain.doFilter(servletRequest, servletResponse); return; } }
*/
// 登陸頁面無需過濾
if (path.indexOf("/login.jsp") > -1) {
chain.doFilter(servletRequest, servletResponse);
return;
}
// 判斷如果沒有取到員工資訊,就跳轉到登陸頁面
if ("".equals(employee) || employee == null) {
// 跳轉到登陸頁面
servletResponse.sendRedirect("/ssh_employee/login.jsp");
} else {
// 已經登陸,繼續此次請求
chain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
配置中的filter-mapping,定義的是需過濾的請求型別,上面的配置即過濾所有對jsp頁面的請求。過濾器的實現與struts2、spring框架無關,在使用者請求被相應前執行,在過濾器中,可使用response.sendRedirect(“”)等方法
跳轉到需要的連結,如登入頁面、錯誤頁面等,不需要跳轉時,chain.doFilter(request, response);即可繼續執行使用者的請求。注意使用filter時避免連續兩次跳轉,否則會報java.lang.IllegalStateException錯誤,除非必要,不建議使用/*(過濾所有訪問)的配置方式,這樣配置,圖片、js檔案、css檔案等訪問都會被過濾
攔截器interceptor實現:
配置:struts.xml
<!-- 攔截器 -->
<interceptors>
<interceptor name="myInterceptor" class="xu.ssh.action.MyInterceptor"></interceptor>
<interceptor-stack name="myInterceptor">
<interceptor-ref name="myInterceptor">
<param name="excludeMethods">login</param><!-- 不攔截的方法-->
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 將上述攔截器設定為預設攔截器 ,這樣在後續同一個package內部的所有Action執行之前都會被login攔截。-->
<default-interceptor-ref name="myInterceptor" />
程式碼:
package xu.ssh.action;
import org.apache.struts2.ServletActionContext;
import xu.ssh.domain.Employee;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class MyInterceptor extends MethodFilterInterceptor{
/**
* @param args
*/
@Override
protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
Employee employee = (Employee) ServletActionContext.getRequest().getSession().getAttribute("existEmployee");
if(employee!=null){
// is logined ,have the userinfo in the session
return actionInvocation.invoke();//遞迴呼叫攔截器
}else{
//is not logged
ActionSupport support = (ActionSupport) actionInvocation.getAction();
support.addActionError("請先登入:)");
return "loginfail";//返回到登入頁面
}
}
}
攔截器截獲使用者對action的訪問,如需要跳轉,只需如action一樣返回一個result,spring根據result的配置執行跳轉。如無需跳轉,可呼叫invocation.invoke();方法來執行使用者請求的action。攔截器在action之前開始,在action完成後結束(如被攔截,action根本不執行)