码迷,mamicode.com
首页 > 其他好文 > 详细

Filter编程:(2)Filter进阶

时间:2016-06-14 06:33:21      阅读:215      评论:0      收藏:0      [点我收藏+]

标签:filter

  1. Filter简介

    1. 从功能角度来说,Filter能做什么?

    2. 从API角度来说,如何实现Filter?

    3. 从原理角度来说,Filter是如何实现拦截的?

  2. Filter生命周期和Filter链

    1. Filter生命周期的三个方法:init、doFilter和destory

    2. Filter链及其调用顺序

  3. Filter高级开发

    1. HttpServletRequestWrapper

    2. HttpServletResponseWrapper

    3. 动态代理

    4. Filter映射

  4. Filter案例


3、Filter高级开发

由于开发人员在filter中可以得到代表用户请求和响应的request、response对象,因此在编程中可以使用Decorator(装饰器)模式对request、response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求。


3.1、HttpServletRequestWrapper

HttpServletRequestWrapper类,全名是javax.servlet.http.HttpServletRequestWrapper,它是对HttpServletRequest的一种(装饰模式)实现,便于程序开发者进行扩展。

Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper , (HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法)以避免用户在对request对象进行增强时需要实现request接口中的所有方法。


用装饰模式解决GET和POST请求编码的问题

CharacterEncodingFilter.java

package com.rk.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

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.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

public class CharacterEncodingFilter implements Filter
{
	private FilterConfig filterConfig;
	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		this.filterConfig = filterConfig;
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException
	{
		HttpServletRequest request;
		HttpServletResponse response;
		try
		{
			request = (HttpServletRequest) req;
			response = (HttpServletResponse) resp;
		}
		catch (Exception e)
		{
			throw new RuntimeException("non-http request or response");
		}
		
		String encoding = this.filterConfig.getInitParameter("encoding");
		if(encoding == null)
			encoding = "UTF-8";
		request.setCharacterEncoding(encoding);//解决POST请求参数编码
		response.setCharacterEncoding(encoding);//更改响应字符流使用的编码
		response.setContentType("text/html;charset="+encoding);//更改响应字符流使用的编码,还能告知浏览器用什么格式进行显示
		
		CharacterEncodingHttpServletRequest myRequest = new CharacterEncodingHttpServletRequest(request);
		chain.doFilter(myRequest, response);
		
	}

	@Override
	public void destroy()
	{
		
	}
}
/**
 * 使用“装饰模式”定义自己的处理GET请求中字符编码的问题
 * @author lsieun
 *
 */
class CharacterEncodingHttpServletRequest extends HttpServletRequestWrapper
{
	/**
	 * 构造方法
	 */
	public CharacterEncodingHttpServletRequest(HttpServletRequest request)
	{
		super(request);
	}
	
	@Override
	public String getParameter(String name)
	{
		String value = super.getParameter(name);
		if(value == null) return value;
		
		//如果是GET请求,则进行转码
		if("GET".equalsIgnoreCase(super.getMethod()))
		{
			try
			{
				byte[] bytes = value.getBytes("ISO-8859-1");
				value = new String(bytes,super.getCharacterEncoding());
			}
			catch (UnsupportedEncodingException e)
			{
				throw new RuntimeException(e);
			}
		}
		return value;
	}
}

web.xml中的配置

  <filter>
  	<filter-name>CharacterEncodingFilter</filter-name>
  	<filter-class>com.rk.filter.CharacterEncodingFilter</filter-class>
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>utf-8</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>CharacterEncodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>



3.2、HttpServletResponseWrapper

HttpServletResponseWrapper类,全名是javax.servlet.http.HttpServletResponseWrapper,它是对HttpServletResponse的一种(装饰模式)实现,便于程序开发者进行扩展。

Servlet  API 中提供了response对象的Decorator设计模式的默认实现类HttpServletResponseWrapper , (HttpServletResponseWrapper类实现了response接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 response对象的对应方法)以避免用户在对response对象进行增强时需要实现response接口中的所有方法。


用户装饰模式对响应的内容进行GZIP格式压缩

GZipFilter.java

