1. 程式人生 > >Javaweb:Servlet過濾器以及常見應用展示

Javaweb:Servlet過濾器以及常見應用展示

Filter簡介:

Filter也稱之為過濾器,它是Servlet技術中最實用的技術,WEB開發人員通過Filter技術,對web伺服器管理的所有web資源:例如Jsp, Servlet, 靜態圖片檔案或靜態 html 檔案等進行攔截,從而實現一些特殊的功能。

l特點:

過濾器不是目標資源,是在訪問目標資源的前後執行的。

過濾器的攔截是雙向的

可以有多個過濾器。

過濾器攔截是一堆目標資源。

Servlet API中提供了一個Filter介面,開發web應用時,如果編寫的Java類實現了這個介面,則把這個java類稱之為過濾器Filter。通過Filter

技術,開發人員可以實現使用者在訪問某個目標資源之前,對訪問的請求和響應進行攔截,如下所示:

過濾器的工作原理

通過使用過濾器,可以攔截客戶端的請求和響應,檢視、提取或者以某種方式操作正在客戶端和伺服器之間進行交換的資料。

通過使用過濾器,可以對Web元件的前期處理和後期處理進行控制。

過濾器可以有多個,以構成一個過濾器鏈。Servlet容器會根據過濾器的配置情況來決定過濾器的呼叫次序。

過濾器Filter的實現和部署

(1)實現一個過濾器Filter

定義的過濾器類必須要實現介面javax.servlet.Filter,並且實現該介面中定義的3個方法:

vod

init(…):用於初始化過濾器。

void destroy():用於銷燬過濾器。

void doFilter(…):用於執行過濾操作。

(2)部署一個過濾器Filter

web.xml配置檔案中部署Filter

<filter>元素定義過濾器,在 web.xml 檔案中使用<filter><filter-mapping>元素對編寫的filter類進行註冊,並設定它所能攔截的資源,<filter>元素有兩個必要子元素:

<filter-name>用來設定過濾器的名字

<filter-class >

用來設定過濾器的類路徑

<filter>
 	<filter-name>TestFilter</filter-name>
 	<filter-class>filter.TestFilter</filter-class>
 </filter>

<filter-mapping>配置過濾器的對映資訊,有兩個必要的子元素:

<filter-name>用來設定過濾器的名字

<url-pattern>用來設定被過濾的元件

<filter-mapping>
 	<filter-name>TestFilter</filter-name>
 	<url-pattern>/*.jsp</url-pattern>
 </filter-mapping>

例項:

過濾器類:

package cn.itcast.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;

/**
 * 實現Filter介面,重寫方法
 * 在web.xml進行配置
 * @author Administrator
 */
public class FilterDemo1 implements Filter{
	
	/**
	 * 初始化
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}

	/**
	 * 每次請攔截的方式都執行(通過配置來決定)
	 * 由伺服器呼叫doFilter() -- 進去到過濾器
	 * FilterChain伺服器建立,把傳入進來(過濾器的資訊 )
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("站住,打劫!!");
		
		
		// 放行
		// 放行 -- 執行下一個過濾器 -- 沒有訪問目標資源
		chain.doFilter(request, response);
		
		// 去訪問Servlet
		
		// System.out.println("小夥,再來一次吧!!");
		
	}
	
	/**
	 * 銷燬
	 */
	public void destroy() {
		
	}

}

web.xml配置:


	<!-- 配置過濾器   -->
	<!-- 配置過濾器的資訊 -->
	<filter>
		<!-- 配置名字 -->
		<filter-name>FilterDemo1</filter-name>
		<!-- 包名+類名 -->
		<filter-class>cn.itcast.filter.FilterDemo1</filter-class>
	</filter>
	<!-- 配置過濾器的對映 -->
		<!-- 配置訪問方式 -->
	<!-- 
	<filter-mapping>
		<filter-name>FilterDemo1</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

Filter--- FilterChain

在一個web應用中,可以開發編寫多個Filter,這些Filter組合起來稱之為一個Filter鏈。

web伺服器根據Filterweb.xml檔案中的註冊順序<mapping>,決定先呼叫哪個Filter,當第一個FilterdoFilter方法被呼叫時,web伺服器會建立一個代表Filter鏈的FilterChain物件傳遞給該方法。在doFilter方法中,開發人員如果呼叫了FilterChain物件的doFilter方法,則web伺服器會檢查FilterChain物件中是否還有filter,如果有,則呼叫第2filter,如果沒有,則呼叫目標資源。

