Servlet 过滤器

简介:   过滤器Filter,是介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。一、过滤器的概念    现在有以下几个请求:        1、针对所有的Servlet,产品经理想要了解从请求到响应之间的时间差。

  过滤器Filter,是介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。

一、过滤器的概念

    现在有以下几个请求:

        1、针对所有的Servlet,产品经理想要了解从请求到响应之间的时间差。

        2、针对某些特定的页面,希望仅有几个用户才能知道。

        3、基于安全方面,用户希望输入的特定字符必须过滤并且替换为无害的字符。

        4、请求与响应的编码从Big5改为UTF-8。

    思路分析:

        1、运行Servlet的service()方法前后,各记录一个时间,计算其差。:过滤器

        2、运行Servlet的service()方法前,验证是否为允许的用户。

        3、运行Servlet的service()方法前,对请求参数进行字符过滤与替换。

        4、运行Servlet的service()方法前,对请求与响应对象设置编码。

    性能评测、用户验证、字符替换、编码设置这类需求,应该设置为独立的元件,随时可以加入到应用程序中,这类元件就像过滤器,安插在浏览器与Servlet之间。如图、

        

二、过滤器的实现与设置

    必须实现Filter接口,并用@WebFilter标注。Filter接口主要实现三个方法:init()、doFilter()、destroy()

    FilterConfig类似于Servlet接口init()方法参数上的ServletConfig,FilterConfig设置信息的代表对象。如果定义过滤器时设置了初始参数,可以通过FilterConfig的getInitParameter()方法来取得初始参数。

    Filter接口的doFilter()方法,类似Servlet接口的service()方法,当请求来到容器,而容器发现调用Servlet的service()方法前,就会调用该过滤器的doFilter()方法。可以再doFilter()方法中进行service()方法的前置处理,而后决定是否调用FilterChaindoFilter()方法。

    如果调用了FilterChain的doFilter()方法,就会执行下一个过滤器,如果没有下一个过滤器了,就调用Servlet的service()方法,如果因为某个情况没有执行下一个过滤器(如,用户没有通过验证)而没有调用FilterChaindoFilter()方法,则请求就不会交给目标Servlet。FilterChain运行后会以堆栈顺序返回。

    例1:实现简单的性能评测过滤器,记录请求和响应间的时间差,了解Servlet处理请求到响应所花的时间。

 1 package ServletAPI;
 2 
 3 import java.io.IOException;
 4 import javax.servlet.Filter;
 5 import javax.servlet.FilterChain;
 6 import javax.servlet.FilterConfig;
 7 import javax.servlet.ServletException;
 8 import javax.servlet.ServletRequest;
 9 import javax.servlet.ServletResponse;
10 import javax.servlet.annotation.WebFilter;
11 import javax.servlet.annotation.WebInitParam;
12 
13 /**
14  * Servlet Filter implementation class PerformanceFilter
15  */
16 @WebFilter(
17         filterName = "performance", 
18         urlPatterns = { "/*" } 
19         )
20 public class PerformanceFilter implements Filter {
21     private FilterConfig fConfig;
22     /**
23      * Default constructor. 
24      */
25     public PerformanceFilter() {
26         // TODO Auto-generated constructor stub
27     }
28 
29     /**
30      * @see Filter#destroy()
31      */
32     public void destroy() {
33         // TODO Auto-generated method stub
34     }
35 
36     /**
37      * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
38      */
39     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
40         // TODO Auto-generated method stub
41         // place your code here
42 
43         // pass the request along the filter chain
44         long begin=System.currentTimeMillis();
45         chain.doFilter(request, response);
46         fConfig.getServletContext().log("Request process in "+(System.currentTimeMillis()-begin)+" millseconds.");
47     }
48 
49     /**
50      * @see Filter#init(FilterConfig)
51      */
52     public void init(FilterConfig fConfig) throws ServletException {
53         // TODO Auto-generated method stub
54         this.fConfig=fConfig;
55     }
56 
57 }
PerformanceFilter.java

三、请求封装器

