一.過濾器概述
------------------------------------------------
1.1.什麼是過濾器?
Servlet技術規範中, 定義了Servlet、Filter、Listener三門技術, 其中Filter也叫作過濾器,經過過濾器技術,開發人員能夠實現用戶在訪問某個資源以前或以後,對訪問的請求和響應進行攔截,從而作一些相關的處理。
過濾器:
◇ 所謂的過濾器, 就是攔截用戶對資源的訪問
◇ 一個過濾器能夠攔截多個資源, 一個資源也能夠配置多個過濾器進行攔截
◇ 其實所謂的攔截, 就是將表明請求的request對象和表明響應的response對象攔截下來, 攔截下來後:
◇ 控制是否容許訪問 -- 用戶登錄以後才能查看本身的訂單頁面
◇ 在訪問資源以前或以後作一些處理 好比: 全站亂碼解決
...
===================================================
二.開發過濾器
------------------------------------------------
2.1.開發過濾器的步驟
Servlet API中提供了一個Filter接口, 開發web應用時, 若是編寫一個類實現了這個接口, 則這個類就是一個過濾器
(1) 寫一個類實現Filter接口, 並實現其中的方法
(2) 在web應用的web.xml中配置過濾器
------------------------------------------------
~~2.2.Filter生命週期:
當服務器啓動時, web應用加載後會當即建立出當前web應用中的全部的Filter對象, 建立出來後, 當即調用init方法進行初始化出操做. 今後之後這個Filter對象一直駐留在內存中爲後續所攔截的請求服務, 每次過濾到對資源的訪問時, 都會執行doFilter這個方法進行攔截處理, 直到服務器關閉或者web應用移出容器爲止, 隨着web應用的銷燬, 過濾器也跟着銷燬, 在銷燬以前會調用destroy方法執行善後的處理.
------------------------------------------------
2.3.配置過濾器
<filter> -- 配置一個過濾器
<filter-name>FilterDemo1</filter-name>
-- 過濾器的名字
<filter-class>cn.tedu.FilterDemo1</filter-class> -- 過濾器處理類的全路徑名
</filter>
<filter-mapping> -- 爲指定的過濾器配置要攔截的路徑, 一個過濾器能夠配置多個<filter-mapping>
<filter-name>FilterDemo1</filter-name> -- 過濾器的名字
<servlet-name>ServletDemo1</servlet-name> -- 攔截哪一個名字的Servlet, 能夠配置多個
<url-pattern>/servlet/*</url-pattern> -- 要攔截的路徑, 路徑的寫法和Servlet的<url-pattern>寫法一致, 能夠配置多個
<dispatcher>REQUEST</dispatcher> -- 配置攔截哪一種方式的對資源的訪問, 能夠取值爲REQUEST/FORWARD/INCLUDE/ERROR
REQUEST:默認,普通請求,最經常使用
FORWARD:所攔截的資源是經過請求轉發訪問的
INCLUDE:所攔截的資源是經過頁面包含訪問的
ERROR:所攔截的資源經過異常機制訪問的
</filter-mapping>
------------------------------------------------
2.4.Filter中的方法介紹
--------------------------------------------
init(FilterConfig filterConfig)
FilterConfig -- 表明當前Filter在web.xml中配置信息的對象
經過這一對象能夠獲取當前過濾器在web.xml配置的初始化參數
經過這一對象能夠獲取表明當前web應用的ServletContext對象
獲取初始化參數:
getInitParameter(String name);
getInitParameterNames()
獲取ServletContext對象
getServletContext();
--------------------------------------------
doFilter(request, response, FilterChian filterChian)
FilterChian -- 過濾器鏈
一個web資源能夠被多個過濾器所攔截, 多個過濾器攔截的順序是按照Filter在web.xml中配置的<filter-mapping>的順序執行的.這多個過濾器按照攔截的順序就組成了一個攔截器鏈, 用FilterChian表示.
若是一個過濾器處理完所攔截的請求後, 想要執行後面的攔截器, 則能夠調用FilterChian上doFilter方法, 表示放行過濾器, 接着執行下一個節點
若是下一個節點仍然是過濾器, 則接着進行過濾, 執行的過程同上
若是沒有後續的過濾器, 則執行真正的資源處理此次請求
--------------------------------------------
destroy()
略
===================================================
三.過濾器的應用
------------------------------------------------
3.1.全站亂碼解決過濾器
(1).建立EncodingFilter過濾器類, 實現過濾器接口(Filter)
詳細代碼參考: EncodingFilter.java
(2).在web.xml中配置過濾器
<!-- 配置全站亂碼解決過濾器 -->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.tedu.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
------------------------------------------------
3.2.自動登錄過濾器實現
(1).建立AutoLoginFilter過濾器類, 實現過濾器接口(Filter)
詳細代碼參考: AutoLoginFilter.java
(2).在web.xml中配置過濾器
<!-- 配置自動登錄過濾器 -->
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>cn.tedu.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(3).在LoginServlet中, 實現30天自動登錄, 將用戶名和密碼保存進Cookie
if("true".equals(request.getParameter("autologin"))){
//實現30天自動登錄
Cookie cookie = new Cookie("autologin", username+":"+password);
cookie.setPath(request.getContextPath()+"/");
cookie.setMaxAge(3600*24*30);
response.addCookie(cookie);
}
===================================================
四.//案例--裝飾者模式在亂碼處理中的應用
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("全站亂碼解決過濾器初始化成功...");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//1.解決響應正文亂碼
response.setContentType("text/html;charset=utf-8");
//2.解決請求參數亂碼 -- (利用裝飾設計模式對request對象進行包裝)
HttpServletRequest myReq = new MyHttpServletRequest((HttpServletRequest)request);
//3.放行過濾器
chain.doFilter(myReq, response);
}
public void destroy() {
}
}
class MyHttpServletRequest extends HttpServletRequestWrapper{
//將request對象保存在類的內部
private HttpServletRequest request;
//定義flag, 控制getParameterMap()方法中map的遍歷次數
private boolean flag = true;
public MyHttpServletRequest(HttpServletRequest request) {
super(request);//這行代碼千萬不要省寫!!!
this.request = request;
}
public String getParameter(String name) {
return getParameterValues(name) == null ? null : getParameterValues(name)[0];
}
public String[] getParameterValues(String name) {
return (String[]) getParameterMap().get(name);
}
public Map getParameterMap() {
try {
String method = request.getMethod();
if("POST".equals(method)){//--POST提交
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
}else if("GET".equals(method)){
//手動編解碼解決亂碼問題!
Map<String, String[]> map = request.getParameterMap();
if(flag){
for(Map.Entry<String, String[]> entry : map.entrySet()){
String[] vs = entry.getValue();
for(int i=0; i<vs.length; i++){
vs[i] = new String(vs[i].getBytes("iso8859-1"), "utf-8");
}
}
flag = false;
}
return map;
}else{
return request.getParameterMap();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}html
=================================================java
五.裝飾類詳解web
ServletRequest(接口)設計模式
|-- HttpServletRequest(接口)服務器
|-- 匿名實現類(xxx) 實例: request對象cookie
request對象 --> 被裝飾者app
ServletRequestWrapper--> 裝飾類this
1.ServletRequestWrapper裝飾類 和 被裝飾者(request對象)所屬的類(xxx)實現了同一個接口(ServletRequest)url
2.提供了構造方法容許將被裝飾者傳入並保存在了類的內部spa
3.對於不想改造的方法直接調用已有對象上的方法, 對於想要改造的方法直接進行改造(沒有對任何方法進行改造), 如:
request對象 --> 被裝飾者
HttpServletRequestWrapper -- 裝飾類
HttpServletRequestWrapper類繼承了ServletRequestWrapper裝飾類類, 因此HttpServletRequestWrapper也是一個裝飾類!!
HttpServletRequestWrapper類沒有直接去包裝request對象, 而是先將當前構造方法中的request對象傳給父類(ServletRequestWrapper), 讓父類進行包裝, 再繼承父類中包裝後的方法。
而對於自身獨有的方法, 本身再進行包裝: 經過父類提供的方法(super.getRequest()) 獲取 包裝後的request對象, 並強制轉型爲 HttpServletRequest, 並經過提供 _getHttpServletRequest 方法, 方便在當前類的內部使用, 代碼以下:
對於HttpServletRequestWrapper類中全部的方法, 直接調 super.getRequest() 對象 -- 即被父類包裝後的request對象上的方法
也就是說, 對於HttpServletRequestWrapper裝飾類, 是向將本身構造方法中的request對象傳給父類(方便父類進行包裝), 再經過super.getRequest(); 獲取父類中包裝的request對象(目的是保證本身和父類包裝的是同一個request)
接下來對內部的方法進行包裝, 即HttpServletRequestWrapper類中的方法分爲兩類: 第一類是經過父類繼承過來的(父類對於這行方法已經進行包裝), 第二類是本身獨有的方法, 在自身類的內部進行包裝!!