package com.rk.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GZipFilter implements Filter
{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException
	{
		HttpServletRequest request;
		HttpServletResponse response;
		try
		{
			request = (HttpServletRequest) req;
			response = (HttpServletResponse) resp;
		}
		catch (Exception e)
		{
			throw new RuntimeException("non-http request or response");
		}
		
		MyHttpServletResponse myResponse = new MyHttpServletResponse(response);
		chain.doFilter(request, myResponse);
		
		byte[] bytes = myResponse.getOldData();//获取原始数据是问题关键
		System.out.println("压缩前:" + bytes.length);
		//GZIP压缩
		ByteArrayOutputStream out = new ByteArrayOutputStream();//内存字节缓存输出流
		GZIPOutputStream gzipOutputStream = new GZIPOutputStream(out);
		gzipOutputStream.write(bytes);//压缩后的数据写到了ByteArrayOutputStream中了
		gzipOutputStream.close();
		//取出压缩后的数据
		bytes = out.toByteArray();
		System.out.println("压缩后:" + bytes.length);
		//告知客户端正文的压缩方式:gzip
		response.setHeader("Content-Encoding", "gzip");
		response.setContentLength(bytes.length);//响应消息头,告知客户端正文的长度
		response.getOutputStream().write(bytes);
	}

	@Override
	public void destroy()
	{
		
	}
}

class MyHttpServletResponse extends HttpServletResponseWrapper
{
	private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
	private PrintWriter printWriter = null;
	public MyHttpServletResponse(HttpServletResponse response)
	{
		super(response);
	}
	
	@Override
	public PrintWriter getWriter() throws IOException
	{
		printWriter =  new PrintWriter(new OutputStreamWriter(outputStream,super.getCharacterEncoding()));
		return printWriter;
	}
	
	@Override
	public ServletOutputStream getOutputStream() throws IOException
	{
		return new MyServletOutputStream(outputStream);
	}
	
	public byte[] getOldData()
	{
		if(printWriter != null)
		{
			printWriter.close();
		}
		try
		{
			outputStream.flush();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		return outputStream.toByteArray();
	}
}

class MyServletOutputStream extends ServletOutputStream
{
	private ByteArrayOutputStream outputStream;
	
	public MyServletOutputStream(ByteArrayOutputStream outputStream)
	{
		this.outputStream = outputStream;
	}

	@Override
	public void write(int b) throws IOException
	{
		this.outputStream.write(b);
	}
}

web.xml中的配置

  <filter>
  	<filter-name>GZipFilter</filter-name>
  	<filter-class>com.rk.filter.GZipFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>GZipFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

相关类:

ByteArrayOutputStream类
全名:java.io.ByteArrayOutputStream
(1)这是一个输出流(an output stream),可以将数据(data)转换成字节数组(a byte array)。
This class implements an output stream in which the data is written into a byte array. 
(2)它的缓冲区(buffer)随着数据(data)的写入而不断增长。
The buffer automatically grows as data is written to it. 
(3)可以通过toByteArray()或toString()方法得到数据(data)。
The data can be retrieved using toByteArray() and toString(). 
(4)对ByteArrayOutputStream进行关闭,是没有效果的。
Closing a ByteArrayOutputStream has no effect. The methods in this class can be called after the stream has been closed without generating an IOException.
GZIPOutputStream类
全名:java.util.zip.GZIPOutputStream
This class implements a stream filter for writing compressed data in the GZIP file format.




3.3、动态代理

用动态代理解决GET和POST请求编码的问题

EncodingFilter.java

package com.rk.filter;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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;

/**
 *编码处理统一写到EncodingFilter中(servlet中不需要再处理编码)
 */
public class EncodingFilter implements Filter
{
	//1. 定义私有成员变量filterConfig
	private FilterConfig filterConfig = null;
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		//2.在init方法中获取FilterConfig对象
		this.filterConfig = filterConfig;
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException
	{
		//3. 从filter配置中获取encoding参数
		String characterEncoding = filterConfig.getInitParameter("encoding");
		if(characterEncoding == null)
		{
			characterEncoding = "UTF-8";
		}
		
		final HttpServletRequest request = (HttpServletRequest) req;		
		HttpServletResponse response = (HttpServletResponse) resp;
		
		final String encoding = characterEncoding;		
		request.setCharacterEncoding(encoding);//解决POST请求参数编码
		response.setCharacterEncoding(encoding);//更改响应字符流使用的编码
		response.setContentType("text/html;charset=" + encoding);//更改响应字符流使用的编码,还能告知浏览器用什么格式进行显示
		
		
		//4. 创建动态代理:处理GET请求参数的编码问题
		HttpServletRequest proxy = (HttpServletRequest)Proxy.newProxyInstance(
												request.getClass().getClassLoader(), 		// 指定当前使用的类加载器
												new Class[]{HttpServletRequest.class}, 	// 对目标对象实现的接口类型
												new InvocationHandler()							// 事件处理器
												{
													@Override
													public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
													{
														// 定义方法返回值
														Object result = null;
														// 获取方法名
														String methodName = method.getName();
														// 判断:对getParameter方法进行GET提交中文处理
														if("getParameter".equals(methodName) && request.getMethod()=="GET")
														{
															String str = request.getParameter(args[0].toString());
															if(str == null || str.equals(""))
															{
																result = str;
															}
															else
															{
																result = new String(str.getBytes("ISO8859-1"),encoding);
															}
														}
														else
														{
															result = method.invoke(request, args);
														}
														
														return result;
													}
												});
		// 5.放行 (执行下一个过滤器或者servlet)
		chain.doFilter(proxy, response); // 传入代理对象
	}