Filter鏈實驗(檢視filterChain API文件)

Filter是如何實現攔截的?

Filter介面中有一個doFilter方法,當開發人員編寫好Filter,並配置對哪個web資源(攔截url)進行攔截後,WEB伺服器每次在呼叫web資源之前,都會先呼叫一下filterdoFilter方法,因此,在該方法內編寫程式碼可達到如下目的:

呼叫目標資源之前,讓一段程式碼執行

是否呼叫目標資源(即是否讓使用者訪問web資源)。

web伺服器在呼叫doFilter方法時,會傳遞一個filterChain物件進來,filterChain物件是filter介面中最重要的一個物件,它也提供了一個doFilter方法,開發人員可以根據需求決定是否呼叫此方法,呼叫該方法,則web伺服器就會呼叫web資源的service方法,即web資源就會被訪問,否則web資源不會被訪問。

呼叫目標資源之後,讓一段程式碼執行

Filter的生命週期:

init(FilterConfig filterConfig)throws ServletException

和我們編寫的Servlet程式一樣,Filter的建立和銷燬由WEB伺服器負責web 應用程式啟動時web 伺服器將建立Filter 的例項物件,並呼叫其init方法進行初始化(注:filter物件只會建立一次,init方法也只會執行一次。示例 )

開發人員通過init方法的引數,可獲得代表當前filter配置資訊的FilterConfig物件。(filterConfig物件見下頁PPT)

doFilter(ServletRequest,ServletResponse,FilterChain)

每次filter進行攔截都會執行

在實際開發中方法中引數requestresponse通常轉換為HttpServletRequestHttpServletResponse型別進行操作

destroy()

Web容器解除安裝 Filter 物件之前被呼叫。

package cn.itcast.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;

/**
 * 過濾器的生命週期
 * @author Administrator
 *
 */
public class FilterDemo2 implements Filter{
	
	/**
	 * 初始化的操作
	 * 過濾器什麼建立呢?	伺服器啟動的時候建立過濾器的例項。
	 * 呼叫幾次?	呼叫一次	
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("init...");
	}
	
	/**
	 * 什麼時候執行
	 * 每次請求的時候,過濾器配置滿足過濾的條件,有一次請求就會執行一次。
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("doFilter....");
		chain.doFilter(request, response);
	}

	/**
	 * 過濾器什麼時候銷燬  伺服器關閉,移除專案
	 * 呼叫幾次 一次。
	 */
	public void destroy() {
		System.out.println("destroy....");
	}

}

 FilterConfig介面:

使用者在配置filter時,可以使用<init-param>filter配置一些初始化引數,當web容器例項化Filter物件,呼叫其init方法時,會把封裝了filter初始化引數的filterConfig物件傳遞進來。因此開發人員在編寫filter時,通過filterConfig物件的方法,就可獲得:

String getFilterName():得到filter的名稱。

String getInitParameter(String name): 返回在部署描述中指定名稱的初始化引數的值。如果不存在返回null.

Enumeration getInitParameterNames():返回過濾器的所有初始化引數的名字的列舉集合。

public ServletContext getServletContext():返回Servlet上下文物件的引用。

Filter的配置之<filter>(和上面有雷同)

<filter>
 	     <filter-name>testFitler</filter-name>
	     <filter-class>org.test.TestFiter</filter-class>
	     <init-param>
		 <param-name>word_file</param-name>	
		 <param-value>/WEB-INF/word.txt</param-value>
	     </init-param>
</filter>



<filter-name>用於為過濾器指定一個名字,該元素的內容不能為空。
<filter-class>元素用於指定過濾器的完整的限定類名。
<init-param>元素用於為過濾器指定初始化引數,它的子元素<param-name>指定引數的名字,<param-value>指定引數的值。在過濾器中,可以使用FilterConfig介面物件來訪問初始化引數。

 Filter的配置之<filter-mapping>:

<filter-mapping>元素用於設定一個 Filter 所負責攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑

<filter-name>子元素用於設定filter的註冊名稱。該值必須是在<filter>元素中宣告過的過濾器的名字

