1.什么是Filter
Filter也称之为过滤器,可以对web服务器管理的所有web资源:例如Jsp、Servlet、html文件等进行拦截,从而实现一些特殊的功能。
Filter的用途
- 解决中文乱码问题
- 权限访问控制
- 过滤敏感词汇
- 压缩响应信息
2.编写过滤器
实现过滤器需要两个步骤:
- 编写Java类实现Filter接口
- 在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()的代码执行如下
- 调用目标资源前,让一段代码执行
- 是否调用目标资源(即是否有FilterChain对象的doFilter方法)
- 调用目标资源后,响应回给客户端时经过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分为两个步骤
- 注册Filter
- 映射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请求进行装饰。包括以下文件:
- index.html:发送get、post请求的界面
- EncodingFilter:过滤器,对所有的请求进行编码处理
- IndexServlet:Servlet,测试是否能得到正确的数据
- 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;
}
}
- 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);
}
}
参考: