JavaWeb三大組件
1. 都需要在web.xml中進行配置
Servlet
Listener
Filter
2. 過濾器
它通過web.xml管理着一大片資源,它會在一組資源(jsp、servlet、.css、.html等等)的前面執行!它當你想要訪問它管理的資源時,那麼它就會攔截進行處理.它可以讓請求得到目標資源,也可以不讓請求達到!就好比如門衛. 只要是對很多的資源進行操作就應該想到filter
過濾器如何編寫
1. 寫一個類實現Filter接口
2. 在web.xml中進行配置管理哪些資源
1. Filter接口
public void doFilter(ServletRequest request, ServletResponseresponse, FilterChain chain) throws IOException, ServletException{ System.out.println("filterstart..."); chain.doFilter(request,response);//放行 System.out.println("filterend..."); }
void init(FilterConfig)
* 創建之後,馬上執行;Filter會在服務器啓動時就創建!
void destory()
* 銷燬之前執行!在服務器關閉時銷燬
void doFilter(ServletRequest,ServletResponse,FilterChain)
* 每次過濾時都會執行
Filter是單例的!和servlet一樣
2. web.xml
<filter>
<filter-name>xxx</filter-name>
<filter-class>web.filter.AFitler</fitler-class>
</servlet>
<fitler-mapping>
<filter-name>xxx</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
這個配置代表了這個filter管理哪些資源.訪問這些資源時,這個過濾器就會執行doFilter()..
FilterConfig-->與ServletConfig相似
* 獲取初始化參數:getInitParameter()
* 獲取過濾器名稱:getFilterName()
* 獲取appliction:getServletContext()
FilterChain(這個用於放行)
* doFilter(ServletRequest, ServletResponse):放行!
就相當於調用了目標Servlet的service()方法!
-------------------------------
-------------------------------
多過濾器情況下FilterChain的doFilter()方法:執行目標資源,或是執行下一個過濾器!如果沒有下一個過濾器那麼執行的是目標資源,如果有,那麼就執行下一個過濾器!
-------------------------------
過濾器的四種攔截方式
<dispatcher>REQUEST</dispatcher>默認的!攔截直接請求
<dispatcher>FORWARD</dispatcher> 攔截請求轉發
<dispatcher>INCLUDE</dispatcher> 攔截請求包含
<dispatcher>ERROR</dispatcher> 攔截錯誤轉發
在<filter-mapping>中進行配置!
-------------------------------
多個過濾器的執行順序
<filter-mapping>的配置順序決定了過濾器的執行順序!
過濾器的應用場景:
執行目標資源之前做預處理工作,例如設置編碼,這種試通常都會放行,只是在目標資源執行之前做一些準備工作;
通過條件判斷是否放行,例如校驗當前用戶是否已經登錄,或者用戶IP是否已經被禁用;
在目標資源執行後,做一些後續的特殊處理工作,例如把目標資源輸出的數據進行處理
實例:
統計IP
循環遍歷在ServletContext中的map,其中key是ip地址,value是訪問次數
jsp頁面
<body> <h1>分IP統計訪問次數</h1> <table align="center"width="50%" border="1"> <tr> <th>IP地址</th> <th>次數</th> </tr> <c:forEach items="${aplicationScope.ipCountMap}" var="entry"> <tr> <td>${entry.key }</td> <td>${entry.value }</td> </tr> </c:forEach> </table> </body>
filter代碼
public void init(FilterConfig fConfig) throws ServletException { context = fConfig.getServletContext(); Map<String, Integer> ipCountMap = new LinkedHashMap<String, Integer>(); context.setAttribute("ipCountMap", ipCountMap); } public void doFilter(ServletRequest request, ServletResponseresponse, FilterChain chain) throws IOException, ServletException{ HttpServletRequest req = (HttpServletRequest) request; String ip = req.getRemoteAddr(); Map<String, Integer> ipCountMap = (Map<String,Integer>) context .getAttribute("ipCountMap"); Integer count = ipCountMap.get(ip); if (count == null) { count = 1; } else { count += 1; } ipCountMap.put(ip, count); context.setAttribute("ipCountMap", ipCountMap); chain.doFilter(request, response); } public void destroy() {} }
解決全站字符亂碼
亂碼問題:
l 獲取請求參數中的亂碼問題;
POST請求:request.setCharacterEncoding(“utf-8”);
GET請求:newString(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);
l 響應的亂碼問題:response.setContextType(“text/html;charset=utf-8”)。
處理POST請求簡單,可是處理get請求需要獲取參數,filter獲取所有過濾資源的參數是不可能實現的.這裏可以調包request再發給servlet.增強request對象(改變getParamater()方法.讓每次獲取參數時直接解決亂碼問題).
增強對象的方式有三種:(對a對象進行增強,fun1()方法)
繼承: AA類繼承a對象的類型:A類,然後重寫fun1()方法,其中重寫的fun1()方法就是被增強的方法。但是,繼承必須要知道a對象的真實類型,然後才能去繼承。如果我們不知道a對象的確切類型,而只知道a對象是IA接口的實現類對象,那麼就無法使用繼承來增強a對象了;
裝飾者模式: AA類去實現a對象相同的接口:IA接口,還需要給AA類傳遞a對象,AA類所有方法的實現都是調用a對象相同方法實現,只有fun1()方法需要改變下內容,對fun1()進行增強;
動態代理:和增強者模式比較相似
這裏對request對象進行增強是通過繼承request對象的裝飾類,裝飾類是接口的包裝類,但是它不進行任何增強,我們通過繼承它然後重寫需要增強的方法,這樣就不用重寫需要增強的方法了.
(增強時一看繼承類,二看有沒有接口的包裝類,三接口的裝飾者模式)
public class EncodingFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 處理post請求編碼問題 request.setCharacterEncoding("utf-8"); HttpServletRequest req = (HttpServletRequest) request; /* * 處理GET請求的編碼問題 */ // String username = request.getParameter("username"); // username = new String(username.getBytes("ISO-8859-1"), "UTF-8"); /* * 調包request */ if(req.getMethod().equals("GET")) { EncodingRequest er = new EncodingRequest(req); chain.doFilter(er, response); } else if(req.getMethod().equals("POST")) { chain.doFilter(request, response); } } public void init(FilterConfig fConfig) throws ServletException { } }
繼承包裝類增強request
/** * 裝飾reqeust */ public class EncodingRequest extends HttpServletRequestWrapper { private HttpServletRequest req; public EncodingRequest(HttpServletRequest request) { super(request); this.req = request; } public String getParameter(String name) { String value = req.getParameter(name); // 處理編碼問題 try { value = new String(value.getBytes("iso-8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } return value; } }