<url-pattern>設定 filter 所攔截的請求路徑(過濾器關聯的URL樣式)

<servlet-name>指定過濾器所攔截的Servlet名稱。

<dispatcher>指定過濾器所攔截的資源被 Servlet 容器呼叫的方式,可以是REQUEST,INCLUDE,FORWARDERROR之一,預設REQUEST。使用者可以設定多個<dispatcher> 子元素用來指定 Filter 對資源的多種呼叫方式進行攔截。

package cn.itcast.filter;

import java.io.IOException;
import java.util.Enumeration;

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;

public class FilterDemo3 implements Filter{

	/**
	 * 使用FilterConfig來獲取一些資訊
	 */
	public void init(FilterConfig config) throws ServletException {
		// 獲取filter配置的名稱<filter-name>
		String filterName = config.getFilterName();
		System.out.println("過濾器的配置名稱:"+filterName);
		// 獲取初始化引數
		String username = config.getInitParameter("username");
		String password = config.getInitParameter("password");
		System.out.println(username+" : "+password);
		
		Enumeration<String> e = config.getInitParameterNames();
		while(e.hasMoreElements()){
			// username和password
			String name = e.nextElement();
			// 獲取username的值
			String value = config.getInitParameter(name);
			System.out.println(name+" : "+value);
		}
		
		// 獲取ServeltContext物件
		ServletContext c = config.getServletContext();
		
	}
	
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("我是demo3...");
		chain.doFilter(request, response);
		System.out.println("我是回來的demo3...");
	}

	public void destroy() {
		
	}

}
 <filter>
	 	<filter-name>FilterDemo3</filter-name>
	 	<filter-class>cn.itcast.filter.FilterDemo3</filter-class>
	 	<init-param>
	 		<param-name>username</param-name>
	 		<param-value>root</param-value>
	 	</init-param>
	 	<init-param>
	 		<param-name>password</param-name>
	 		<param-value>123</param-value>
	 	</init-param>
	 </filter>
	  <filter-mapping>
	 	<filter-name>FilterDemo3</filter-name>
	 	<url-pattern>/*</url-pattern>
	 	<dispatcher>ERROR</dispatcher>
	 </filter-mapping>
	 -->

 

對映Filter示例:

<filter-mapping>
     <filter-name>testFilter</filter-name>
    <url-pattern>/test.jsp</url-pattern>
</filter-mapping>



<filter-mapping>
    <filter-name>testFilter</filter-name>
   <url-pattern>/index.jsp</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>

對映Filter的多種方式:

<dispatcher> 子元素可以設定的值及其意義:

REQUEST:當用戶直接訪問頁面時,Web容器將會呼叫過濾器。如果目標資源是通過RequestDispatcherinclude()forward()方法訪問時,那麼該過濾器就不會被呼叫。

INCLUDE:如果目標資源是通過RequestDispatcherinclude()方法訪問時,那麼該過濾器將被呼叫。除此之外,該過濾器不會被呼叫。

FORWARD:如果目標資源是通過RequestDispatcherforward()方法訪問時,那麼該過濾器將被呼叫,除此之外,該過濾器不會被呼叫。

ERROR:如果目標資源是通過宣告式異常處理機制呼叫時,那麼該過濾器將被呼叫。除此之外,過濾器不會被呼叫。

Filter常見應用(1):

統一全站字元編碼的過濾器

通過配置引數encoding指明使用何種字元編碼,以處理Html Form請求引數的中文問題

過濾器類:

web.xml配置檔案: 

 

package cn.itcast.demo1;

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;

/**
 * 解決全域性的編碼的問題
 * @author Administrator
 *
 */
public class EncodingFilter implements Filter{

	
	private FilterConfig filterConfig;

	public void init(FilterConfig filterConfig) throws ServletException {
		this.filterConfig = filterConfig;
	}

