`

Filter拦截include方式的请求

阅读更多

最近需要在项目中做一个缓存框架,通过插件方式加入,要求可以通过配置文件,指定需要缓存页面的URL。

于是就想到做一个拦截器Filter。

该Filter可以首先拦截所有的请求,然后取得请求的URL,与配置中的需要缓存的URL对比,如果需要缓存,则进入缓存处理,如果不需要缓存,则直接到下一个Fitler。

具体的缓存处理,采用开源框架OScache。

方案还是比较简单的。 测试中发现,一般的Fitler只能拦截到从浏览器地址栏中过来的请求。 而页面的采用<jsp:include>方式载入的请求页面,则不能拦截到。

查看相关资料http://www.ibm.com/developerworks/java/library/j-tomcat2/ 后,得出结论:

在Servlet2.3中,Fitler是不能拦截include, forward, error 方式发来的请求的。

在Serlvet2.4中,则增强了Filter的功能,使之可以拦截到上面说的三个请求。 不过需要在配置文件中增加一个配置。

<filter> 

  1.     <filter-name>Cache</filter-name> 
  2.     <filter-class>prx.cache.filter.CacheFilter</filter-class> 
  3.     <init-param> 
  4.         <!-- 过期时间设置,默认为60秒 --> 
  5.         <param-name>refreshPeriod</param-name> 
  6.         <param-value>120</param-value> 
  7.     </init-param> 
  8. </filter> 
  9.  
  10. <filter-mapping> 
  11.     <filter-name>Cache</filter-name> 
  12.     <url-pattern>/*</url-pattern> 
  13. </filter-mapping> 
 该方式,不能拦截到 include 请求。

修改如下:

  1. <filter> 
  2.     <filter-name>Cache</filter-name> 
  3.     <filter-class>prx.cache.filter.CacheFilter</filter-class> 
  4.     <init-param> 
  5.         <!-- 过期时间设置,默认为60秒 --> 
  6.         <param-name>refreshPeriod</param-name> 
  7.         <param-value>120</param-value> 
  8.     </init-param> 
  9. </filter> 
  10.  
  11. <filter-mapping> 
  12.     <filter-name>Cache</filter-name> 
  13.     <url-pattern>/index.jsp</url-pattern> 
  14.     <dispatcher>request</dispatcher> 
  15.     <!-- 使得页面中通过 include 方式嵌入的匹配页面也可以通过该Filter --> 
  16.     <dispatcher>include</dispatcher> 
  17. </filter-mapping> 
 在配置文件,增加 <dispatcher></dispatcher>配置:

<dispatcher>request </dispatcher>    Filter 只能拦截 匹配的 request 方式的请求,为默认值 。

<dispatcher>include </dispatcher>     Filter 只能拦截 匹配的 incldue 方式的请求

<dispatcher>forward </dispatcher>    Filter 只能拦截 匹配的 forward 方式的请求

<dispatcher>error </dispatcher>         Filter 只能拦截 匹配的 error 方式的请求

dispatcher可以配置多个,用来组合各种需求。

例如:上面的配置,Fitler可以拦截 request和include 方式的请求。

通过以上的配置,就可以是Filter拦截到 include 的请求了。(当然,tomcat需要支持 servlet2.4)

到此解决了问题一。

在后来的测试又发现,虽然Filter是拦截了 incldue 的请求,但是在 Fitler 中,却无法取得该 incldue 的URL

由于项目的缓存方案是需要,取得URL请求,然后再判断是否需要缓存。 所以必须取得该 include 请求的URL。

  1. public void doFilter(ServletRequest request, ServletResponse response, 
  2.             FilterChain chain) throws IOException, ServletException { 
  3.          
  4.         HttpServletRequest httpRequest = (HttpServletRequest)request; 
  5.          
  6.         //取的url相对地址,例如:/PrxWebCache/index.jsp 
  7.         String url = httpRequest.getRequestURI(); 
  8.         System.out.println(url); 
  9.          
  10.         int cacheGrade = CacheUtils.isNeedCacheUrl(url); 
  11.         if(cacheGrade != 0) {   //是否是需要缓存的url 
  12.             String key = CacheUtils.createKeyByUrl(httpRequest); 
  13.             boolean isInCache = CacheUtils.isInCache(httpRequest, key, cacheGrade); 
  14.             if(isInCache) { 
  15.                 try { 
  16.                     String content =  (String)CacheUtils.getFromCache(httpRequest, key, cacheGrade, refreshPeriod); 
  17.                     System.out.println("缓存"); 
  18.                     response.getWriter().print(content);     
  19.                 } catch (NeedsRefreshException e) { //过期,需要刷新 
  20.                     System.out.println("刷新"); 
  21.                     cacheAndResponseContent(httpRequest, response, chain, key, cacheGrade); 
  22.                 } 
  23.             } else { 
  24.                 //拦截响应数据,先加入缓存,再响应给客户端 
  25.                 cacheAndResponseContent(httpRequest, response, chain, key, cacheGrade); 
  26.             } 
  27.         } else { 
  28.             chain.doFilter(request, response); 
  29.         } 
  30.     } 

在Filter中,通过 httpRequest.getRequestURI(); 取出的 URL:

1. 当是 request 请求时,取得的 URL 是正确的。

2. 当是 include 请求时, 取得的 URL 是 包含该 include 元素的原页面的 URL

比如: 在 main.jsp  页面中  有个 <jsp:include page="index.jsp?type=test"/>

当Fitler拦截到 该 include请求时, httpRequest.getRequestURI(); 得出的是 main.jsp 而不是我需要的 index.jsp

但是 通过 httpRequest.getParameter("type");  却可以得到 传入的参数 "test"。

到网上搜个半天,都没有相关答案。最后在 OScache 源码中发现了一个方法。 

httpRequest.getAttribute("javax.servlet.include.request_uri")

通过该方法,可以直接取出 include 请求的 URL 值。

至于,这个 "javax.servlet.include.request_uri" 参数怎么设置进来的,还没仔细研究。 时间紧张,先用着,以后再研究吧。

又发现一个问题:

在Filter中拦截到incldue方式的请求后,在取得传入的所有参数的时候,会把request 的请求参数也读出来。

比如:请求页面  /index.jsp?type1=request&param1=test1  然后再 index.jsp页面中有一个 <jsp:include page="/main.jsp?type2=include&param2=test2"/>

当访问 /index.jsp?type1=request&param1=test1 时,使用上面的方法拦截到  include请求 /main.jsp?type2=include&param2=test2

Filter中的 在取得该请求的所有参数的时候,会将 /index.jsp的参数(type1=request&param1=test1)也读出来

  1. /** 
  2.  * 返回请求的URL的参数部分,例如:url=/index.jsp?type=1&searchWord=java,则返回type=1&searchWord=java 
  3.  * @param request 
  4.  */ 
  5.     private static String getSortedQueryString(HttpServletRequest request) { 
  6.         Map paramMap = request.getParameterMap(); 
  7.  
  8.         if (paramMap.isEmpty()) { 
  9.             return null
  10.         } 
  11.  
  12.         Set paramSet = new TreeMap(paramMap).entrySet(); 
  13.  
  14.         StringBuffer buf = new StringBuffer(); 
  15.  
  16.         boolean first = true
  17.  
  18.         for (Iterator it = paramSet.iterator(); it.hasNext();) { 
  19.             Map.Entry entry = (Map.Entry) it.next(); 
  20.             String[] values = (String[]) entry.getValue(); 
  21.  
  22.             for (int i = 0; i < values.length; i++) { 
  23.                 String key = (String) entry.getKey(); 
  24.  
  25.                 if ((key.length() != 10) || !"jsessionid".equals(key)) { 
  26.                     if (first) { 
  27.                         first = false
  28.                     } else { 
  29.                         buf.append('&'); 
  30.                     } 
  31.  
  32.                     buf.append(key).append('=').append(values[i]); 
  33.                 } 
  34.             } 
  35.         } 
  36.  
  37.         // We get a 0 length buffer if the only parameter was a jsessionid 
  38.         if (buf.length() == 0) { 
  39.             return null
  40.         } else { 
  41.             return buf.toString(); 
  42.         } 
  43.     }
该方法返回的结果为: /main.jsp?type2=include&param2=test2&type1=request&param1=test1

这样就取得了包含,index.jsp的参数。

我现在想要只想要取得 include请求的参数,即 /main.jsp?type2=include&param2=test2 的参数部分type2=include&param2=test2

但是通过 request.getParameter()方法,是无法判断出哪个参数才是 include 请求的参数。

经过上面的启发,于是又想到了,是不是有别的AttributeName 可以仅取到 include 请求的参数呢?

通过测试,果然发现的确有该AttributeName:"javax.servlet.include.query_string"

只要通过一句话便可以得到该  参数字符串:

  1. (String)request.getAttribute("javax.servlet.include.query_string");
该结果即为:type2=include&param2=test2  正是需要的仅为 include 请求的参数。

本文出自 http://1077267.blog.51cto.com/1067267/438224

分享到:
评论

相关推荐

    Filter(过滤器)简介和工作原理

    Filter 或者目标 Servlet 程序去处理,也可以直接向客户端返回响应信息,或者利用 RequestDispatcher 的 forward() 和 include() 方法,以及 HttpServletResponse 的 sendRedirect() 方法将请求转向到其他资源。...

    JavaWeb开发技术-Filter映射.pptx

    Filter是一种特殊的Java类,能够拦截客户端到服务器端的请求和服务器响应,对数据进行预处理或者后处理。在这个主题中,我们将深入探讨Filter的映射及其在web.xml文件中的配置,以及它们如何与Servlet容器交互。 ...

    jsp,servlet,filter温故知新

    - **过滤**:通过实现`doFilter()`方法,Filter可以拦截请求和响应,进行预处理或后处理。 - **销毁**:在Filter不再使用时,服务器会调用`destroy()`方法。 在`FilterDemo`这个例子中,我们可以创建一个自定义的...

    day19_Filter&Listener教案1

    可以通过多个`&lt;filter-mapping&gt;`元素为一个Filter配置不同的拦截规则,也可以通过`&lt;dispatcher&gt;`元素指定Filter在请求的不同阶段(如FORWARD、INCLUDE、ERROR等)发挥作用。 【监听器(Listener)简介】 监听器...

    java filter

    - 可以通过`&lt;dispatcher&gt;`元素指定`Filter`是否应用于特定的请求分派器类型,如`INCLUDE`、`FORWARD`等。 2. **批量设置请求编码** 一个常见的应用场景是批量设置请求的编码格式。例如,下面的示例展示了如何...

    javafilter[参考].pdf

    Java Filter 是Java Servlet API 中的一个重要概念,它允许开发者在请求到达目标Servlet或者JSP之前进行拦截处理,以及在响应返回给客户端之后进行后处理。这个功能在软件开发中广泛应用于日志记录、权限控制、数据...

    LogFilter (2)_javaweb_

    在`web.xml`中,我们需要配置`&lt;filter&gt;`和`&lt;filter-mapping&gt;`元素来指定`LogFilter`的类名和需要拦截的URL模式。例如: ```xml &lt;filter&gt; &lt;filter-name&gt;LogFilter&lt;/filter-name&gt; &lt;filter-class&gt;...

    Filter学习心得

    Filter(过滤器)是Java Web开发中的一个重要组件,它主要用于拦截用户请求,在请求达到目标资源(如Servlet或JSP页面)之前进行预处理,或者在响应返回客户端之前进行后处理。通过Filter可以实现诸如权限验证、编码...

    java filter过滤器

    【Java Filter过滤器详解】 Java Filter是Java Servlet...总的来说,Java Filter提供了一种灵活的方式来增强Web应用程序的功能,通过在请求和响应之间插入自定义逻辑,可以在不修改原有代码的情况下实现多种扩展需求。

    javafilter简单的使用[借鉴].pdf

    在Web应用程序中,Filter允许开发者在请求到达Servlet之前和响应离开Servlet之后进行拦截和处理,增强了应用的灵活性和可扩展性。 一、Filter的生命周期与配置 Filter遵循一定的生命周期,包括`init()`、`doFilter...

    深入了解Java中的Filter过滤器

    在`&lt;filter-mapping&gt;`中,`&lt;dispatcher&gt;`元素用于指定Filter拦截资源的方式,常见的值有REQUEST、INCLUDE、FORWARD和ERROR,分别对应不同的请求处理阶段。例如,REQUEST表示用户直接访问,INCLUDE表示通过`...

    servlet过滤器详解

    通过这种方式,过滤器能够有效地拦截和修改请求或响应的信息。 - **过滤器的作用**: - **拦截请求**:在请求到达Servlet之前,过滤器可以对其进行拦截,从而实现对请求内容的检查或修改。 - **修改请求**:过滤...

    Exper9.rar

    - **DispatcherTypes**:Filter可以拦截多种类型的请求,如REQUEST、FORWARD、INCLUDE、ERROR等,这使得Filter能应用于各种场景。 3. **配置Filter** 在web.xml中,我们需要定义Filter的映射,包括Filter的类名、...

    第9章 Servlet高级_课后题_gh210628.docx

    * Filter 链中各个 Filter 执行请求时的拦截顺序与响应时的拦截顺序相同。 六、Session 配置 * 在 web.xml 中,&lt;session-config&gt; 元素用于配置 Session 的超时时间。 * 在空闲状态下,Session 对象的销毁是根据 ...

    javaWed笔记

    - 在`web.xml`文件中,可以通过在`&lt;filter-mapping&gt;`元素内的`&lt;url-pattern&gt;`子元素中使用通配符“*”,来配置过滤器拦截所有请求。这种方式非常灵活且方便,特别适用于需要对所有请求进行相同预处理或后处理的情况...

    Servlet学习笔记5

    -- 指定哪些URL模式会被此Filter拦截 --&gt; &lt;dispatcher&gt;request &lt;dispatcher&gt;forward &lt;dispatcher&gt;include &lt;!-- 指定Filter在请求分发过程中的作用范围 --&gt; &lt;/filter-mapping&gt; ``` #### 二、CharArrayWriter和...

    Java Filter 过滤器详细介绍及实例代码

    - `&lt;url-pattern&gt;`:使用正则表达式指定Filter拦截的请求路径。 - `&lt;servlet-name&gt;`:指定Filter拦截的Servlet名称。 - `&lt;dispatcher&gt;`:定义Filter何时被调用,可选值有REQUEST, INCLUDE, FORWARD, 和 ERROR。 ...

    jsp-14-过滤器

    过滤器可以在请求到达目标资源(如Servlet、JSP)之前或之后拦截请求和响应。通过实现`doFilter()`方法,我们可以定义过滤器的行为。 2. **过滤器生命周期** 过滤器有三个关键方法:`init()`, `doFilter()`, 和 `...

    jsp过滤器开发

    过滤器的主要功能是对请求和响应进行预处理和后处理,允许开发者在请求到达目标资源之前和响应离开应用程序之后进行拦截,执行诸如认证、日志记录、参数处理、压缩等任务。 1. **过滤器的工作原理** 过滤器的工作...

Global site tag (gtag.js) - Google Analytics