概述
- JavaWeb三驾马车:Servlet,Filter,Linstener
- Filter也称之为过滤器,对 Servlet 容器调用 Servlet 的过程(请求与响应)进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊功能
- Servlet API 中定义三个接口供编写Filter:Filter,FilterChain,FilterConfig
- Filter 程序是一个实现Filter接口的Java类,与 Servlet 程序相似,由 Servlet 容器调用与执行
- Filter 程序需在 web.xml 文件中进行注册和设置它所能拦截的资源(jsp,Servlet,静态资源等)
创建
- eclipse创建
- 右键 → new → Filter → 包名,类名 → next → Filter mappings中输入要过滤的路径 → next → interfaces选择要实现的接口
- 会自动在 web.xml 文件中注册映射
生命周期
- 第1步 访问url-parttern, 里面是/* 匹配的是所有的资源
- 第2步 找到filter-name元素,之后查找filter 元素里面的同名filter-name
- 第3步 通过filter-name 找到 filter-class(包名.类名)
- 第4步 创建EncodingFilter类的对象,执行init方法
- 第5步 执行doFilter方法,在doFilter方法中,进行逻辑处理, 也可以判断是否放行 //chain.doFilter(request, response); 表示放行
- 第6步 不再使用,销毁的时候,调用destroy方法销毁
Filter接口
- void init(FilterConfig filterConfig)
- 类似于Servlet的init方法,Servlet容器加载web应用后即创建Filter对象,在创建Filter对象后立即被调用,且只调用一次,用于对Filter进行初始化操作
- web.xml中标签
- <filter>:注册Filter
- <filter-name>:Filter名
- <filter-class>:Filter地址
- <init-param>:Filter初始化参数
- <param-name>:初始化参数名
- <param-value>:初始化参数值
- <filter-mapping>:映射Filter
- <filter-name>:Filter名
- <url-pattern>:Filter映射地址,可多个
- <servlet-name>:指定过滤器所拦截的Servlet名
- <dispatcher>:指定过滤器所拦截的资源被Servlet容器调用的什么方式才执行
- 默认为REQUEST请求(RequestDispatcher的include()方法或forward()方法)
- INCLUDE(RequestDispatcher的include()方法)
- FORWARD转发(RequestDispatcher的forward()方法)
- ERROR(声明式异常处理机制调用//jsp跳转到错误页面)
- 可多个
- void doFilter(ServletRequest request,ServletResponse response, FilterChain chain))
- 类似于Servlet的service方法,编写逻辑代码
- FilterChain:Filter链,多个Filter可构成Filter链
- void destroy()
- 类似于Servlet的destroy方法
- 释放当前Filter所占用的资源,在Filter被销毁之前被调用,且只调用一次
FilterChain接口
- 代表当前Filter链对象,由容器实现,将其作为参数传入过滤器对象的doFilter方法,使用FilterChain对象调用过滤器链中的下一个过滤器,直到最后一个后交给目标Servlet
- void doFilter(ServletRequest request,ServletResponse response)
- 把请求交给Filter链的下一个Filter,直到最后一个后交给目标Servlet,在执行最后一个Filter未执行代码,直到第一个Filter结束,用于放行过滤代码
- 多个Filter拦截顺序和<filter-mapping>配置的顺序有关
FilterConfig接口
- 类似于ServletConfig接口,由容器实现,将其作为参数传入过滤器对象的init方法,ServletContext对象和Filter的配置参数信息封装在该对象中
- String getFilterName() //获取过滤器名
- String getInitParameter(String name) //获取指定名的初始化参数值
- Enumeration getInitParameterNames() //获取所有过滤器初始化参数值的枚举集合
- ServletContext getServletContext() //获取Servlet上下文对象引用
HttpServletRequestWrpper类
- 使用场景
- 当我们在使用filter的时候却会发现至少有一半的时间我们都想改变HttpServletRequest对象的参数。如:用filter在HttpServletRequest对象到达Servlet之前将用户输入的空格去掉。但是由于java.util.Map包装的HttpServletRequest对象的参数是不可改变的,要怎样改变从Servlet容器中传入的HttpServletRequest对象的某个行为?
- ①继承HttpServletRequest接口的Servlet容器的实现类,但就和具体的容器相耦合
- ②提供HttpServletRequest接口的实现类,需要和具体的容器相耦合,且麻烦
- ③使用装饰器设计模式:提供一个类实现HttpServletRequest接口,传入具体的一个容器实现的HttpServletRequest接口的实现类作为上述类的成员变量,使用HttpServletRequest成员变量来实现所有方法
- 使用
- HttpServletRequestWrapper类是HttpServletRequest类的装饰类,包装原始的request对象
- 相似的HttpServletResponseWrapper类包装原始的response对象
- 想要改变在httpServletRequest中的参数,可以通过httpServletRequest的装饰类HttpServletRequestWrapper来实现,只需要在装饰类中按照需要重写其getParameter(getParameterValues)方法即可
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
HttpServletRequest orgRequest = null;
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
orgRequest = request;
}
@Override
public String getParameter(String name) {
String value = super.getParameter(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(xssEncode(name));
if (value != null) {
value = xssEncode(value);
}
return value;
}
private static String xssEncode(String s) {
if (s == null || "".equals(s)) {
return s;
}
StringBuilder sb = new StringBuilder(s.length() + 16);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '>':
sb.append('>');
break;
case '<':
sb.append('<');
break;
case '\'':
sb.append('‘');
break;
case '\"':
sb.append('“');
break;
case '&':
sb.append('&');
break;
case '\\':
sb.append('\');
break;
case '#':
sb.append('#');
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
}
public HttpServletRequest getOrgRequest() {
return orgRequest;
}
public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
if (req instanceof XssHttpServletRequestWrapper) {
return ((XssHttpServletRequestWrapper) req).getOrgRequest();
}
return req;
}
public static void main(String[] args) {
System.out.println(XssHttpServletRequestWrapper.xssEncode("<script>alert(1)</script>"));
}
}
public class XssFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain Chain) throws IOException , ServletException {
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest)request);
Chain.doFilter(xssRequest, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}