	@Override
	public void destroy()
	{
		
	}

}

web.xml中的配置

  <filter>
  	<filter-name>EncodingFilter</filter-name>
  	<filter-class>com.rk.filter.EncodingFilter</filter-class>
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>utf-8</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>EncodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

 

3.4、Filter配置和映射

Filter配置

<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
<filter-class>元素用于指定过滤器的完整的限定类名。
<init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。


Filter映射

<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。


<url-pattern>的一些示例:

1. 拦截所有
<url-pattern>/*</url-pattern>
2. 拦截jsp
<!-- 拦截指定的jsp -->
<url-pattern>/index.jsp</url-pattern>
<url-pattern>/list.jsp</url-pattern>
<!-- 拦截所有的jsp -->
<url-pattern>*.jsp</url-pattern>
3. 拦截servlet
<!-- 根据servlet的内部名称拦截 -->
<servlet-name>IndexServlet</servlet-name>
<!-- 拦截指定的servlet  -->
<url-pattern>/index</url-pattern>
4. 指定拦截指定的类型
<url-pattern>/*</url-pattern>
<!-- 拦截直接访问的请求或者重定向的资源 -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>



<dispatcher> 子元素可以设置的值及其意义:

REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。


4、Filter案例

 

4.1、根据Cookie自动登录

AutoLoginFilter.java 

package com.rk.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;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import sun.misc.BASE64Decoder;

/**
 * @author lsieun
 *用户自动登录的过滤器:这个过滤器,无论用户登录与否,都会放行;其重点是对带有用户登录信息的Cookie进行处理
 *		1、如果用户已经登录(Session当中有用户记录),则不对Cookie进行处理
 *		2、如果用户没有登录(Session当中没有用户记录)
 *				2.1、如果Cookie中含有用户登录信息,则进行登录
 *				2.2、如果没有用户登录信息,则不进行处理
 */
public class AutoLoginFilter implements Filter
{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException
	{
		HttpServletRequest request;
		HttpServletResponse response;
		try{
			request = (HttpServletRequest)req;
			response = (HttpServletResponse)resp;
		}catch(Exception e){
			throw new RuntimeException("non-http request or response");
		}
		//获取Session
		HttpSession session = request.getSession();
		//如果在Session中找不到用户登录信息,则查找Cookie
		if(session.getAttribute("loginInfo") == null)
		{
			Cookie[] cookies = request.getCookies();
			if(cookies != null)
			{
				for(Cookie cookie : cookies)
				{
					//如果Cookie中包含用户登录信息,则自动登录
					if("loginInfo".equals(cookie.getName()))
					{
						String value = cookie.getValue();
						BASE64Decoder base64 = new BASE64Decoder();
						String username = new String(base64.decodeBuffer(value));
						request.getSession().setAttribute("loginInfo", username);//将用户信息保存到Session中
						break;
					}
				}
			}
		}
		chain.doFilter(request, response);
	}