1、实现字符替换过滤器

    假设用户不希望在留言中输入<a href=’http://openhome.cc’>openhome.cc</a>这样的信息,希望直接变成超链接。希望将一些html过滤掉,如将<、>角括号置换为HTML实体字符&lt;  &gt;

    EscapeWrapper类继承了HttpServletRequestWrapper,并定义了一个接受HttpSevletRequest的构造器,真正的HttpSevletRequest将通过此构造器传入,必须使用super()调用HttpSevletRequestWrapper接受HttpSevletRequest的构造器,之后要取得被封装的HttpSevletRequest,则可以调用getRequest()方法。

 1 package ServletAPI;
 2 import javax.servlet.http.HttpServletRequest;
 3 import javax.servlet.http.HttpServletRequestWrapper;
 4 
 5 
 6 import org.apache.commons.lang3.StringEscapeUtils;
 7 
 8 public class EscapeWrapper extends HttpServletRequestWrapper {
 9     public EscapeWrapper(HttpServletRequest request){
10         super(request);//必须调用父类的构造器,传入HttpServletRequest的实例。
11     }
12     public String getParameter(String name){//重新定义getParameter方法
13         String value=getRequest().getParameter(name);
14         return StringEscapeUtils.escapeHtml4(value);//将取得的请求参数值进行字符替换
15     }
16 }
EscapeWrapper.java

  可以使用这个请求封装器类搭配过滤器,以进行字符过滤操作的服务。例如:

 1 package ServletAPI;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.Filter;
 6 import javax.servlet.FilterChain;
 7 import javax.servlet.FilterConfig;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.ServletRequest;
10 import javax.servlet.ServletResponse;
11 import javax.servlet.annotation.WebFilter;
12 import javax.servlet.http.HttpServlet;
13 import javax.servlet.http.HttpServletRequest;
14 
15 /**
16  * Servlet Filter implementation class EscapeFilter
17  */
18 @WebFilter("/*")
19 public class EscapeFilter implements Filter {
20 
21     /**
22      * Default constructor. 
23      */
24     public EscapeFilter() {
25         // TODO Auto-generated constructor stub
26     }
27 
28     /**
29      * @see Filter#destroy()
30      */
31     public void destroy() {
32         // TODO Auto-generated method stub
33     }
34 
35     /**
36      * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
37      */
38     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
39         // TODO Auto-generated method stub
40         // place your code here
41 
42         // pass the request along the filter chain
43         HttpServletRequest requestWrapper=new EscapeWrapper((HttpServletRequest) request);//将原请求对象包裹至EscapeWrapper中。
44         
45         chain.doFilter(request, response);//将EscapeWrapper对象当做请求对象传入doFilter()
46     }
47 
48     /**
49      * @see Filter#init(FilterConfig)
50      */
51     public void init(FilterConfig fConfig) throws ServletException {
52         // TODO Auto-generated method stub
53     }
54 
55 }
EscapeFilter.java

  运行结果:

    

2、实现编码设置过滤器

    实现方式:过滤器+封装器

 1 package ServletAPI;
 2 
 3 import java.io.UnsupportedEncodingException;
 4 
 5 import javax.servlet.http.HttpServletRequest;
 6 import javax.servlet.http.HttpServletRequestWrapper;
 7 
 8 public class EncodingWrapper extends HttpServletRequestWrapper{
 9     private String ENCODING;
10     public EncodingWrapper(HttpServletRequest request,String ENCODING){
11         super(request);
12         this.ENCODING=ENCODING;
13     }
14     public String getParameter(String name){
15         String value=getRequest().getParameter(name);
16         if(value!=null){
17             try {
18                 byte[] b=value.getBytes("ISO-8859-1");
19                 value=new String(b,ENCODING);//编码转换
20             } catch (UnsupportedEncodingException e) {
21                 // TODO: handle exception
22                 throw new RuntimeException(e);
23             }
24         }
25         return value;
26     }
27 }
EncodingWrapper.java
 1 package ServletAPI;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.Filter;
 6 import javax.servlet.FilterChain;
 7 import javax.servlet.FilterConfig;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.ServletRequest;
