Servlet之过滤器总结--Filter

来源:互联网 发布:果园系统源码 编辑:程序博客网 时间:2024/05/17 10:56

            前言

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

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

                     围的IP是不能访问到的。

                          另外,在实际的项目中我们可能涉及到字符的转码,如果在每个页面都去设置转码会十分的

                    麻烦,这时就可以使用Filter来解决了。

             Filter

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

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

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

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

                            简单来说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