	@Override
	public void destroy()
	{
		
	}

}

web.xml中的配置

  <filter>
  	<filter-name>AutoLoginFilter</filter-name>
  	<filter-class>com.rk.filter.AutoLoginFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>AutoLoginFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

LoginServelt.java

package com.rk.servlet;


import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sun.misc.BASE64Encoder;

public class LoginServelt extends HttpServlet
{

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		PrintWriter out = response.getWriter();
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String uri = request.getParameter("uri");
		
		if("小明".equals(username) && "123456".equals(password))
		{
			request.getSession().setAttribute("loginInfo", username);
			//将用户名进行BASE64编码
			BASE64Encoder base64 = new BASE64Encoder();
			String base64Str = base64.encode(username.getBytes());
			
			//生成Cookie,并保存到response当中
			Cookie cookie = new Cookie("loginInfo", base64Str);
			cookie.setMaxAge(60 * 60);
			response.addCookie(cookie);
			
			//是否进行URL跳转
			if(uri != null && !uri.equals(""))
			{
				response.sendRedirect(uri);
			}
			else
			{
				response.sendRedirect(request.getContextPath() + "/main.jsp");
			}
		}
		
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		this.doGet(request, response);
	}

}


4.2、判断用户是否登录

AuthenticationFilter.java

package com.rk.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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 javax.servlet.http.HttpSession;

/**
 * 登录的过滤器
 * 		1、如果用户访问的当前资源时不需要登录,则放行
 * 		2、如果用户访问的当前资源需要登录
 * 			2.1、如果当前用户已经登录,则放行
 * 			2.2、如果当前用户没有登录,则跳转至登录页面
 *
 */
public class AuthenticationFilter implements Filter
{
	private List<String> listOfUnfilterURI = null;
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		//获取在web.xml中配置的无需登录的资源信息
		String unfilterURI = filterConfig.getInitParameter("unfilteredURI");
		listOfUnfilterURI = Arrays.asList(unfilterURI.split("\\|")) ;
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException
	{
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		
		boolean flag = false;//标识是否放行
		
		//得到用户访问的URI
		String requestURI = request.getRequestURI();
		
		//1、如果用户访问的当前资源时不需要登录,则放行
		if(listOfUnfilterURI != null)
		{
			for(String str : listOfUnfilterURI)
			{
				if(requestURI.contains(request.getContextPath() + str))
				{
					//如果当前资源不需要登录,则将flag设置为true
					flag = true;
					break;
				}
			}
		}
		
		//2、如果用户访问的当前资源需要登录
		if(flag == false)
		{
			HttpSession session = request.getSession(false);
			//2.1、如果当前用户已经登录
			if(session !=null && session.getAttribute("loginInfo")!=null)	
			{
				flag = true;
			}
			//2.2、如果当前用户没有登录(此处不需要写代码,flag默认为false)
		}

		if(flag)
		{
			//放行
			chain.doFilter(request, response);
		}
		else
		{
			//跳转至登录页面
			request.setAttribute("uri", requestURI);
			request.getRequestDispatcher("login.jsp").forward(request, response);
		}
		
	}

	@Override
	public void destroy()
	{
	}

}

web.xml中的配置

 

  <filter>
  	<filter-name>AuthenticationFilter</filter-name>
  	<filter-class>com.rk.filter.AuthenticationFilter</filter-class>
  	<init-param>
  		<param-name>unfilteredURI</param-name>
  		<param-value>/login.jsp|/login</param-value>
  	</init-param>
  </filter>



4.3、对动态资源不进行缓存

DynamicResourceNoCacheFilter.java

package com.rk.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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lsieun
 *控制动态资源不要缓存的过滤器
 */
public class DynamicResourceNoCacheFilter implements Filter
{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException
	{
		HttpServletRequest request = null;
		HttpServletResponse response = null;
		try
		{
			request = (HttpServletRequest) req;
			response = (HttpServletResponse) resp;
		}
		catch (Exception e)
		{
			throw new RuntimeException("non-http request or response");
		}
		
		response.setDateHeader("Expires", -1);
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Pragma", "no-cache");
		
		chain.doFilter(request, response);
	}

	@Override
	public void destroy()
	{
		
	}

}