10 import javax.servlet.ServletResponse;
11 import javax.servlet.annotation.WebFilter;
12 import javax.servlet.annotation.WebInitParam;
13 import javax.servlet.http.HttpServletRequest;
14 
15 import org.omg.CORBA.PUBLIC_MEMBER;
16 
17 /**
18  * Servlet Filter implementation class EncodingFilter
19  */
20 @WebFilter(
21         urlPatterns = { "/*" }, 
22         initParams = { 
23                 @WebInitParam(name = "ENCODING", value = "UTF-8")
24         })
25 public class EncodingFilter implements Filter {
26     private String ENCODING;
27     /**
28      * Default constructor. 
29      */
30     public EncodingFilter() {
31         // TODO Auto-generated constructor stub
32     }
33 
34     /**
35      * @see Filter#destroy()
36      */
37     public void destroy() {
38         // TODO Auto-generated method stub
39     }
40 
41     /**
42      * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
43      */
44     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
45         // TODO Auto-generated method stub
46         // place your code here
47 
48         // pass the request along the filter chain
49         HttpServletRequest req=(HttpServletRequest)request;
50         if("GET".equals(req.getMethod())){
51             req=new EncodingWrapper(req,ENCODING);//GET请求时创建封装器
52         }
53         else{
54             req.setCharacterEncoding(ENCODING);
55         }
56         chain.doFilter(request, response);
57     }
58 
59     /**
60      * @see Filter#init(FilterConfig)
61      */
62     public void init(FilterConfig fConfig) throws ServletException {
63         // TODO Auto-generated method stub
64         ENCODING=fConfig.getInitParameter("ENCODING");//读取初始参数
65     }
66 
67 }
EncodingFilter.java

四、响应封装器

    Servlet是通过HttpServletResponse对象来对浏览器进行响应的,通过getWriter()取得PrintWriter,或是通过getOutputStream()取得ServletOutputStream。如果想要对响应的内容进行压缩处理,主要继承了HttpServletResponseWrapper之后,重新定义这两个方法实现的。

    用GZIPOutputStream类实现压缩,其增加了压缩输出功能,重新定义writer()方法,通过GZIPOutputStream的writer()方法来做串流输出,GZIPOutputStream的writer()实现了压缩的功能。

 1 package ServletAPI;
 2 
 3 import java.io.IOException;
 4 import java.util.zip.GZIPOutputStream;
 5 
 6 import javax.servlet.ServletOutputStream;
 7 
 8 public class GZipServletOutputStream  extends ServletOutputStream{
 9     private GZIPOutputStream gzipOutputStream;
10     public GZipServletOutputStream(ServletOutputStream servletOutputStream) throws IOException{
11         this.gzipOutputStream=new GZIPOutputStream(servletOutputStream);
12         //使用GZIPOutputStream来增加压缩功能。
13     }
14     @Override
15     public void write(int b) throws IOException {
16         // TODO Auto-generated method stub
17         gzipOutputStream.write(b);//输出时通过GZIPOutputStream的write()方法来压缩输出
18     }
19     public GZIPOutputStream getGzipOutputStream(){
20         return gzipOutputStream;
21     }
22 
23 }
GZipServletOutputStream.java
 1 package ServletAPI;
 2 
 3 import java.io.IOException;
 4 import java.io.OutputStreamWriter;
 5 import java.io.PrintWriter;
 6 import java.util.zip.GZIPOutputStream;
 7 
 8 import javax.servlet.ServletOutputStream;
 9 import javax.servlet.http.HttpServletResponse;
10 import javax.servlet.http.HttpServletResponseWrapper;
11 
12 public class CompressionWrapper extends HttpServletResponseWrapper {
13     private GZipServletOutputStream gzServletOutputStream;
14     private PrintWriter printWriter;
15     public CompressionWrapper(HttpServletResponse response) {
16         super(response);
17         // TODO Auto-generated constructor stub
18         
19     }
20     public ServletOutputStream getOutputStream()throws IOException{
21         if(printWriter!=null){
22             throw new IllegalStateException();//已调用过getWriter(),再调用getOutputStream()就抛出异常
23         }
24         if(gzServletOutputStream==null){
25             gzServletOutputStream=new GZipServletOutputStream(getResponse().getOutputStream());
26             //创建有压缩功能的GZipServletOutputStram对象    
27         }
28         return gzServletOutputStream;
29     }
30     public PrintWriter getWriter() throws IOException{
31         if(gzServletOutputStream!=null){
32             throw new IllegalStateException();//已调用过getOutputStream(),再调用getWriter()就抛出异常
33         }
34         if(printWriter==null){
35             gzServletOutputStream=new GZipServletOutputStream(getResponse().getOutputStream());
36             OutputStreamWriter osw= new OutputStreamWriter(gzServletOutputStream,getResponse().getCharacterEncoding());
37             //创建GzipServletOutputStream对象,供构造PrintWriter时使用
38             printWriter=new PrintWriter(osw);
39         }
40         return printWriter;
41     }
42     
43     public void setContentLength(int len){}//不实现此方法内容,因为真正的输出会压缩
44     public GZIPOutputStream getGZIPOutputStream(){
45         if(this.gzServletOutputStream==null){
46             return null;
47         }
48         return this.gzServletOutputStream.getGzipOutputStream();
49     }
50 }
CompressionWrapper.java

  在同一个请求期间,getWriter()和getOutputStream()只能选择一个调用。接下来实现一个压缩过滤器,使用上面开发的CompressionWrapper来封装原HttpServletResponse。

 1 package ServletAPI;
 2 
 3 import java.io.IOException;
 4 import java.util.zip.GZIPOutputStream;
 5 
 6 import javax.servlet.Filter;
 7 import javax.servlet.FilterChain;
 8 import javax.servlet.FilterConfig;
 9 import javax.servlet.ServletException;
