zoukankan      html  css  js  c++  java
  • Java 过滤器

    过滤器是一个驻留在服务器端的Web组建,可以截取客户端和资源之间的请求和响应信息。Web过滤器是不能直接处理客户端请求,返回客户端数据的!

    举例来说:当我们登录CSDN或邮箱的时候,输入应用名和密码就可以进入我们请求的页面,当我们点击退出后,下一次进入时需要重新输入登录用户名与密码。这是过滤器应用的一个场景。

    我们需要了解:

    • 过滤器的工作原理
    • 生命周期
    • 过滤器的几种类型
    • 实例

    1、过滤器的工作原理

    上面的图简单说明了过滤器在客户端和服务器之间的作用。

    2、过滤器的生命周期

    Web容器启动的时候,会加载web.xml并执行一次init()函数,然后每次客户端的请求都会执行doFilter()函数,最后当容器关闭的时候会执行destroy()函数

    上面显示的是一个Web应用程序的结构,所有的Webroot中的内容都是Web的内容,Web-INF下所有的资源都不能直接被url访问,其他的文件,用户可以通过url访问。

    关于url-pattern的书写规范,

    (A)一个filter映射一个url:这种情况下的url与url-pattern中配置的url进行精确匹配。url-pattern中的访问路径必须以  /  开头,表示的是Web应用程序的根目录,而不是Web站点的根目录,路径名称可以是多级目录的形式,例如

    <url-pattern>/demo/index.html</url-pattern>

    (B)一个filter映射多个url:这种情况下可以使用通配符,需要注意的也有两种情况:

    (1)*.扩展名,*点前面不能有 “/”

    (2)以/开头,并以 /* 结尾,例如

    <url-pattern>/action/*</url-pattern>表示的是整个action目录下的url

    <url-pattern>/</url-pattern>表示的是整个web应用程序下的url

    过滤器链

    1. 在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链
    2. Web服务器根据Filter在web.xml文件中的注册顺序(按filter-mapping元素的顺序),决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,Web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。
    3. 在doFilter方法中,如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。

     

    每次客户端的请求,服务器都会Filter中的doFilter方法,因此,我们可以在diFilter中完成一些处理,下面是一个简单的代码实现:

    public class FilterFirst implements Filter {     
    	// 应用被加载时完成过滤器的实例化     
    	public FilterFirst() {         
    		System.out.println("调用了默认构造方法");     
    	}       
    	// 初始化:服务器传入FilterConfig参数     
    	public void init(FilterConfig filterConfig) throws ServletException {         
    		System.out.println("调用初始化方法");     }       
    		// 用户每次访问被过滤资源都会调用过滤器的doFilter方法     
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {         
    		System.out.println("FilterDemo1第一次拦截");         
    		// 对request、response进行预处理,代码放在chain.doFilter()前         
    	chain.doFilter(request, response);// 放行         
    		// 对响应信息进行拦截,代码放在chain.doFilter()后         
    		System.out.println("FilterDemo1第二次拦截");     
    	}       
    	// 应用从服务器上卸载时调用销毁方法     
    	public void destroy() {         
    		System.out.println("调用销毁方法");     
    	} 
    } 
    

    web.xml的配置

    <filter>     
    <filter-name>FilterDemo1</filter-name>     
    <filter-class>org.flyne.filter.FilterDemo1</filter-class> 
    </filter>   
    
    <filter-mapping>     
    <filter-name>FilterDemo1</filter-name>     
    <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    

      注意代码中出现的doFilter函数以及其中的参数。ServletRequest request, ServletResponse response, FilterChain chain 因此:

    (1)我们可以实现将客户端到服务器,服务器到客户端的交换数据进行处理。

    (2) 处理完成后,我们一定要记得写上chain.doFilter(request, response);否则,Web访问会一直处于被拦截的状态;

     四、实例

    1)SetCharacterEncodingFilter:解决POST请求参数和响应输出的中文乱码

    public class SetCharacterEncodingFilter implements Filter {       
    	private String encoding; //编码可以通过<init-param>元素配置       
    	public void init(FilterConfig filterConfig) throws ServletException {         
    		encoding = filterConfig.getInitParameter("encoding");         
    		if(encoding == null){//如果用户忘记配置,默认encoding为UTF-8             
    			encoding = "UTF-8";         
    		}     
    	}       
    
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    	         //只能解决POST请求参数乱码问题         
    	         request.setCharacterEncoding(encoding);         
    	         //指定输出编码(最后带上,后面会有说明)         
    	         response.setCharacterEncoding(encoding);         
    	         //指定输出流编码及客户端应使用的码表         
    	         response.setContentType("text/html;charset="+encoding);         
    	         chain.doFilter(request, response);     
    	}       
    
    	public void destroy() {       } 
    } 
    
    ------------------------web.xml配置------------------------ 
    <filter>     
    <filter-name>SetCharacterEncodingFilter</filter-name>     
    <filter-class>org.flyne.examples.SetCharacterEncodingFilter</filter-class>     
    <init-param>         
    <param-name>encoding</param-name>         
    <param-value>UTF-8</param-value>     
    </init-param> 
    </filter> 
    
    <filter-mapping>     
    <filter-name>SetCharacterEncodingFilter</filter-name>     
    <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    

    2)2)NoCacheFilter:禁止客户端缓存动态资源

    public void doFilter(ServletRequest req, ServletResponse resp,  FilterChain chain) throws IOException, ServletException {   
    
    	//响应头为HTTP协议里的,需转换一下     
    	HttpServletRequest request = null;     
    	HttpServletResponse response = null;     
    	try{        
    		request = (HttpServletRequest)req;         
    		response = (HttpServletResponse)resp;     
    	}catch(Exception e){         
    		throw new RuntimeException("not-http request or response");     
    	}       
    		response.setHeader("Expires", "0");     
    		response.setHeader("Cache-Control", "no-cache"); //    
    		response.setHeader("Pragma", "no-cache");   //这三个参数的意义差不多  
    		chain.doFilter(request, response); 
    	} 
    	------------------------web.xml配置------------------------ 
    	<filter>     
    	<filter-name>NoCacheFilter</filter-name>     
    	<filter-class>org.flyne.examples.NoCacheFilter</filter-class> 
    	</filter> 
    
    	<filter-mapping>     
    	<filter-name>NoCacheFilter</filter-name>     
    	<url-pattern>/servlet/*</url-pattern>     
    	<url-pattern>*.jsp</url-pattern> 
    	</filter-mapping> 
    

    3)SetCacheExpiresFilter:控制静态资源缓存时间 (这个主要是理解HTTP协议中Expire的作用)

    public class SetCacheExpiresFilter implements Filter {       
    	private int htmlExp;//HTML的缓存时间,单位为小时,下同     
    	private int cssExp;//CSS的缓存时间     
    	private int jsExp;//JS的缓存时间      
    	public void init(FilterConfig filterConfig) throws ServletException {         
    		htmlExp = Integer.parseInt(filterConfig.getInitParameter("html"));         
    		cssExp = Integer.parseInt(filterConfig.getInitParameter("css"));         
    		jsExp = Integer.parseInt(filterConfig.getInitParameter("js"));     
    	}       
    
    	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {    
    	   	// 响应头为HTTP协议里的,需转换一下         
    	   	HttpServletRequest request = null;         
    	   	HttpServletResponse response = null;         
    	   	try { 
    	   		request = (HttpServletRequest) req;             
    	   		response = (HttpServletResponse) resp;         
    	   	} catch (Exception e) {             
    	   		throw new RuntimeException("not-http request or response");         
    	   	}           
    	   	//根据请求资源的后缀名确定缓存时间         
    	   	String uri = request.getRequestURI();         
    	   	String extName = uri.substring(uri.lastIndexOf(".")+1);         
    	   	long expTime = 0;         
    	   	if("html".equals(extName)){             	
    	   		expTime = System.currentTimeMillis()+htmlExp*60*60*1000;          
    	   	}else if("css".equals(extName)){             
    	   		expTime = System.currentTimeMillis()+cssExp*60*60*1000;         
    	   	}else if("js".equals(extName)){             
    	   		expTime = System.currentTimeMillis()+jsExp*60*60*1000;         
    	   	}         
    
    	   	response.setDateHeader("Expires", expTime);           
    	   	chain.doFilter(request, response);    
    	   }       
    
    	   public void destroy() {     } 
    
    	} 
    
    	------------------------web.xml配置------------------------ 
    
    	<filter>     
    	<filter-name>SetCacheExpiresFilter</filter-name>     
    	<filter-class>org.flyne.examples.SetCacheExpiresFilter</filter-class>     
    	<init-param>         
    	<param-name>html</param-name>         
    	<param-value>1</param-value>     
    	</init-param>     
    	<init-param>         
    	<param-name>css</param-name>         
    	<param-value>2</param-value>     
    	</init-param>     
    	<init-param>         
    	<param-name>js</param-name>         
    	<param-value>3</param-value>     
    	</init-param> </filter> <filter-mapping>     
    	<filter-name>SetCacheExpiresFilter</filter-name>     
    	<url-pattern>*.html</url-pattern>     
    	<url-pattern>*.css</url-pattern>     
    	<url-pattern>*.js</url-pattern> 
    	</filter-mapping> 
    

    4)AutoLoginFilter :用户自动登录

    当用户登陆时,将表单提交到LoginServlet处理,如果用户勾选了记住我,则将用户的登陆信息存入Cookie:Cookie名为“logInfo”,值为(用户名的base64加密结果_密码的md5加密结果)。下面的自动登录过滤器基于以上信息:

    public class AutoLoginFilter implements Filter {       
    //表现层同service层打交道     
    		private UserService service = new UserServiceImpl();       
    		public void init(FilterConfig filterConfig) throws ServletException {     }     
    		public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {         
    		// 转为Http协议的request和response         
    			HttpServletRequest request = null;        
    		 	HttpServletResponse response = null;         
    		 	try {             
    		 		request = (HttpServletRequest) req;             
    		 		response = (HttpServletResponse) resp;         
    		 	} catch (Exception e) {             	
    		 		throw new RuntimeException("not-http request or response");         
    		 	}           
    		 	HttpSession session = request.getSession();         
    		 	// 判断用户有没有登录:只管没有登录的        
    		 	User sUser = (User) session.getAttribute("user");         
    		 	if (sUser == null) {           
    		 		Cookie[] cookies = request.getCookies();             
    		 		for (int i = 0; cookies != null && i < cookies.length; i++) {                 
    		 		Cookie cookie = cookies[i];                 
    		 		//名为logInfo的Cookie记录了登录信息(用户名、密码)                 
    		 		if ("logInfo".equals(cookie.getName())) {                     
    		 		String value = cookie.getValue();                     
    		 		//Cookie中的用户名是经过Base64加密的,所以需要解密                     
    		 		String username = SecurityUtil.base64Decode(value.split("_")[0]);                     
    		 		String password = value.split("_")[1];                     
    		 		//Cookie中的密码是md5加密后的,所以第三个参数为true                     
    		 		User user = service.login(username, password, true);                     
    		 		//通过则在session中设置登陆标记                     
    		 		if(user!=null){                         
    		 			session.setAttribute("user", user);                     
    		 		}                     
    		 		break;                 
    		 		}             
    		 	}        
    		}         
    		chain.doFilter(request, response);     
    	}       
    public void destroy() {     } 
    
    } 
    

    未完......

    参考:MOOC  过滤器 实例来自 http://www.flyne.org/article/636/2

          

  • 相关阅读:
    可爱的中国电信 请问我们的电脑还属于我们自己吗?
    了解客户的需求,写出的代码或许才是最优秀的............
    DELPHI DATASNAP 入门操作(3)简单的主从表的简单更新【含简单事务处理】
    用数组公式获取字符在字符串中最后出现的位置
    在ehlib的DBGridEh控件中使用过滤功能(可以不用 MemTableEh 控件 适用ehlib 5.2 ehlib 5.3)
    格式化json返回的时间
    ExtJs中使用Ajax赋值给全局变量异常解决方案
    java compiler level does not match the version of the installed java project facet (转)
    收集的资料(六)ASP.NET编程中的十大技巧
    收集的资料共享出来(五)Asp.Net 权限解决办法
  • 原文地址:https://www.cnblogs.com/CBDoctor/p/4235082.html
Copyright © 2011-2022 走看看