web.xml中的配置 

  <filter>
  	<filter-name>DynamicResourceNoCacheFilter</filter-name>
  	<filter-class>com.rk.filter.DynamicResourceNoCacheFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>DynamicResourceNoCacheFilter</filter-name>
  	<url-pattern>*.jsp</url-pattern>
  	<dispatcher>REQUEST</dispatcher>
  	<dispatcher>FORWARD</dispatcher>
  </filter-mapping>
  <filter-mapping>
  	<filter-name>DynamicResourceNoCacheFilter</filter-name>
  	<url-pattern>/servlet/*</url-pattern>
  	<dispatcher>REQUEST</dispatcher>
  	<dispatcher>FORWARD</dispatcher>
  </filter-mapping>


4.5、对静态资源进行缓存

StaticResourceCacheFilter.java

package com.rk.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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lsieun
 *控制静态资源的缓存时间
 */
public class StaticResourceCacheFilter implements Filter
{
	private FilterConfig filterConfig;
	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		this.filterConfig = filterConfig;
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException
	{
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		
		String requestURI = request.getRequestURI();
		// 截取后缀名
		String extensionName = requestURI.substring(requestURI.lastIndexOf(‘.‘)+1);
		String strTime = "0";
		// 根据用户访问的资源类型,html css js的缓存时间都不同.
		if("html".equals(extensionName))
		{
			strTime = this.filterConfig.getInitParameter("html");
		}
		else if("css".equals(extensionName))
		{
			strTime = this.filterConfig.getInitParameter("css");
		}
		else if("js".equals(extensionName))
		{
			strTime = this.filterConfig.getInitParameter("js");
		}
		long time = Integer.parseInt(strTime) * 1000 * 60 * 60;// 缓存的时间(单位:毫秒)
		response.setDateHeader("Expires", System.currentTimeMillis() + time);
		chain.doFilter(request, response);
	}

	@Override
	public void destroy()
	{
		
	}

}

web.xml中的配置 

  <filter>
  	<filter-name>StaticResourceCacheFilter</filter-name>
  	<filter-class>com.rk.filter.StaticResourceCacheFilter</filter-class>
  	<init-param>
  		<param-name>html</param-name>
  		<param-value>1</param-value>
  	</init-param>
  	<init-param>
  		<param-name>css</param-name>
  		<param-value>2</param-value>
  	</init-param>
  	<init-param>
  		<param-name>js</param-name>
  		<param-value>3</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>StaticResourceCacheFilter</filter-name>
  	<url-pattern>*.html</url-pattern>
  </filter-mapping>
  <filter-mapping>
  	<filter-name>StaticResourceCacheFilter</filter-name>
  	<url-pattern>*.css</url-pattern>
  </filter-mapping>
  <filter-mapping>
  	<filter-name>StaticResourceCacheFilter</filter-name>
  	<url-pattern>*.js</url-pattern>
  </filter-mapping>



4.6、总结

在一次网络访问中,Tomcat会将请求和回应分别封装为request和response,而Filter能够起作用,正是对request和response中的信息加以利用。例如:

(1)用Filter解决字符乱码的问题,是对request和response中的字符编码进行设置;

(2)用Filter判断是否自动登录,是对request中Cookie信息进行处理;

(3)用Filter判断用户是否登录,是对request中Session进行处理;

(4)用Filter对动态资源(JSP、Servlet)不进行缓存,是对response的响应头进行处理;

(5)用Filter对静态资源(HTML、JS、CSS)进行缓存,也是对response的响应头进行处理;

(6)用Filter对响应内容进行GZIP压缩,是对response的响应体进行处理。

通过上述这几个经典应用,可以总结出:Filter只是利用request和response的信息进行预先或滞后处理,解决一些通用性的问题,并不会处理业务逻辑的内容。

在网络编程中,一般是先对request(输入)进行处理,再对response(输出)进行处理;当存在多个Filter的时候,也应该把处理request的Filter放在前面,处理response的Filter放在后面。

如果让我进行排序,我就这样排序:字符编码>自动登录>用户是否登录>动态资源不缓存>静态资源缓存>内容GZIP压缩。



Filter编程:(2)Filter进阶

标签:filter

原文地址:http://lsieun.blog.51cto.com/9210464/1788886

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!