Filter(过滤器)

本文详细介绍了Java Web中的Filter过滤器,包括其用途、编写步骤、工作原理及如何在web.xml中配置。Filter主要用于解决中文乱码、权限控制等问题,通过拦截web资源请求并预处理。文中给出了一个解决中文乱码问题的Filter应用实例,通过装饰者模式对GET请求进行编码处理。同时,还讨论了多个Filter的执行顺序以及Filter拦截资源的多种调用方式。
摘要由CSDN通过智能技术生成

1.什么是Filter

Filter也称之为过滤器,可以对web服务器管理的所有web资源:例如Jsp、Servlet、html文件等进行拦截,从而实现一些特殊的功能。

Filter的用途

  1. 解决中文乱码问题
  2. 权限访问控制
  3. 过滤敏感词汇
  4. 压缩响应信息

2.编写过滤器

实现过滤器需要两个步骤:

  1. 编写Java类实现Filter接口
  2. 在web.xml文件中注册Filter,并设置它需要拦截的资源。
package com.mbc.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;

public class MyFilter implements Filter {
	/**
	 * init()属于Filter的生命周期方法。当web应用程序启动时,web服务器将创建Filter的实例对象,
	 * 调用init方法,完成对象的初始化功能,从而能对用户的请求进行拦截。Filter对象只会创建一次,因此
	 * init方法也只会执行一次。init方法的参数:FilterConfig对象,封装了当前filter的配置信息,由服务器
	 * 根据web.xml中的相应的配置信息来生成。
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("过滤器初始化了。。。");
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		//对request和response进行一些预处理
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html; charset=UTF-8");
		System.out.println("我是目标资源执行之前运行的代码...");
		chain.doFilter(request, response);//让目标资源执行,放行
		System.out.println("我是目标资源执行之后,响应回给客户端时经过过滤器运行的代码...");
	}

	/**
	 * destroy()属于Filter的生命周期方法。在服务器关闭之前执行,仅执行一次,
	 * 用于释放过滤器使用的资源
	 */
	public void destroy() {
		System.out.println("过滤器销毁了。。。");
	}
}

在web. xml中配置Filter

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.mbc.filter.MyFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Filter是如何实现拦截的

当我们编写好Filter并配置好Filter要对哪些web资源拦截后,当用户需要访问配置有Filter的web资源时,web服务器每次在调用web资源的service方法之前会调用Filter的doFilter方法。该方法中可以决定是否过滤掉用户的请求。web服务器调用Filter的doFilter方法时,会传递一个FilterChain的对象进来,它也提供了一个doFilter方法,开发人员根据需求决定是否调用此方法(chain.doFilter(request, response);)。若调用,web服务器通过调用web资源的service方法,用户就可以访问到请求的资源,否则就访问不了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hPJTdnDU-1647351835745)(https://note.youdao.com/yws/api/personal/file/E8C416348CC9417BB3F4567570D48154?method=download&shareKey=55e51c36407cb87b5644aa6538581dff)]

Filter中doFilter()的代码执行如下

  1. 调用目标资源前,让一段代码执行
  2. 是否调用目标资源(即是否有FilterChain对象的doFilter方法)
  3. 调用目标资源后,响应回给客户端时经过Filter时执行的代码

即若用户对web资源的访问通过Filter的过滤后,服务器对用户的访问进行响应时还需要执行chain.doFilter(request, response)下的代码。

如图所示:图片来自javaweb学习总结(四十二)——Filter(过滤器)学习

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8sgdmh1-1647351835746)(https://note.youdao.com/yws/api/personal/file/43EAB66EF6054E60885E33EC0F94BF40?method=download&shareKey=7e68e4c85c21f0bdd40c377ade451385)]


3.Filter的部署

Filter分为两个步骤

  1. 注册Filter
  2. 映射Filter

1. 注册Filter

<filter>
          <description>过滤器的描述</description>
          <filter-name>MyFilter</filter-name>
          <filter-class>com.mbc.filter.MyFilter</filter-class>
          <!--配置FilterDemo02过滤器的初始化参数-->
          <init-param>
              <description>配置过滤器的初始化参数</description>
              <param-name>name</param-name>
              <param-value>mbc</param-value>
          </init-param>
          <init-param>
              <description>配置初始化参数</description>
              <param-name>age</param-name>
              <param-value>18</param-value>
          </init-param>
</filter>

说明:

  • <description>:用于添加描述信息,可以不配置
  • <filter-name>:用于指定Filterd的名称
  • <filter-class>:用于指定过滤器的完整类名
  • <init-param>:用于为过滤器指定初始化参数,可以有多个。它的子元素<param-name>指定参数的名字,<parm-value>指定参数的值。此元素可以不配置。通过FilterConfig对象访问初始化参数,类似Servlet的ServletConfig。

2. 映射Filter

<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

说明:

  • <filter-mapping>:元素用于设置一个Filter所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet名称和资源访问的请求路径

  • <filter-name>:子元素用于设置filter的注册名称。该值必须是在元素中声明过的过滤器的名字

  • <url-pattern>:设置filter所拦截的请求路径

  • <servlet-name>:指定过滤器所拦截的Servlet名称。

  • <dispatcher>:指定过滤器所拦截的资源被Servlet容器调用的方式,可以是

    • REQUEST:只要是请求过来,都拦截,默认就是REQUEST

    • FORWARD: 只要是转发都拦截

    • ERROR: 页面出错发生跳转时拦截

    • INCLUDE:包含页面的时候就拦截

可以设置多个子元素用来指定Filter对资源的多种调用方式进行拦截


4.多个Filter的执行顺序

如果有多个过滤器,那么他们会按照注册的映射顺序执行,即根据web.xml中元素的配置顺序。只要有一个过滤器不放行,那么后面排队的过滤器不会收到请求。


5.Filter应用实例

解决中文乱码问题

这里使用装饰者模式,对GET请求进行装饰。包括以下文件:

  1. index.html:发送get、post请求的界面
  2. EncodingFilter:过滤器,对所有的请求进行编码处理
  3. IndexServlet:Servlet,测试是否能得到正确的数据
  4. EncodingRequestImpro:装饰类,对get请求的getParameterMap()、getParameterValues()、getParameter()进行装饰(编码处理)

1.index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<a href="IndexServlet?name=张三&hobby=游泳">通过get提交中文数据</a>
	<form method="post" action="IndexServlet">
		<input name="name" value="张三">
		<input name="hobby" value="游泳">
		<input type="submit" value="提交">
	</form>
</body>
</html>

2.EncodingFilter

package com.mbc.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 com.mbc.servlet.EncodingRequest;
import com.mbc.servlet.EncodingRequestImpro;

public class EncodingFilter implements Filter {


	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		
		if(req.getMethod().equals("GET")) {
		    HttpServletRequest req = (HttpServletRequest) request;    
			//对请求进行装饰
			EncodingRequestImpro encodingRequest = new EncodingRequestImpro(req);
			//装饰完后放行
			chain.doFilter(encodingRequest, response);
		}else if(req.getMethod().equals("POST")) {
			request.setCharacterEncoding("UTF-8");
			chain.doFilter(request, response);
		}
		
	}

	public void init(FilterConfig fConfig) throws ServletException {
	}

	public void destroy() {
	}
}