10 import javax.servlet.ServletRequest;
11 import javax.servlet.ServletResponse;
12 import javax.servlet.annotation.WebFilter;
13 import javax.servlet.http.HttpServletRequest;
14 import javax.servlet.http.HttpServletResponse;
15 
16 /**
17  * Servlet Filter implementation class CompressionFilter
18  */
19 @WebFilter(filterName="CompressionFilter",urlPatterns="/*")
20 public class CompressionFilter implements Filter {
21 
22     /**
23      * Default constructor. 
24      */
25     public CompressionFilter() {
26         // TODO Auto-generated constructor stub
27     }
28 
29     /**
30      * @see Filter#destroy()
31      */
32     public void destroy() {
33         // TODO Auto-generated method stub
34     }
35 
36     /**
37      * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
38      */
39     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
40         // TODO Auto-generated method stub
41         // place your code here
42 
43         // pass the request along the filter chain
44         HttpServletRequest req=(HttpServletRequest)request;
45         HttpServletResponse res=(HttpServletResponse)response;
46         String encoding=req.getHeader("accept-encoding");
47         
48         if((encoding!=null)&&(encoding.indexOf("gzip")>-1)){//检查是否接受gzip压缩
49             CompressionWrapper responseWrapper=new CompressionWrapper(res);//创建响应封装器
50             responseWrapper.setHeader("content-encoding","gzip");//设置响应内容编码为gzip格式
51             chain.doFilter(request, responseWrapper);//下一个过滤器
52             GZIPOutputStream gzipOutputStream=responseWrapper.getGZIPOutputStream();
53             if(gzipOutputStream!=null){
54                 gzipOutputStream.finish();//调用GZIPOutputStream的finish方法来完成压缩输出。
55             }
56         }else{
57             chain.doFilter(request, response);//不接受压缩,直接进行下一个过滤器
58         }
59     }
60 
61     /**
62      * @see Filter#init(FilterConfig)
63      */
64     public void init(FilterConfig fConfig) throws ServletException {
65         // TODO Auto-generated method stub
66     }
67 
68 }
CompressionFilter.java

  浏览器是否采用GZIP压缩的格式,可以通过检查accept-encoding请求标头中是否包括gzip字符串来判断,如果接受,就创建CompressionWrapper封装原对象,并设置content-encoding响应标头为gzip即可。接着调用doFilter()时,传入的响应对象为CompressionWrapper对象。当doFilter()结束时,必须调用GZIPOutputStream的finish()方法,这才会将GZIP后的资料从缓冲区中全部移除并进行响应。

    如果客户端不接受GZIP压缩,就直接调用FilterChain的doFilter()。

 

