Filter编程:(2)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压缩。

时间: 2024-08-25 10:54:55

Filter编程:(2)Filter进阶的相关文章

Python学习:映射函数(map)和函数式编程工具(filter和reduce)

在序列中映射函数map map函数会对一个序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表. 例1: def sum(x):     return x + 10 L1 = [1,2,3,4,5,6,7] L = map(sum, L1) #结果为[11, 12, 13, 14, 15, 16, 17] map还有更高级的使用方法,例如提供了序列作为参数,它能够并行返回分别以每个序列中的元素作为函数对应参数得到的结果的列表.如例2所示. 例2: def sum(

DirectShow基础编程 源Filter CSource CSourceStream (转)

DirectShow是微软定义的一套接口集合,由不同的接口组成,例如:IBaseFilter,IPin.这些接口之间的关系形成了DirectShow的架构. DirectX SDK提供了一个C++的BaseClasses,是这些接口的实现.这些实现已经很成熟完善,因此我们不需要重新开发一套类库去实现DirctShow的接口,直接使用就可以. DirectShow编程就是Filter编程,根据功能实现不同的Filter.推模式的源Filter一般从CSource派生,在派生类中实现特殊的功能,而C

Filter编程:(1)Filter基础

Filter简介 从功能角度来说,Filter能做什么? 从API角度来说,如何实现Filter? 从原理角度来说,Filter是如何实现拦截的? Filter生命周期和Filter链 Filter生命周期的三个方法:init.doFilter和destory Filter链及其调用顺序 Filter高级开发 HttpServletRequestWrapper HttpServletResponseWrapper 动态代理 Filter映射 Filter案例 1.Filter简介 1.1.从功能

.net mvc Authorization Filter,Exception Filter与Action Filter

一:知识点部分 权限是做网页经常要涉及到的一个知识点,在使用MVC做权限设计时需要先了解以下知识: MVC中Url的执行是按照Controller->Action->View页面,但是我们经常需要在函数执行所指定的Action之前或者action方法之后处理一些逻辑,为了处理这些逻辑,ASP.NET MVC允许你创建action过滤器Filter,我们都知道在Action上使用的每一个 [Attribute]大都是自定义的Filter. mvc提供四种类型的Filter接口:IActionFi

JavaWeb-过滤器Filter学习(一)Filter知识点

Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信息.自动登录等一些高级功能. Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter.

小米面经-技术岗(编程小白如何进阶)

先介绍下背景,我本科专业是硬件转软件方面,所以一开始算法基础比较差,没有做过系统设计,为了能得到好的面试机会,我一直都有努力准备,还在网上关注了各种能提高编程能力的攻略,我觉得打好基础的前提是要找到优质的学习资源,这样才能事半功倍,切忌在网上搜一些质量参差不齐的题去练习,有的连答案都不知道对不对,更别提对面试有帮助了. 我对比了几家刷题的网站,最后选了Lintcode(http://www.lintcode.com/).题目基本上涵盖了所有IT公司面试会面到的算法题,推荐给想刷题的小伙伴们,建议

Filter 字符编码Filter 一

使用字符编码Filter package com.helloweenvsfei.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;

filter的用法filter过滤器

1.过滤器的概念 Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应. 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链. 优点:过滤链的好处是,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容.而在实际使用时,就要特别注意过滤链的执行顺序问题 2.过滤器的作用描述 在HttpServletRequ

JavaEE---过滤器Filter ,过滤器Filter的实现与部署,编码案例+权限案例

过滤器是一种Web组件,用于对客户端发送的请求信息和返回给客户端的响应信息进行处理.  过滤器Filter的工作原理 ---通过使用过滤器,可以拦截客户端的请求和响应,查看 .提取或者以某种方式操作正在客户端和服务器之间进行交换的数据. ---通过使用过滤器,可以对Web组件的前期处理和后期处理进行控制. ---过滤器可以有多个,以构成一个过滤器链.Servlet容器会根据过滤器的配置情况来决定过滤器的调用次序. 过滤器Filter的实现和部署 ---必须实现接口javax.serclet.Fi