Servlet之过滤器总结--Filter

            前言

                          咱们知道实际开发中咱们可能有这种须要:对于某个网站来讲须要限制一些ip对该网站的访html

                     问。例如教育网站,一般咱们只能访问到它的首页,至于教务管理的页面,不在该教育网段范java

                     围的IP是不能访问到的。web

                          另外,在实际的项目中咱们可能涉及到字符的转码,若是在每一个页面都去设置转码会十分的编程

                    麻烦,这时就可使用Filter来解决了。浏览器

             Filter

                            Servlet过滤器Fileter是一个小型的web组件,它们经过拦截请求和响应,以便查看、提取或服务器

                      以某种方式操做客户端和服务器之间交换的数据,实现“过滤”的功能。Filter一般封装了一些功app

                      能的web组件,过滤器提供了一种面向对象的模块化机制,将任务封装到一个可插入的组件中,jsp

                      Filter组件经过配置文件来声明,并动态的代理。ide

                            简单来讲Servlet的Filter是:模块化

                            ●  声明式的:经过在web.xml配置文件中声明,容许添加、删除过滤器,而无需改动任何

                                 应用程序代码或jsp页面。

                           ●  灵活的:过滤器可用于客户端的直接调用执行预处理和后期的处理工做,经过过滤链可

                                 以实现一些灵活的功能。

                           ●  可移植的:因为现今各个web容器都是以Servlet的规范进行设计的,所以Servlet过滤器

                                 一样是跨容器的。

                           ●  可重用的:基于其可移植性和声明式的配置方式,Filter是可重用的。

                            总的来讲,Servlet的过滤器是经过一个配置文件来灵活的声明的模块化可重用组件。

                       过滤器动态的截获传入的请求和传出的响应,在不修改程序代码的状况下,透明的添加或删除

                       他们。其独立于任何平台和web容器。

               Filter体系结构

                               如其名字所暗示的同样,Servlet过滤器用于拦截传入的请求和传出的响应,并监视、修改

                         处理web工程中的数据流。过滤器是一个可插入的自由组件。

                               web资源能够不配置过滤器、也能够配置单个过滤器,也能够配置多个过滤器,造成一个

                         过滤器链。Filter接受用户的请求,并决定将请求转发给链中的下一个组件,或者终止请求

                         直接向客户端返回一个响应。若是请求被转发了,它将被传递给链中的下一个过滤器(以

                         web.xml过滤器的配置顺序为标准)。这个请求在经过过滤链并被服务器处理以后,一个响应

                         将以相反的顺序经过该链发送回去。这样,请求和响应都获得了处理。

                              Filter能够应用在客户端和Servlet之间、servlet和serlvet或jsp之间,以及jsp之间。而且

                         能够经过配置信息,灵活的使用那个过滤器。

                Filter工做原理

                               基于Filter体系结构的描述,咱们能够看出Filter的工做原理,简单的经过一幅流程图加以

                            演示:

                     

                              客户端浏览器在访问web服务器的某个具体资源的时候,通过过滤器1中code1代码块的相

                           关处理以后,将request请求传递给过滤链中的下一个过滤器2,(过滤链的顺序以配置文件

                           中的顺序为基准)过滤器2处理完以后,request就传递的Servlet完成相应的逻辑。

                              返回响应的过程相似,只是过滤链的顺序相反,这里就很少说了。

                  Filter的建立过程

                                  在具体去实现FIlter以前,先去看看Filter的源码,简单的看看实现Filter须要作的事,从

                            源码中能够看出,要编写一个过滤器必须实现Filter接口。实现其接口规定的方法。

                                   ★  实现javax.servlet.Filter接口

                                   ★ 实现init方法,读取过滤器的初始化参数

                                   ★ 实现doFilter方法,完成对请求或响应的过滤

                                   ★ 调用FilterChain接口对象的doFilter方法,向后续的过滤器传递请求或响应

                                  一个简单的字符编码处理的过滤器实现:

package com.kiritor.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;  public class EncodeFilter implements Filter{     //定义替换后的字符集,从过滤器的配置参数中读取     String newCharSet;     public void destroy(){     }     public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException      {         //处理请求字符集         request.setCharacterEncoding(newCharSet);                  //传递给下一个过滤器。这里没有下一个,做为过滤器的规则和良好的编程习惯,应该加上         chain.doFilter(request,response);          //处理响应字符集         response.setContentType("text/html;charset="+newCharSet);     }          public void init(FilterConfig filterConfig)throws ServletException      {         //从过滤器的配置中得到初始化参数,若是没有就使用默认值         if(filterConfig.getInitParameter("newcharset")!=null)         {             newCharSet = filterConfig.getInitParameter("newcharset");         }         else             newCharSet = "GB2312";     } }
                           这里对于过滤器对请求和响应的具体"过滤"过程,笔者就很少提了。

                Filter的配置

                                Filter是一个可插入的web组件,必须在web.xml文件中配置才有效,那么Filter是如何

                           配置的呢?针对上述字符编码的Filter,配置信息以下:                 

 <!-- 指定过滤器的名字,初始化参数等信息 -->   <filter>     <display-name>EncodeFilter</display-name>     <filter-name>EncodeFilter</filter-name>     <filter-class>com.kiritor.filter.EncodeFilter</filter-class>   </filter>   <!-- 指定过滤器的URL关联/*表示全部的 -->   <filter-mapping>     <filter-name>EncodeFilter</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping>
                                 url-pattern配置详解
                            在web.xml文件中,如下语法用于定义映射:

                               l 以”/’开头和以”/*”结尾的是用来作路径映射的。

                               l 之前缀”*.”开头的是用来作扩展映射的。

                               l “/” 是用来定义default servlet映射的。

                               l 剩下的都是用来定义详细映射的。好比: /aa/bb/cc.action

                               因此,为何定义”/*.action”这样一个看起来很正常的匹配会错?

                           由于这个匹配即属于路径映射,也属于扩展映射,致使容器没法判断。

                Filter编程实例演示:

                               接下来笔者将演示一个IP过滤器,过滤掉某个具体的ip,并将客户端的访问记录作

                           一个日志文件记录。实际的过程以下:

                               这里笔者保留了字符处理的Filter,打印信息,以便更好的理解过滤链的执行状况。

                               编写IP过滤器:IPFilter

package com.kiritor.filter;  import java.io.IOException; import java.net.InetAddress;  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;  import com.kiritor.logUtil.LogUtil;  /**  * Servlet Filter implementation class IPFilter  */ public class IPFilter implements Filter {      /**      * Default constructor.       */     private String ip;     private FilterConfig config;     public IPFilter() {         // TODO Auto-generated constructor stub     }      /**      * @see Filter#destroy()      */     public void destroy() {         // TODO Auto-generated method stub     }      /**      * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)      */     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {         HttpServletRequest req= (HttpServletRequest)request;         HttpServletResponse res = (HttpServletResponse)response;         // 获取客户请求lP         /*下面那条注释语句获得的是IPV6地址,          * 客户端和服务器在同一台机子上是得不到ipv4地址的**/         //String remoteIP = request.getRemoteAddr();         //以这种方式获取IPv4地址         InetAddress inet = InetAddress.getLocalHost();         LogUtil.logRecord(inet.getHostAddress());         //System.out.println(remoteIP);         if (inet.getHostAddress().equals("192.168.0.3")){                          req.getRequestDispatcher("ipErr.jsp").forward(request, response);                      } else {             chain.doFilter(request, response);// 调用过滤链上的下一个过滤器         }         System.out.println("IPFilter处理");         chain.doFilter(request, response);     }      /**      * @see Filter#init(FilterConfig)      */     public void init(FilterConfig fConfig) throws ServletException {         //从过滤器的配置中得到初始化参数,若是没有就使用默认值         this.config = fConfig;         if(fConfig.getInitParameter("ipinfo")!=null)         {             ip = fConfig.getInitParameter("ipinfo");         }         else             ip = "192.168.0.3";     }  }   
                        接下来进行配置:

        

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">   <display-name>Servlet_Filter</display-name>   <welcome-file-list>     <welcome-file>index.html</welcome-file>     <welcome-file>index.htm</welcome-file>     <welcome-file>index.jsp</welcome-file>     <welcome-file>default.html</welcome-file>     <welcome-file>default.htm</welcome-file>     <welcome-file>default.jsp</welcome-file>   </welcome-file-list>   <filter>     <display-name>EncodeFilter</display-name>     <filter-name>EncodeFilter</filter-name>     <filter-class>com.kiritor.filter.EncodeFilter</filter-class>     <init-param>         <param-name>newcharset</param-name>         <param-value>gb2312</param-value>     </init-param>   </filter>   <filter-mapping>     <filter-name>EncodeFilter</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping>   <filter>     <display-name>IPFilter</display-name>     <filter-name>IPFilter</filter-name>     <filter-class>com.kiritor.filter.IPFilter</filter-class>     <init-param>         <param-name>ipinfo</param-name>         <param-value>192.168.0.3</param-value>     </init-param>   </filter>   <filter-mapping>     <filter-name>IPFilter</filter-name>     <url-pattern>/*</url-pattern>   </filter-mapping> </web-app>
                               接下来简单的日志文件操做: 
package com.kiritor.logUtil;  import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date;  import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest;  /**  * @author Kiritor  * 2013-6-15 上午8:21:19  * 功能:实现IP访问的日志记录  */ public  class LogUtil {    public static void logRecord(String ip)    {        try{            FileOutputStream out = new FileOutputStream("D:\\log.txt",true);                        Date date = new Date();            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd a  hh:mm:ss");            String str = f.format(date);                        String runningMsg = str+"--->\r\n"+                  ip +"登陆"                     +"\r\n";            out.write(runningMsg.getBytes());            out.close();                    }catch(Exception e){            e.printStackTrace();        }    } } 
                           ok,咱们看看实际的运行效果吧!
         

                           日志文档信息记录以下:        

2013-06-15 上午  08:56:59---> 192.168.0.3登陆 2013-06-15 上午  09:00:08---> 192.168.0.3登陆 
                              好了,对于Servlet过滤器的学习就到这个地方了,固然上述实例只是Filter的简单运用

                      十分的灵活与方便。

                       参考文档:

                        http://www.ibm.com/developerworks/cn/java/j-pj2ee10/index.html

                                                                                                                                     By      Kiritor

                                                                                                                                     2013 /06 /15