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


                   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章