Filter(过滤器)简介:
- Filter的基本功能是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet 进行响应处理的前后实现一些特殊的功能。
- 在 Servlet API 中定义了三个接口类来开供开发人员编写Filter程序: Filter, FilterChain, FilterConfig
- Filter程序是-个实现了Filter接口的Java类,与Servlet程序相似,它由Servlet容器进行调用和执行
- Filter程序需要在web.xml文件中进行注册和设置它所能拦截的资源: Filter 程序可以拦截Jsp, Servlet,静态图片文件和静态html文件
Filter 基本工作原理
-
当在 web.xml 中注册了一个 Filter 来对某个 Servlet 程序进行拦截处理时,这个 Filter 就成了 Servlet 容器与该 Servlet 程序的通信线路上的一道关卡,该 Filter 可以对 Servlet 容器发送给 Servlet 程序的请求和 Servlet程序回送给 Servle t容器的相应进行拦截,可以决定是否将请求继续传递给 Servlet 程序,以及对请求和相应信息是否进行修改
-
在一个web应用程序中可以注册多个Filter 程序,每个 Filter 程序都可以对一个或一组 Servlet 程序进行拦截。
-
若有多个Filter程序对某个Servlet程序的访问过程进行拦截,当针对该Servlet 的访问请求到达时,web 容器将把这多个 Filter 程序组合成一个Filter链(过滤器链)。Filter 链中各个Filter的拦截顺序与它们在应用程序的web.xml中映射的顺序一致
Filter 接口
-
Web 容器创建Filter对象实例后,将立即调用该 Filter 对象的 init 方法。Init 方法在 Filter 生命周期中仅执行一次,web 容器在调用 init 方法时,会传递一个包含 Filter 的配置和运行环境的 FilterConfig 对象 (FilterConfig 的用法和 ServletConfig 类似)。利用 FilterConfig 对 象可以得到ServletContext 对象,以及部署描述符中配置的过滤器的初始化参数。在这个方法中,可以抛出 ServletException 异常,通知容器该过滤器不能正常工作。
-
destroy() :在Web容器卸载Filter对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源
-
与开发Servlet不同的是,Filter接口并没有相应的实现类可供继承,要开发过滤器,只能直接实现 Filter 接口。
FilterConfig接口
- javax.servlet. FilterConfig 接口 :该接口类似于 ServletConfig 接口,由容器实现。Servlet 规范将代表 ServletContext 对象和 Filter 的配置参数信息都封装在该对象中。Servlet 容器将其作为参数传入过滤器对象的 init() 方法中。
- String getFilterName() :得到描述符中指定的过滤器的名字。
- String getlnitParameter(String name) :返回在部署描述中指定的名字为name的初始化参数的值。如果不存在返回 null.
- Enumeration getlnitParameterNames() :返回过滤器的所有初始化参数的名字的枚举集合。
- public ServletContext getServletContext() :返回 Servlet 上下文对象的引用。
Filter 是什么
- JavaWEB的一一个重要组件,可以对发送到Servlet的请求进行拦截,并对响应也进行拦截.
- Filter是实现了Filter 接口的Java类.
- Filter 需要在web.xml文件中进行配置和映射.
创建一个 Filter
- 创建一个 Filter 类,实现接口: Filter
第一个Filter 过滤不正确的用户名
public class FilterLogIn implements Filter {
//得到一个 filterConfig
FilterConfig filterConfig = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//得到 配置文件中的初始化 用户名
String initUser = filterConfig.getInitParameter("userName");
//得到请求参数中的用户名
String userName = request.getParameter("userName");
//判断是否相等
if (!initUser.equals(userName)) {
request.setAttribute("message", "用户名不正确");
//用户名不相等返回登陆界面
request.getRequestDispatcher("/login.jsp").forward(request, response);
return ;
}
//用户名正确 放行
chain.doFilter(request, response);
}
第二个 Filter 过滤不正确的密码(原理同上)
public class FilterLogInPass implements Filter {
FilterConfig filterConfig = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String initPassword = filterConfig.getInitParameter("password");
String password = request.getParameter("password");
if (!initPassword.equals(password)) {
request.setAttribute("message", "密码不正确");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return ;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
- 注册 Filter(web.xml)
<!-- 配置的登陆的 filter -->
<!-- 检查账号 -->
<filter>
<filter-name>logFilter</filter-name>
<filter-class>com.athome.filterLogIn.FilterLogIn</filter-class>
<init-param>
<param-name>userName</param-name>
<param-value>Tom</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>logFilter</filter-name>
<url-pattern>/success.jsp</url-pattern>
</filter-mapping>
<!-- 检查密码 -->
<filter>
<filter-name>logFilterPass</filter-name>
<filter-class>com.athome.filterLogIn.FilterLogInPass</filter-class>
<init-param>
<param-name>password</param-name>
<param-value>root</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>logFilterPass</filter-name>
<url-pattern>/success.jsp</url-pattern>
</filter-mapping>
- jsp 文件
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 回显 -->
<font color="red">${requestScope.message }</font>
<br><br>
<form action="success.jsp" method="post">
UserName:<input tyep="text" name="userName" value="${param.userName }">
Password:<input type="password" name="password">
<input type="submit" value="Submit">
</form>
</body>
</html>
success.jsp中
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4>Hello:${param.userName }</h4>
</body>
</html>
自实现 HttpFilter 类
目的:简洁public abstract class HttpFilter implements Filter{
/**
* 用于保存 FilterConfig 对象
*/
FilterConfig filterConfig;
/**
* 不建议子类直接覆盖,若直接覆盖,可能会导致 filterConfig 成员变量初始化失败
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
init();
}
/**
* 供子类继承的初始化方法,可以通过 getFilterConfig() 获取 FilterConfig 对象
*/
protected void init() {}
/**
* 直接返回 init(FilterConfig) 的 filterConfig 对象
* @return
*/
public FilterConfig getFilterConfig() {
return filterConfig;
}
/**
* 原生的 doFilter 方法,在方法内部把ServletRequest 和 ServletResponse
* 转化成立HttpServletRequest 和 HttpServletResponse,并调用了
* doFilter(HttpServletRequest request,HttpServletResponse response,FilterChain chain)
* 不建议直接继承该方法
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request2 = (HttpServletRequest) request;
HttpServletResponse response2 = (HttpServletResponse) response;
doFilter(request2,response2,chain);
}
/**
* 抽象方法,为Http 请求定制,必须实现的方法
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
*/
abstract public void doFilter(HttpServletRequest request,HttpServletResponse response,
FilterChain chain)throws IOException, ServletException ;
/*
* 空的destroy() 方法
*/
@Override
public void destroy() { }
}
练习1
fiilter 中:
/**
* Servlet Filter implementation class CacheFilter
*/
@WebFilter("/cache/*")
public class CacheFilter extends HttpFilter {
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
//去除页面缓存
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
//放行
chain.doFilter(request, response);
}
}
jsp中:
A.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="B.jsp">Goto PageB</a>
<br><br>
<img alt="" src="timg.jpg">
</body>
</html>
B.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="A.jsp">GoTo PageA</a>
</body>
</html>
练习2
解决方案一: 在每个 调用前加上 request.setCharacterEncoding(“utf-8”);
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
//第一种方式
request.setCharacterEncoding("utf-8");
%>
</body>
</html>
第二种方式:使用过滤器
filter 中
@WebFilter("/encode/*")
public class EncodingFilter extends HttpFilter {
private String encode;
@Override
protected void init() {
//得到编码值
encode = getFilterConfig().getServletContext().getInitParameter("encoding");
System.out.println(encode);
}
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
//设置编码方式
request.setCharacterEncoding(encode);
//放行
chain.doFilter(request, response);
}
}
在 web.xml 中 设置web 应用的初始化参数
<context-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</context-param>
jsp 中:
logIn.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="secc.jsp" method="post">
UserName:<input type="text" name="username">
<input type="submit" value="Submit">
</form>
</body>
</html>
succ.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
Hello: ${param.username }
</body>
</html>
补充 dispatcher 元素
dispatcher 元素 : 值定过滤器所拦截的资源被servlet 容器调用的方式 可以是REQUEST, INCLUDE, FORWARD和ERROR之-一,默认REQUEST.-
REQUEST: 当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过 RequestDispatcher的include( ) 或 forward( ) 方法访问,或通过GET或POST请求直接访问。
-
FORWARD: 如果目标资源是通过 RequestDispatcher 的 forward( ) 方法访问时,那么该过滤器将被调用,或**< jsp:forward page="/…" />** 或通过 page 指令的 errorPage 转发页面. <%@ page errorPage=“test.jsp” %>
-
INCLUDE: 如果目标资源是通过 RequestDispatcher 的 include( ) 方法访问时或 <jsp:include file="/…" />,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
-
ERROR :如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
在web.xml文件中通过error-page节点进行声明:
<error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location> /test.jsp </location>
</error-page>
<filter-mapping>
< filter-name> secondFilter </filter-name>
<url-pattern> /test.jsp </url-pattern>
<dispatcher> REQUEST </dispatcher>
<dispatcher> FORWARD </dispatcher>
<dispatcher>INCLUDE </dispatcher>
<dispatcher> ERROR </dispatcher>
</filter-mapping>