	/**
	 * 設定編碼的問題
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		String encoding = filterConfig.getInitParameter("encoding");
		// 解決POST亂碼的問題
		request.setCharacterEncoding(encoding);
		// 響應
		response.setContentType("text/html;charset="+encoding);
		// 放行
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}

Filter常見應用(2)

禁止瀏覽器快取所有動態頁面的過濾器:

3 HTTP 響應頭欄位都可以禁止瀏覽器快取當前頁面,它們在 Servlet 中的示例程式碼如下:

response.setDateHeader("Expires",-1);

response.setHeader("Cache-Control","no-cache"); 

response.setHeader("Pragma","no-cache"); 

並不是所有的瀏覽器都能完全支援上面的三個響應頭,因此最好是同時使用上面的三個響應頭。

Expires資料頭:值為GMT時間值,為-1指瀏覽器不要快取頁面

Cache-Control響應頭有兩個常用值:

no-cache指瀏覽器不要快取當前頁面。

max-age:xxx指瀏覽器快取頁面xxx秒。

package cn.itcast.demo2;

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.HttpServletResponse;

public class TimeFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 設定三個頭資訊
		HttpServletResponse resp = (HttpServletResponse) response;
		resp.setHeader("Cache-Control", "no-cache");
		resp.setHeader("Pragma", "no-cache");
		resp.setDateHeader("Expires", -1);
		
		chain.doFilter(request, resp);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}
 <filter>
	 	<filter-name>TimeFilter</filter-name>
	 	<filter-class>cn.itcast.demo2.TimeFilter</filter-class>
	 </filter>
	 <filter-mapping>
	 	<filter-name>TimeFilter</filter-name>
	 	<url-pattern>*.jsp</url-pattern>
	 </filter-mapping>
</filter>

 

Filter常見應用(3):

分ip統計訪問次數

因為一個網站可能有多個頁面,無論哪個頁面被訪問,都要統計訪問次數,所以使用過濾器最為方便。

因為需要分IP統計,所以可以在過濾器中建立一個Map,使用IP為key,訪問次數為value。當有使用者訪問時,獲取請求的IP,如果IP在Map中存在,說明以前訪問過,那麼在訪問次數上加1,即可;IP在Map中不存在,那麼設定次數為1。

把這個Map存放到ServletContext中!

package cn.itcast.demo3;

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;

public class CountFilter implements Filter{

	private FilterConfig config;

	/**
	 * 進行初始化的操作
	 * 在ServletContext域中存入map
	 */
	public void init(FilterConfig config) throws ServletException {
		// 先有一個MAP
		Map<String, Integer> countMap = new HashMap<String, Integer>();
		ServletContext context = config.getServletContext();
		// 存
		context.setAttribute("countMap", countMap);
		this.config = config;
	}
	
	/**
	 * 該方法執行了
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		/**
		 * 1.獲取map
		 * 2.獲取ip
		 * 3.在map中和ip就對比
		 * 	* 如果map中有ip,獲取count,+1
		 * 	* 如果map中沒有ip,把ip和count=1存入到map中
		 * 4.把map存入到ServletContext中
		 * 5.放行
		 */
		ServletContext context = config.getServletContext();
		// 獲取map
		Map<String, Integer> countMap = (Map<String, Integer>) context.getAttribute("countMap");
		// 獲取你的ip
		String ip = request.getRemoteAddr();
		// 判斷map中是否存在該ip
		Integer count = countMap.get(ip);
		// 判斷count為null
		if(count == null){
			// 第一次來
			count = 1;
		}else{
			// 來過很多次了
			count++;
		}
		// 把ip和count存入到Map中
		countMap.put(ip, count);
		// 向域中存入map
		context.setAttribute("countMap", countMap);
		// 放行
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}
 <filter>
	 	<filter-name>CountFilter</filter-name>
	 	<filter-class>cn.itcast.demo3.CountFilter</filter-class>
	 </filter>
	 <filter-mapping>
	 	<filter-name>CountFilter</filter-name>
	 	<url-pattern>/*</url-pattern>
	 </filter-mapping>

Filter常見應用(4):

實現使用者自動登陸的過濾器

什麼是自動登入?

自動登入就是必須先登入,並且選擇自動登入的按鈕,關閉瀏覽器,再次開啟瀏覽器訪問原來的登入頁面的時候,會直接進入,不行再次登入。

 

在使用者登陸成功後,以cookis形式傳送使用者名稱、密碼給客戶端

編寫一個過濾器,filter方法中檢查cookie中是否帶有使用者名稱、密碼資訊,如果存在則呼叫業務層登陸方法,登陸成功後則向session中存入user物件(即使用者登陸標記),以實現程式完成自動登陸。

保證環境配置準備完畢,還需要在MySQL中建立表資訊,與User封裝類的欄位相同。

後臺程式:

MyjdbcUtil.java: 操作資料庫的工具類,獨立放在util工具包中:

package cn.itcast.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * 操作JDBC
 * @author Administrator
 */
