Servlet之过滤器总结--Filter

            前言

                          我们知道实际开发中我们可能有这种需要:对于某个网站来说需要限制一些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


                   

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值