過濾器的相關概念
Filter是什麼
Filter 是java下的一種過濾器 ,能實現對java web程序 客戶端和服務器端消息的過濾,也就是在服務器段接受request之前,可以預先對request進行處理,或在客戶端接受response之前,對response進行處理。開發人員能夠通過這種技術,對一些資源進行管控,能夠對網頁請求,文件等進行攔截,是一種保證系統安全的技術。
運行機制
服務器在接收到來自瀏覽器的請求之後,在servlet處理請求之前,要先經過層層Filter的過濾。這樣能夠保證它request到達servlet之前預處理request等。
生命週期
在web項目中,Filter是一個接口,我們所實現這個接口之後,會有三個需要重寫的方法。
(1)init(FilterConfig filterConfig) throws ServletException
Web 容器調用 init(FilterConfig) 來初始化過濾器。容器在調用該方法時,向過濾器傳遞 FilterConfig 對象,利用 FilterConfig 對象可以得到 ServletContext 對象,以及在 web.xml 中配置的過濾器的初始化參數。在這個方法中,可以拋出 ServletException 異常,通知容器該過濾器不能正常工作。此時的 Web 容器啓動失敗,整個應用程序不能夠被訪問。 實例化和初始化的操作只會在容器啓動時執行,而且只會執行一次。
(2)doFilter(ServletRequest,ServletResponse,FilterChain)
doFilter 方法類似於 Servlet 接口的 service 方法。當客戶端請求目標資源的時候,容器會篩選出符合 filter-mapping
中的 url-pattern
的 filter,並按照聲明 filter-mapping
的順序依次調用這些 filter 的 doFilter 方法。在這個鏈式調用過程中,可以調用 chain.doFilter(ServletRequest, ServletResponse)
將請求傳給下一個過濾器(或目標資源),也可以直接向客戶端返回響應信息,或者利用 RequestDispatcher 的 forward 和 include 方法,以及 HttpServletResponse 的 sendRedirect 方法將請求轉向到其它資源。需要注意的是,這個方法的請求和響應參數的類型是 ServletRequest 和 ServletResponse,也就是說,過濾器的使用並不依賴於具體的協議。
(3)destroy()
destroy 方法指示過濾器的生命週期結束。在這個方法中,可以釋放過濾器使用的資源。
過濾實現
長時間打開一個網頁不進行操作會出現登錄失效的情況,此時要是沒有攔截功能,那麼會出現在未登錄的情況下還能進行操作。
我們先創建登錄成功後要訪問的Servlet,也就是login.jsp中給出認證之後要訪問的頁面。
success: function(msg){
if("vcodeError" == msg){
....
} else if("loginError" == msg){
....
} else if("admin" == msg){
window.location.href = "SystemServlet?method=toAdminView";
} else if("student" == msg){
window.location.href = "SystemServlet?method=toStudentView";
} else if("teacher" == msg){
window.location.href = "SystemServlet?method=toTeacherView";
}
}
瀏覽器就可以根據這個消息跳轉到管理員登錄成功之後應該去的頁面。
public class SystemServlet extends HttpServlet {
private static final long serialVersionUID = -7258264317769166483L;
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException{
doPost(req,res);
}
public void doPost(HttpServletRequest req,HttpServletResponse res) throws IOException{
res.getWriter().write("hello");
}
}
從上面的代碼中可以看出來,登錄成功後會跳轉到SystemServlet。
同樣,我們仍然要在web.xml進行配置,建立SystemServlet到訪問路徑的映射。
<servlet>
<description>登錄後的主界面顯示</description>
<servlet-name>SystemServlet</servlet-name>
<servlet-class>com.ischoolbar.programmer.servlet.SystemServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SystemServlet</servlet-name>
<url-pattern>/SystemServlet</url-pattern>
</servlet-mapping>
這樣配置之後,我們登錄成功之後,瀏覽器會給我們響應,並且打印出“hello”於瀏覽器頁面中。
完成了Servlet和xml,接下來就可以創建對登錄的攔截功能了。我們的需求是,用戶在登錄失效的情況下,重新定向到登錄頁面,登錄之後再繼續對系統進行操作。
我們新建一個package,取名爲filter,再在此包下創建一個名爲LoginFilter的java文件。
public class LoginFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
Object user = request.getSession().getAttribute("user");
if(user == null){
//未登錄
response.sendRedirect("index.jsp");
return;
}else{
chain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
上面的程序中,顯示對ServletRequest和ServletRequest進行強轉。
在這裏我的理解是:ServletRequest和HttpServletRequest ,ServletRequest和HttpServletResponse 都是接口。而後者又是前者的子接口,子接口中實現的方法是父接口所沒有的,我們想要從Session中獲取信息,父接口沒有其實現的方法,只能向下轉型使用子接口實現的方法。
另外,如果沒有將用戶信息從Session中拿出來,這說明用戶是未登錄的狀態,就重新定向到了登錄頁面。
我們來驗證一下:
從結果來看,過濾器已經發揮了作用。