public class MyJdbcUtil {
	
	public static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	/**
	 * 獲取連結
	 * @return
	 * @throws SQLException 
	 */
	public static Connection getConnection() throws SQLException{
		return dataSource.getConnection();
	}
	
	/**
	 * 獲取連線池
	 * @return
	 */
	public static DataSource getDataSource(){
		return dataSource;
	}
	
	/**
	 * 釋放資源
	 * @param rs
	 * @param stmt
	 * @param conn
	 */
	public static void release(ResultSet rs,Statement stmt,Connection conn){
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			rs = null;
		}
		if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}
		if(conn != null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
	/**
	 * 釋放資源的方法
	 * @param stmt
	 * @param conn
	 */
	public static void release(Statement stmt,Connection conn){
		if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}
		if(conn != null){
			try {
				// 歸還的方法
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
}

LoginServlet.java:

package cn.itcast.demo4;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登陸的功能
 * @author Administrator
 *
 */
public class LoginServlet extends HttpServlet {

	private static final long serialVersionUID = -8579027867816374707L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		request.setCharacterEncoding("UTF-8");
		// 獲取引數
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		
		UserDao dao = new UserDao();
		User existUser = dao.findUser(username, password);
		if(existUser == null){
			// 給提示
			request.getRequestDispatcher("/demo4/login.jsp").forward(request, response);
		}else{
			
			// 把使用者名稱和密碼儲存到cookie中,回寫到瀏覽器。
			String autologin = request.getParameter("autologin");
			// 下一次自動登陸,把你的使用者名稱和密碼儲存起來
			if("auto_ok".equals(autologin)){
				// 建立cookie,回寫
				Cookie cookie = new Cookie("autologin",username+"#itcast#"+password);
				// 設定有效時間
				cookie.setMaxAge(60*60);
				// 回寫
				response.addCookie(cookie);
			}
			// 把使用者的資訊儲存到session中
			request.getSession().setAttribute("existUser", existUser);
			response.sendRedirect(request.getContextPath()+"/demo4/suc.jsp");
		}
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}


User.java:

package cn.itcast.demo4;

public class User {
	
	private int id;
	private String username;
	private String password;
	private String nickname;
	private String type;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
}

UserDao.java:

package cn.itcast.demo4;

import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import cn.itcast.utils.MyJdbcUtil;

public class UserDao {
	
	/**
	 * 通過使用者名稱和密碼查詢單個使用者
	 * @param username
	 * @param password
	 * @return
	 */
	public User findUser(String username,String password){
		QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
		try {
			return runner.query("select * from t_user where username = ? and password = ?", new BeanHandler<User>(User.class), username,password);
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

}

 AutoLoginFilter.java:            過濾器實現自動登入功能

package cn.itcast.demo4;

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.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * 自動登陸的功能
 * @author Administrator
 *
 */
public class AutoLoginFilter implements Filter{

	public void init(FilterConfig filterConfig) throws ServletException {
		
	}
	
	
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		/**
		 * * 在過濾器中可以直接獲取session中的使用者資訊,如果user不為空,說明瀏覽器沒關。放行。
			* 從session中獲取不到user的資訊
		  * 先獲取cookie,獲取指定名稱的cookie,
		  * 如果cookie為空,放行。
		  * 如果cookie不為空,獲取使用者名稱和密碼。去資料庫查詢。
		  * 如果查詢不到,cookie的資訊不正確,放行(沒有存入session中)。
		  * 如果查詢到了,cookie中的資訊是正確,把使用者的資訊儲存到session中。放行。
		 */
		// 從session中獲取使用者的資訊
		HttpServletRequest req = (HttpServletRequest) request;
		HttpSession session = req.getSession();
		// 從session獲取使用者的資訊
		User user = (User) session.getAttribute("existUser");
		// 如果瀏覽器沒關閉,session中的使用者資訊不為null的
		if(user != null){
			chain.doFilter(req, response);
		}else{
			// session中沒有使用者的資訊
			// 獲取指定名稱的cookie
			Cookie [] cookies = req.getCookies();
			// 獲取到cookie,就可以進行判斷了
			Cookie cookie = getCookieByName(cookies,"autologin");
			// 如果cookie為null
			// 在你的瀏覽器中,根本就沒有autologin的cookie
			if(cookie == null){
				// 直接放行	自己訪問suc.jsp(因為suc.jsp已經做過處理了,沒有session預設讓你去登陸)了。
				chain.doFilter(req, response);
			}else{
				// 從cookie中獲取使用者名稱和密碼,去資料中查詢
				String username = cookie.getValue().split("#itcast#")[0];
				String password = cookie.getValue().split("#itcast#")[1];
				// 你需要去資料庫中進行查詢
				UserDao dao = new UserDao();
				// 去資料庫中查詢指定名稱和密碼的使用者
				User existUser = dao.findUser(username, password);
				// 查詢出的使用者為null
				if(existUser == null){
					// 放行
					chain.doFilter(req, response);
				}else{
					// 存入到session中
					session.setAttribute("existUser", existUser);
					// 放行
					chain.doFilter(req, response);
				}
			}
		}
	}
	
	
	public Cookie getCookieByName(Cookie [] cookies,String cookieName){
		if(cookies == null){
			return null;
		}else{
			for (Cookie cookie : cookies) {
				// 判斷
				if(cookie.getName().equals(cookieName)){
					return cookie;
				}
			}
			return null;
		}
	}
	

	public void destroy() {
		
	}

}

<filter>
	 	<filter-name>AutoLoginFilter</filter-name>
	 	<filter-class>cn.itcast.demo4.AutoLoginFilter</filter-class>
	 </filter>
	 <filter-mapping>
	 	<filter-name>AutoLoginFilter</filter-name>
	 	<url-pattern>/*</url-pattern>
	 </filter-mapping>

 

前臺程式:

login.jsp:
 

<%@ 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>Insert title here</title>
</head>
<body>

<h3>登陸頁面</h3>
<form action="${ pageContext.request.contextPath }/login" method="post">
	使用者名稱:<input type="text"  name="username" /><br/>
	密碼:<input type="password"  name="password" /><br/>
	<input type="checkbox" name="autologin" value="auto_ok" />自動登陸<br/> 
	<input type="submit" value="登陸 " />
</form>

</body>
</html>

suc.jsp:
 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
    <%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>
    
<!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>Insert title here</title>
</head>
<body>

<c:if test="${ empty existUser }">
	<h3><a href="${ pageContext.request.contextPath }/demo4/login.jsp">親,請登陸!</a></h3>
</c:if>

<c:if test="${ not empty existUser }">
	<h3>親!歡迎訪問:${ existUser.nickname },角色是:${ existUser.type }</h3>
	
	<h3>
		<a href="${ pageContext.request.contextPath }/admin/add.jsp">新增商品</a>
		<a href="${ pageContext.request.contextPath }/admin/update.jsp">修改商品</a>
		<a href="${ pageContext.request.contextPath }/admin/delete.jsp">刪除商品</a>
		<a href="${ pageContext.request.contextPath }/user/show.jsp">檢視商品</a>
	</h3>
	
</c:if>

</body>
</html>

Filter常見應用(5):

AuthorityFilter 許可權過濾器

在一個系統中通常有多個許可權的使用者。不同許可權使用者的可以瀏覽不同的頁面。使用Filter進行判斷不僅省下了程式碼量,而且如果要更改的話只需要在Filter檔案裡動下就可以。

過濾器類:

package cn.itcast.demo5;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

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.http.HttpServletRequest;

import cn.itcast.demo4.User;

/**
 * URL級別全選驗證
 * @author Administrator
 *
 */
public class CheckUserUrlFilter implements Filter{

	private FilterConfig config;

	/**
	 * 初始化的操作,獲取初始化引數,讀取到Map集合中。存入ServletContext中。
	 */
	public void init(FilterConfig config) throws ServletException {
		// 建立Map儲存資訊
		Map<String, String> urlMap = new HashMap<String, String>();
		// 獲取初始化引數,把引數的內容儲存到urlMap中
		Enumeration<String> e = config.getInitParameterNames();
		while(e.hasMoreElements()){
			// 獲取到<param-name>的值
			String paramName = e.nextElement();
			// 獲取到的是<param-value>的值
			String paramValue = config.getInitParameter(paramName);
			// 存入Map集合中 	{/admin:admin}	{/user:user}
			urlMap.put(paramName, paramValue);
		}
		// 存入到ServletContext中
		config.getServletContext().setAttribute("urlMap", urlMap);
		this.config = config;
	}

	/**
	 * 許可權的驗證
	 * 	* 從請求的連結中拿到連結和urlMap中的連結和type型別做對比
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 先獲取請求的連結		請求:/admin/add.jsp		map {/admin:admin}	{/user:user}
		
		HttpServletRequest req = (HttpServletRequest) request;
		// /day21/admin/add.jsp
		// String uri = req.getRequestURI();
		// System.out.println(uri);
		// 
		// 獲取請求的連結
		String sPath = req.getServletPath();
		// System.out.println(sPath);
		// 和Map來進行對比
		ServletContext context = config.getServletContext();
		// 獲取Map的集合了
		Map<String, String> urlMap = (Map<String, String>) context.getAttribute("urlMap");
		
		// 做對比 set的key值 /admin  /user
		Set<String> set = urlMap.keySet();
		// 迴圈 /admin
		for (String paramName : set) {
			// /admin/add.jsp從/admin開始的
			if(sPath.startsWith(paramName)){
				// 去獲取session的使用者資訊,從使用者的資訊中獲取type屬性的值,和Map中的value的值進行對比。
				User user = (User) req.getSession().getAttribute("existUser");
				// 如果user為null
				if(user == null){
					// 轉發到登陸的頁面上
					req.getRequestDispatcher("/demo4/login.jsp").forward(req, response);
					return;
				}else{
					// 去判斷使用者的type的值和我Map中的value的值做對比
					String userType = user.getType();
					
					// 還有一個Map中存了一個值  {/admin  admin} {/user  user}
					String paramValue = urlMap.get(paramName);
					
					if(userType.equals(paramValue)){
						// 匹配成功了	/admin/add.jsp  做過一次判斷了,已/admin開頭的,
						// 從使用者的資訊中獲取type 的值和Map的值做了對比
						chain.doFilter(req, response);
						return;
					}else{
						// 向用戶提示
						response.setContentType("text/html;charset=UTF-8");
						response.getWriter().write("<h3>親,您許可權不夠!!</h3>");
						return;
					}
				}
			}
		}
		
		chain.doFilter(req, response);
		
	}

	public void destroy() {
		
	}

}

 

web.xml配置檔案: 

<filter>
	 	<filter-name>CheckUserUrlFilter</filter-name>
	 	<filter-class>cn.itcast.demo5.CheckUserUrlFilter</filter-class>
	 	<init-param>
	 		<param-name>/admin</param-name>
	 		<param-value>admin</param-value>
	 	</init-param>
	 	<init-param>
	 		<param-name>/user</param-name>
	 		<param-value>user</param-value>
	 	</init-param>
	 </filter>
	 <filter-mapping>
	 	<filter-name>CheckUserUrlFilter</filter-name>
	 	<url-pattern>/*</url-pattern>
	 </filter-mapping>

 

Filter高階開發:

由於開發人員在filter中可以得到代表使用者請求和響應的requestresponse物件,因此在程式設計中可以使用Decorator(裝飾器)模式對requestresponse物件進行包裝,再把包裝物件傳給目標資源,從而實現一些特殊需求。

Decorator設計模式的實現

1.首先看需要被增強物件繼承了什麼介面或父類,編寫一個類也去繼承這些介面或父類。

2.在類中定義一個變數,變數型別即需增強物件的型別。

3.在類中定義一個建構函式,接收需增強的物件。

4.覆蓋需增強的方法,編寫增強的程式碼。

request物件的增強:

Servlet API 中提供了一個request物件的Decorator設計模式的預設實現類HttpServletRequestWrapper , (HttpServletRequestWrapper 類實現了request 介面中的所有方法,但這些方法的內部實現都是僅僅呼叫了一下所包裝的的 request 物件的對應方法)以避免使用者在對request物件進行增強時需要實現request介面中的所有方法。

使用Decorator模式包裝request物件,完全解決getpost請求方式下的亂碼問題