EncodingFilter部署

<filter>
    <display-name>EncodingFilter</display-name>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>com.mbc.filter.EncodingFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern><!--对所有请求都拦截-->
    <dispatcher>REQUEST</dispatcher>
 </filter-mapping>

3.EncodingRequestImpro

package com.mbc.servlet;

import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class EncodingRequestImpro extends HttpServletRequestWrapper {
	private HttpServletRequest request = null;
	private boolean flag = false;	//用于标记map是否被编码过了
	
	public EncodingRequestImpro(HttpServletRequest request) {
		super(request);
		this.request = request;
	}
	
	@Override
	public Map<String, String[]> getParameterMap() {
		Map<String, String[]> map = request.getParameterMap();
		if(map != null && flag == false) {
			flag = true;
			Set<String> keySet = map.keySet();
			for (String key : keySet) {
				String[] values = map.get(key);
				for(int i = 0; i < values.length; i++) {//对作用域中map中的值重新编码
					try {
						values[i] = new String(values[i].getBytes("ISO-8859-1"), "UTF-8");
					} catch (UnsupportedEncodingException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return map;
	}
	
	@Override
	public String[] getParameterValues(String name) {
		Map<String, String[]> map = this.getParameterMap();//调用正确编码的map
		if(map != null) {
			return map.get(name);
		}
		return null;
	}
	
	@Override
	public String getParameter(String name) {
		String[] values = this.getParameterValues(name);
		if(values != null) {
			return values[0];
		}
		return null;
	}
}
	
  1. IndexServlet
package com.mbc.servlet;

import java.io.IOException;
import java.util.Map;

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

public class IndexServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String name = request.getParameter("name");
		String hobby = request.getParameter("hobby");
		String[] values = request.getParameterValues("name");
		Map<String, String[]> map = request.getParameterMap();
		
		System.out.println("--------------");//检查getParameterValues()得到的是否是乱码
		for (String string : values) {
			System.out.println("values = " + string);
		}
		
		System.out.println("--------------");//检查getParameterMap()得到的是否是乱码
		for(Map.Entry<String, String[]> entry : map.entrySet()) {
			System.out.println(entry.getKey() + " = " + entry.getValue()[0]);
		}
		
		System.out.println("-----------------");//检查getParameter得到的是否是乱码
		System.out.println("name = "+name + "hobby = " + hobby);
		
	}

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

}


参考:

javaweb学习总结(四十二)——Filter(过滤器)学习

JavaWeb三大组件之过滤器(Filter)

使用过滤器(Filter)解决请求参数中文乱码问题(复杂方式)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值