能夠爲一個Web應用組件部署多個過濾器,這些過濾器組成一個過濾器鏈,每一個過濾器只執行某個特定的操做或者檢查。這樣請求在到達被訪問的目標以前,須要通過這個過濾器鏈。html
在Web應用中使用過濾器須要實現javax.servlet.Filter接口,實現Filter接口中所定義的方法,並在web.xml中部署過濾器。java
public class MyFilter implements Filter { public void init(FilterConfig fc) { //過濾器初始化代碼 } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { //在這裏能夠對客戶端請求進行檢查 //沿過濾器鏈將請求傳遞到下一個過濾器。 chain.doFilter(request, response); //在這裏能夠對響應進行處理 } public void destroy( ) { //過濾器被銷燬時執行的代碼 } }
方法名稱web |
功能描述安全 |
public void init(FilterConfig config)session |
容器在實例化過濾器調用。FilterConfig對象包含Filter相關的配置信息。app |
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)框架 |
每當請求和響應通過過濾器鏈時,容器都調用一次該方法。過濾器的一個實例能夠同時服務於多個請求,須要注意線程同步問題,儘可能不用或少用實例變量。 在過濾器的doFilter()方法實現中,任何出如今FilterChain的doFilter方法以前地方,request是可用的;在doFilter()方法以後response是可用的。webapp |
public void destroy()ide |
容器調用destroy()方法指出將從服務中刪除該過濾器。若是過濾器使用了其餘資源,須要在這個方法中釋放這些資源。post |
在Web應用的WEB-INF目錄下,找到web.xml文件,在其中添加以下代碼來聲明Filter。
<filter> <filter-name>MyFilter</filter-name> <filter-class> com.etc.web.MyFilter </filter-class> <init-param> <param-name>codeFilter</param-name> <param-value>UTF-8</param-value> </init-param> </filter> //針對一個Servlet作過濾 <filter-mapping> <filter-name>MyFilter</filter-name> <servlet-name>MyServlet</servlet-name> </filter-mapping> //針對URL Pattern作過濾 <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter-mapping>標記是有前後順序的,它的聲明順序說明容器是如何造成過濾器鏈的。過濾器應當設計爲在部署時很容易配置的形式。經過使用初始化參數,能夠獲得複用性很高的過濾器。
過濾器邏輯與Servlet邏輯不一樣,它不依賴於任何用戶狀態信息,由於一個過濾器實例可能同時處理多個徹底不一樣的請求。
在web.xml中配置過濾器信息
<web-app> <filter> <filter-name>EncodeFilter</filter-name> <filter-class>com.etc.news.web.EncodeFilter</filter-class> <init-param> <param-name>encode</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>EncodeFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
註解方式部署過濾器
<!-- @WebFilter(urlPatterns = {"/*"},filterName="EncodeFilter" ,initParams = {@WebInitParam(name = "encode", value = "utf-8")}) -->
編寫自定義類EncodeFilter
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; public class EncodeFilter implements Filter { private String encode = null; public void destroy() { encode = null; } public void init(FilterConfig filterConfig) throws ServletException { String encode = filterConfig.getInitParameter("encode"); if (this.encode == null) { this.encode = encode; } } // 對全部頁面設置字符集 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (null == request.getCharacterEncoding()) { request.setCharacterEncoding(encode); } chain.doFilter(request, response); response.setContentType("text/html;charset="+encode); response.setCharacterEncoding(encode); } }
import java.io.UnsupportedEncodingException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; /** * 對Get方式傳遞的請求參數進行編碼 */ public class CharacterEncodingRequest extends HttpServletRequestWrapper { private HttpServletRequest request = null; public CharacterEncodingRequest(HttpServletRequest request) { super(request); this.request = request; } /** * 對參數從新編碼 */ @Override public String getParameter(String name) { String value = super.getParameter(name); if (value == null) return null; String method = request.getMethod(); if ("get".equalsIgnoreCase(method)) { try { value = new String(value.getBytes("ISO8859-1"), request.getCharacterEncoding()); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return value; } }
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; public class CharacterEncodingFilter implements Filter { private String encode = "UTF-8";// 默認UTF-8編碼 public void init(FilterConfig filterConfig) throws ServletException { String encoding = filterConfig.getInitParameter("encode"); if (encoding != null) { this.encode = encoding; } } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 設置request編碼 request.setCharacterEncoding(encode); chain.doFilter(new CharacterEncodingRequest(request), response); // 設置響應信息編碼 response.setContentType("text/html;charset=" + encode); response.setCharacterEncoding(encode); } public void destroy() { } }
package com.etc.filter; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; /** http 請求包裝器 */ public class HttpRequestWrapper extends HttpServletRequestWrapper { private Map<String, String> map = null;// 須要替換內容的集合key敏感字 value替換內容 public HttpRequestWrapper(HttpServletRequest request) { super(request); } /** * 敏感字替換 * * @param rs請求字符串 * @return 替換敏感字後的字符串 */ public String replace(String rs) { StringBuffer rssb = new StringBuffer(rs);// StringBuffer修改字符串不產生副本,非線程安全,速度快 Set<String> keys = this.getMap().keySet();// map的key爲敏感字集合 Iterator<String> it = keys.iterator();// 敏感字迭代器 //String ss = null;// 存儲key變量 while (it.hasNext()) { String key = it.next(); int index = rssb.indexOf(key);// 查找字符串中是否存在須要替換的內容 if (index != -1 && key != null) {// 找到敏感字而且敏感字集合該敏感字不爲空,執行替換 //ss = key; rssb.replace(index, index + key.length(), this.getMap().get(key));// 替換敏感字 } } // if (ss != null) { // if (rssb.toString().indexOf(ss) == -1) {// 確保已經替換完畢 // return rssb.toString(); // } else {// 再次進行替換 // return replace(rssb.toString()); // } // } return rssb.toString(); } //Servlet中實際調用的getParameter方法: 重寫的getParameter()方法 public String getParameter(String str) { String content = super.getParameter(str); return replace(content);// 返回被替換文本 // if (str.equals("pager.offset")) {// JSP視圖使用pager-taglib分頁框架的分頁信息。忽略處理 // return super.getParameter(str); // } else {// 敏感字替換 // String content = super.getParameter(str); // return replace(content);// 返回被替換文本 // } } public Map<String, String> getMap() { return map; } public void setMap(Map<String, String> map) { this.map = map; } }
package com.etc.filter; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; import javax.servlet.http.HttpServletRequest; /** 內容過濾器 */ @WebFilter(filterName = "ContentFilter", urlPatterns = "*.action", initParams = { @WebInitParam(name = "filePath", value = "/WEB-INF/words") }) public class ContentFilter implements Filter { private Map<String, String> map = new HashMap<String, String>(); // 過濾器的初始化:讀取敏感字文件 public void init(FilterConfig config) throws ServletException { String filePath = config.getInitParameter("filePath");// 從配置文件中取得文件的相對路徑/WEB-INF/words ServletContext context = config.getServletContext();// 讀取上下文環境 String realPath = context.getRealPath(filePath);// 絕對路徑D:\Tomcat7\webapps\guestbook\WEB-INF\words FileReader fr = null;//節點流 BufferedReader br = null;//處理流 // 根據相對路徑取得絕對路徑 try { fr = new FileReader(realPath);// 根據絕對路徑,經過文件流來讀取文件 br = new BufferedReader(fr); String line = null; while ((line = br.readLine()) != null) { String[] str = line.split("==");// 按照==拆分字符串 map.put(str[0], str[1]); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) { br.close(); } if (fr != null) { fr.close(); } } catch (IOException e) { e.printStackTrace(); } } } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 處理請求中的數據:使用HttpRequestWrapper包裝類替換HttpRequest HttpRequestWrapper hrw = new HttpRequestWrapper((HttpServletRequest) request); hrw.setMap(map); chain.doFilter(hrw, response);// 過濾鏈 } @Override public void destroy() { this.map = null; } }
Web容器管理Servlet/JSP相關的生命週期。
Servlet事件是指HttpServletRequest對象、HttpSession對象、ServletContext對象生成、銷燬或相關屬性進行了設置等等事件。
監聽器由web容器管理,它的做用是監聽Servlet有效事件,並根據需求作出適當響應。下表爲Servlet和JSP中的8個Listener和6個Event類。
Listener接口 |
監聽Event類 |
ServletContextListener |
ServletContextEvent |
ServletContextAttributeListener |
ServletContextAttributevent |
HttpSessionListener |
HttpSessionEvent |
HttpSessionActivationListener |
|
HttpSessionAttributeListener |
HttpSessionBindingEvent |
HttpSessionBindingListener |
|
ServletRequestListener |
ServletRequestEvent |
ServletRequestAttributeListener |
ServletRequestAttributeEvent |
Servlet監聽器的功能和Java的GUI的監聽器相似,能夠監聽Servlet容器因爲Web應用程序中狀態改變而產生的相應事件,而後接受和處理這些事件。
用於監聽ServletContext對象的建立、刪除和添加屬性,以及刪除和修改操做,主要用到如下接口:
1.ServletContextListener接口
該接口主要用來監聽SerrvletContext的建立和刪除,他提供瞭如下兩個方法,也稱爲「web應用程序的生命週期方法」:
2.ServletContextAttributeListener接口
用來監聽ServletContext屬性的增長、刪除及修改,它提供了一下三個方法:
提供了4個接口監聽HTTP會話(HTTPSEession)信息。
1.HttpSessionListener接口
該接口監聽HTTP會話的建立及撤銷,它提供了兩個方法:
2.HttpSessionActivationListener接口
該接口實現監聽HTTP會話active和passivate狀況,它提供了以下2個方法。
3.HttpSessionAttributeListener接口
該接口實現監聽HTTP會話中屬性的設置請求,它提供了3個方法:
4.HttpSessionBindingListener接口
該接口實現監聽HTTP會話中對象的綁定信息,它是惟一不須要在web.xml中設置Listener的,它提供了兩個方法:
用來監聽客戶端的請求,一旦在監聽程序中獲取了客戶端的請求,就能夠統一處理請求,它提供了兩個接口。
1.ServletRequestListener接口
2.ServletRequestAttributeListener接口
1.UserContainer類
package com.etc.listener; import java.util.LinkedList; import java.util.List; /** 在線用戶操做類 ————單例模式 */ public class UserContainer { private static UserContainer userContainer = new UserContainer(); private List<String> list = null;//保存用戶帳號 private UserContainer() { this.list = new LinkedList<String>(); } /** 在線用戶操做類單例模式 :全部的用戶都保存在一個UserInfoList對象中 */ public static UserContainer getInstance() { return userContainer; } /** 添加用戶 */ public boolean addUser(String user) { if (user != null) { this.list.add(user); return true; } else { return false; } } /** 刪除用戶 */ public void removeUser(String user) { if (user != null) { for (int i = 0; i < list.size(); i++) { if (user.equals(list.get(i))) { list.remove(i); } } } } /** 獲取用戶列表 */ public List<String> getList() { return this.list; } }
2.監聽在線用戶類
package com.etc.listener; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; /** 監聽在線用戶類 */ @WebListener public class UserListener implements HttpSessionBindingListener { private String user;// 用戶字符串 private UserContainer userContainer = UserContainer.getInstance();// 用戶信息處理實例 public UserListener() { this.user = null; } /** 設置在線監聽人員 */ public void setUser(String user) { this.user = user; } /** 獲取在線人員 */ public String getUser() { return this.user; } /** 當有對象加入session範圍時,自動調用 */ @Override public void valueBound(HttpSessionBindingEvent arg0) { System.out.println(this.user + "上線 "); this.userContainer.addUser(this.user); } /** 當有對象從session範圍內移除時,會被自動調用 */ @Override public void valueUnbound(HttpSessionBindingEvent arg0) { System.out.println(this.user + "下線 "); this.userContainer.removeUser(this.user); } }
3.Servlet處理類
package com.etc.action; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.etc.listener.UserContainer; import com.etc.listener.UserListener; @WebServlet("/ServletLogin.action") public class ServletLogin extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); UserContainer userContainer = UserContainer.getInstance(); UserListener userListener = new UserListener(); String user = request.getParameter("name").trim();// 獲取用戶名 if (user.length() == 0) { user = "默認用戶"; } userListener.setUser(user);// 設定監聽用戶 session.setAttribute("userListener", userListener); userContainer.addUser(userListener.getUser());// 用戶信息添加到用戶信息處理類 session.setMaxInactiveInterval(30); System.out.println(userContainer.getList().size()); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
4.登錄處理代碼
<% UserInfoList list = UserInfoList.getInstance(); UserInfoTrace trace = new UserInfoTrace(); request.setCharacterEncoding("utf-8"); String user = request.getParameter("name").trim();//獲取用戶名 if (user.length() == 0) { user = "默認用戶"; } trace.setUser(user);//設定監聽用戶 session.setAttribute("trace", trace); list.addUser(trace.getUser());//用戶信息添加到用戶信息處理類 session.setMaxInactiveInterval(30); %> <h3>當前登陸用戶</h3> <ul> <% Vector<String> vector = list.getList(); for (int i = 0; i < vector.size(); i++) { out.print("<li>" + vector.elementAt(i) + "</li>"); } %> </ul>
5.登錄視圖代碼
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>登錄視圖</title> </head> <body> <form action="ServletLogin.action" method="post"> <p> 用戶名:<input type="text" name="name"> </p> <p> <input type="submit" value="登錄"> </p> </form> </body> </html>