当神已无能为力,那便是魔渡众生
目录
相关文章
|
3月前
|
JavaScript Java 容器
servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别
本文简要回顾了Servlet过滤器Filter的概念和使用,通过实例演示了如何创建过滤器以过滤请求字符编码,并解释了在web.xml中配置过滤器时使用`/`、`/*`和`/**`的区别。
servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别
|
4月前
|
存储 前端开发 Java
servlet过滤器--使用过滤器统计网站访问人数的计数(注解形式)
该文章展示了如何使用Servlet过滤器(Filter)通过注解方式创建一个网站访问人数统计功能,通过`@WebFilter`注解定义过滤器及其URL模式,并在`doFilter`方法中实现计数逻辑,将访问次数存储在`ServletContext`中,最后在JSP页面展示访问人数。
servlet过滤器--使用过滤器统计网站访问人数的计数(注解形式)
|
4月前
|
C# 数据可视化 开发者
WPF开发者福音:深度解析OxyPlot与LiveCharts图表库,轻松实现数据可视化不再是难题!
【8月更文挑战第31天】在WPF应用中,数据可视化对提升用户体验至关重要。本文介绍并演示了两种流行图表库OxyPlot和LiveCharts的集成与使用方法。OxyPlot是一款适用于.NET应用的开源图表库,提供多种图表类型,易于集成。LiveCharts则以其丰富的图表类型和动画效果,特别适合实时数据展示。通过具体代码示例,本文展示了如何利用这两种图表库创建折线图和柱状图,并详细说明了安装和配置步骤。希望本文能帮助开发者在WPF应用中轻松实现高效、美观的数据可视化。
206 0
|
4月前
|
监控 前端开发 Java
揭秘Web开发神器:Servlet、过滤器、拦截器、监听器如何联手打造无敌博客系统,让你的用户欲罢不能!
【8月更文挑战第24天】在Java Web开发中,Servlet、过滤器(Filter)、拦截器(Interceptor,特指Spring MVC中的)及监听器(Listener)协同工作,实现复杂应用逻辑。以博客系统为例,Servlet处理文章详情请求,过滤器(如LoginFilter)检查登录状态并重定向,Spring MVC拦截器(如LoggingInterceptor)提供细粒度控制(如日志记录),监听器(如SessionListener)监控会话生命周期事件。这些组件共同构建出高效、有序的Web应用程序。
40 0
|
7月前
|
容器
Servlet 教程 之 Servlet 编写过滤器 6
该教程介绍了如何在Servlet中编写过滤器。可以创建多个过滤器,如AuthenFilter和LogFilter,并通过不同的映射进行配置。过滤器的应用顺序由web.xml中filter-mapping的顺序决定,可通过调整顺序改变过滤器执行的先后。
33 3
|
7月前
|
Java 容器
Servlet 教程 之 Servlet 编写过滤器 2
Servlet过滤器教程:实现Filter接口,包含3个核心方法。1) doFilter用于实际过滤,处理匹配URL的请求,调用FilterChain处理后续过滤。2) init方法在应用启动时被调用,初始化filter,从FilterConfig获取配置信息。3) destroy方法在过滤器销毁前执行,释放资源。
35 2
|
7月前
|
Java
Servlet 教程 之 Servlet 编写过滤器 3
`LogFilter` 是一个 Servlet 过滤器示例,它打印网站名称并传递请求至过滤链。当与 `DisplayHeader` Servlet(显示 HTTP 头信息)配合使用时,提供基础过滤器概念的理解。过滤器在请求处理前可添加额外功能或修改输入,而 `doGet` 方法则用于响应 GET 请求,展示请求头信息。
25 2
|
7月前
|
XML 数据格式
Servlet 教程 之 Servlet 编写过滤器 4
在Servlet教程中,学习如何编写过滤器。在`web.xml`配置文件中,创建一个名为`LogFilter`的过滤器,类为`com.baidu.test.LogFilter`,设置初始化参数`Site`为`百度`。将过滤器映射到`/*`,确保所有请求都会经过此过滤器。同时定义了一个名为`DisplayHeader`的Servlet,映射到`/TomcatTest/DisplayHeader`路径。
28 1
|
7月前
|
XML Java 数据安全/隐私保护
Servlet 教程 之 Servlet 编写过滤器 1
Servlet过滤器用于动态拦截请求和响应,实现如身份验证、数据压缩、日志记录等多种功能。它们可附加于Servlet、JSP或HTML,按web.xml中配置的顺序执行。Web容器启动时会根据部署描述符创建过滤器实例。
34 2
|
7月前
|
容器
Servlet 教程 之 Servlet 编写过滤器 7
Servlet教程讲解如何编写过滤器。在`web.xml`中,`&lt;filter&gt;`定义过滤器,`&lt;filter-name&gt;`和`&lt;filter-class&gt;`分别设定名称和类。`&lt;init-param&gt;`配置初始化参数。`&lt;filter-mapping&gt;`指定过滤器作用的资源,可通过`&lt;servlet-name&gt;`或`&lt;url-pattern&gt;`定义。`&lt;dispatcher&gt;`定义过滤器触发时机,如REQUEST、INCLUDE、FORWARD和ERROR,控制过滤器何时拦截资源调用。
34 0