`

Filter拦截页面中include方式的请求,并取得其请求的URL

    博客分类:
  • Java
阅读更多

 

最近需要在项目中做一个缓存框架,通过插件方式加入,要求可以通过配置文件,指定需要缓存页面的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>
		<filter-name>Cache</filter-name>
		<filter-class>prx.cache.filter.CacheFilter</filter-class>
		<init-param>
			<!-- 过期时间设置,默认为60秒 -->
			<param-name>refreshPeriod</param-name>
			<param-value>120</param-value>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>Cache</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

 该方式,不能拦截到 include 请求。

 

修改如下:

	<filter>
		<filter-name>Cache</filter-name>
		<filter-class>prx.cache.filter.CacheFilter</filter-class>
		<init-param>
			<!-- 过期时间设置,默认为60秒 -->
			<param-name>refreshPeriod</param-name>
			<param-value>120</param-value>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>Cache</filter-name>
		<url-pattern>/index.jsp</url-pattern>
		<dispatcher>request</dispatcher>
		<!-- 使得页面中通过 include 方式嵌入的匹配页面也可以通过该Filter -->
		<dispatcher>include</dispatcher>
	</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。

 

public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		HttpServletRequest httpRequest = (HttpServletRequest)request;
		
		//取的url相对地址,例如:/PrxWebCache/index.jsp
		String url = httpRequest.getRequestURI();
		System.out.println(url);
		
		int cacheGrade = CacheUtils.isNeedCacheUrl(url);
		if(cacheGrade != 0) {	//是否是需要缓存的url
			String key = CacheUtils.createKeyByUrl(httpRequest);
			boolean isInCache = CacheUtils.isInCache(httpRequest, key, cacheGrade);
			if(isInCache) {
				try {
					String content = (String)CacheUtils.getFromCache(httpRequest, key, cacheGrade, refreshPeriod);
					System.out.println("缓存");
					response.getWriter().print(content);	
				} catch (NeedsRefreshException e) {	//过期,需要刷新
					System.out.println("刷新");
					cacheAndResponseContent(httpRequest, response, chain, key, cacheGrade);
				}
			} else {
				//拦截响应数据,先加入缓存,再响应给客户端
				cacheAndResponseContent(httpRequest, response, chain, key, cacheGrade);
			}
		} else {
			chain.doFilter(request, response);
		}
	}

 

在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)也读出来

 

/**
	 * 返回请求的URL的参数部分,例如:url=/index.jsp?type=1&searchWord=java,则返回type=1&searchWord=java
	 * @param request
	 */
	@SuppressWarnings("unchecked")
	private static String getSortedQueryString(HttpServletRequest request) {
        Map paramMap = request.getParameterMap();

        if (paramMap.isEmpty()) {
            return null;
        }

        Set paramSet = new TreeMap(paramMap).entrySet();

        StringBuffer buf = new StringBuffer();

        boolean first = true;

        for (Iterator it = paramSet.iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            String[] values = (String[]) entry.getValue();

            for (int i = 0; i < values.length; i++) {
                String key = (String) entry.getKey();

                if ((key.length() != 10) || !"jsessionid".equals(key)) {
                    if (first) {
                        first = false;
                    } else {
                        buf.append('&');
                    }

                    buf.append(key).append('=').append(values[i]);
                }
            }
        }

        // We get a 0 length buffer if the only parameter was a jsessionid
        if (buf.length() == 0) {
            return null;
        } else {
            return buf.toString();
        }
    }

 

该方法返回的结果为: /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 "

 

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

   (String)request.getAttribute("javax.servlet.include.query_string"); 

 

该结果即为:type2=include&param2=test2  正是需要的仅为 include 请求的参数。

分享到:
评论

相关推荐

    JavaWeb开发技术-Filter映射.pptx

    除了URL模式,`&lt;filter-mapping&gt;`还可以包含`&lt;dispatcher&gt;`元素,用于指定Filter应拦截的Servlet容器调用方式。`&lt;dispatcher&gt;`元素有四种可能的值: 1. **REQUEST**:这是默认值,表示当客户端发出请求时,Filter会...

    jsp,servlet,filter温故知新

    在`FilterDemo`这个例子中,我们可以创建一个自定义的Filter,配置在web.xml中,指定其拦截的URL模式。Filter可以通过`chain.doFilter(request, response)`来将请求传递给下一个Filter或目标资源。 ### 应用场景 -...

    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;...

    javafilter[参考].pdf

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

    day19_Filter&Listener教案1

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

    java filter

    通过以上配置,所有进入系统的请求都会被`EncodingFilter`拦截,并自动设置为`gb2312`编码格式,从而避免了由于编码不一致导致的问题。 #### 四、Filter的实际应用场景 除了上述的批量设置请求编码外,`Filter`还...

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

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

    jsp的URL重写(内附说明)

    - **解析URL:** 在Filter中解析请求URL,根据预设规则拆分出实际参数。 - **转发请求:** 使用`RequestDispatcher.forward()`将请求转发到正确的Servlet或JSP。 4. **使用URL重写框架:** - **Tuckey ...

    java filter过滤器

    Java Filter是Java Servlet技术的一部分,它允许开发者在Servlet容器中对HTTP请求和响应进行拦截处理,实现数据过滤、权限控制、日志记录等多种功能。Filter的生命周期包括三个主要方法:`init()`、`doFilter()` 和 ...

    servlet过滤器详解

    **过滤器(Filter)**是一种Web组件,它能够在客户端请求到达目标资源(如Servlet、JSP页面等)之前进行预处理,以及在响应返回客户端之前进行后处理。通过这种方式,过滤器能够有效地拦截和修改请求或响应的信息。 ...

    深入了解Java中的Filter过滤器

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

    JSP用过滤器解决request getParameter中文乱码问题.docx

    过滤器在Servlet容器中扮演着拦截请求和响应的角色,可以在请求到达目标资源(如JSP页面)之前对其进行预处理,包括设置合适的字符编码,以确保中文字符正确解析。下面将详细介绍如何使用过滤器来解决这个问题。 ...

    Exper9.rar

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

    javaWed笔记

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

    jsp过滤器开发

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

    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和...

    JSP面试题--基础

    - **初次请求**:JSP 页面首次被请求时,会被转换成 Servlet 并编译执行。 - **后续请求**:JSP 编译后的 Servlet 将被缓存,后续请求直接使用缓存的 Servlet 处理。 #### 16. Servlet 的线程安全性问题 Servlet ...

    siteMesh使用示例

    SiteMesh 提供了一种简单有效的方式来进行页面布局,使得开发者可以专注于业务逻辑,而不必担心页面的统一风格问题。通过登录和注册页面的示例,我们可以看到 SiteMesh 如何帮助我们实现页面的统一装饰,同时保持...

    JAVA面试题(中).pdf

    GET方法通常用于获取数据,请求参数附加在URL后面,有长度限制,数据以明文方式在URL中传输,安全性较低;而POST方法则用于发送数据,请求参数在消息体中传输,传输数据量没有限制,安全性相对较高。 Web服务器是...

    sitemesh简单教程页面装配器

    通过在Web应用中部署一个过滤器(filter),该过滤器可以拦截每一个HTTP请求,并根据配置动态地将页面的不同部分组合起来,形成一个完整的视图。这样一来,不仅大大简化了页面的编写工作,也极大地提高了代码的可维护...

Global site tag (gtag.js) - Google Analytics