Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、自动登录、压缩响应信息等一些高级功能。
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示:
自定义filter
public class FilterDemo1 implements Filter{
//销毁方法
publicvoid destroy() {
//TODO Auto-generated method stub
}
//执行方法
publicvoid doFilter(ServletRequest request, ServletResponse response,
FilterChainchain) throws IOException, ServletException {
//TODO Auto-generated method stub
System.out.println("doFilter");
}
//初始方法
publicvoid init(FilterConfig arg0) throws ServletException {
//TODO Auto-generated method stub
}
}
ShowServletprotectedvoid doGet(HttpServletRequest request, HttpServletResponseresponse) throws ServletException, IOException {
// TODO Auto-generatedmethod stub
//设置编码
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("欢迎学习servlet下篇!");
}
在web.xml中配置filter<!-- filter放在servlet的上面 -->
<filter>
<filter-name>FilterDemo1</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<!-- /*表示拦截所有,/表示项目名称,*代表所有 -->
<!-- 不是用户访问的,指的是filter拦截所有资源 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ShowServlet</servlet-name>
<servlet-class>cn.itcast.web.servlet.ShowServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ShowServlet</servlet-name>
<url-pattern>/ShowServlet</url-pattern>
</servlet-mapping>
访问网站会先转到过滤器
过滤器工作原理:
放行请求:
//放行请求
chain.doFilter(request,response);
chain.doFilter(request,response)具有二义性:
>>如果有下一个Filter时,将请求转发给下一个Filter
>>如果无下一个Filter时,将请求转发给Web资源(serlvet/jsp/html)
filter执行顺序:
//执行方法
publicvoid doFilter(ServletRequest request, ServletResponseresponse,
FilterChain chain) throws IOException, ServletException{
// TODO Auto-generatedmethod stub
System.out.println("A");
//放行请求,类似于函数调用
chain.doFilter(request, response);
System.out.println("B");
}
Filter2
publicvoid doFilter(ServletRequest request, ServletResponseresponse,
FilterChain chain) throws IOException, ServletException{
// TODO Auto-generatedmethod stub
System.out.println("C");
chain.doFilter(request, response);
System.out.println("D");
}
在web.xml中配置(filter配置应在sevlet配置的上面,配置在前面的filter会先执行)
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<!-- /*表示拦截所有,/表示项目名称,*代表所有 -->
<!-- 不是用户访问的,指的是filter拦截所有资源 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>FilterDemo2</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo2</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo2</filter-name>
<!-- /*表示拦截所有,/表示项目名称,*代表所有 -->
<!-- 不是用户访问的,指的是filter拦截所有资源 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
filter提取公共代码:
publicvoid doFilter(ServletRequest request, ServletResponseresponse,
FilterChain chain) throws IOException, ServletException{
// TODO Auto-generatedmethod stub
chain.doFilter(request, response);
}
filter2
publicvoid doFilter(ServletRequest request, ServletResponseresponse,
FilterChain chain) throws IOException, ServletException{
// TODO Auto-generatedmethod stub
//设置编码,公共代码
response.setContentType("text/html;charset=UTF-8");
}
ShowServlet,这里就不用再设置编码了,因为在过滤器中已经设置
protectedvoid doGet(HttpServletRequest request, HttpServletResponseresponse) throws ServletException, IOException {
// TODO Auto-generatedmethod stub
response.getWriter().write("欢迎学习servlet下篇!");
}
在showServlet不用再过滤中文乱码问题
2 过滤器简介(过滤器的配置要写在servlet的前面)
a)Filter是SUN公司提供的一个资源过滤器接口,不同的Web容器有着不同的实现
b)Filter位于Web服务器和Web资源(Servlet/Jsp/Html)之间
c)过滤请求和响应二者
d)Filter可以进行简单判段,是否将请求放行给Web资源
e)Filter的开发过程:
>>类 implements javax.servlet.Filter接口
>>在web.xml文件配置Filter过滤器,告之Web服务器有过滤器的存在
web.xml中的配置信息如下:
<filter>
<filter-name>FilterDemo1</filter-name>(过滤器,可以随意,但要和filter-mapping中的name一致)
<filter-class>cn.itcast.web.filter.FilterDemo1</filter-class>(过滤器全路径)
</filter>
<filter-mapping>
<filter-name>FilterDemo1</filter-name>(过滤器名,同上)
<url-pattern>/*</url-pattern>(过滤器能够过滤的资源路径,不是用户在URL中访问的路径)
</filter-mapping>
3 过滤器链
a)一个Web应用可以有0个或多个Filter,多个Filter的组合就是过滤器链
b)多个Filter的执行先后顺序,与web.xml文件中配置的顺序有关
c)chain.doFilter(request,response)具有二义性:
>>如果有下一个Filter时,将请求转发给下一个Filter
>>如果无下一个Filter时,将请求转发给Web资源(serlvet/jsp/html)
d)可以将web资源中的一些公共代码,提取出来,放入Filter中
4 过滤器生命周期
空参构造() 1次
init() 1次
doFilter(请求,响应,过滤器链) N次,与请求次数有关
destory() 1次
Filter是一个单例
//单例
publicclass FilterDemo3 implements Filter{
private FilterConfig filterConfig;
//构造函数:执行一次
public FilterDemo3() {
System.out.println("构造:"+this.hashCode());
}
//销毁方法:执行一次
publicvoid destroy() {
// TODO Auto-generatedmethod stub
System.out.println("destroy:"+this.hashCode());
}
//N次,与请求有关,web容器调用
publicvoid doFilter(ServletRequest request, ServletResponseresponse,
FilterChain chain) throws IOException, ServletException{
// TODO Auto-generatedmethod stub
Enumeration<String>enums=filterConfig.getInitParameterNames();
while(enums.hasMoreElements()){
String key=enums.nextElement();
String value=filterConfig.getInitParameter(key);
System.out.println(key+":"+value);
}
System.out.println("doFilter:"+this.hashCode());
String encoding=filterConfig.getInitParameter("encoding");
System.out.println(encoding);
response.setContentType("text/html;charset="+encoding);
chain.doFilter(request, response);
}
//初始化filter,执行一次
publicvoid init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generatedmethod stub
System.out.println("init:"+this.hashCode());
this.filterConfig=filterConfig;
}
web.xml中配置
<filter>
<filter-name>FilterDemo3</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo3</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>email</param-name>
<param-value>jack@163.com</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterDemo3</filter-name>
<!-- /*表示拦截所有,/表示项目名称,*代表所有 -->
<!-- 不是用户访问的,指的是filter拦截所有资源 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
当访问一个web资源时,没有得到对应的结果,有可能是Filter没有放行资源
b)静态资源和动态资源进行不同的缓存处理,代码如下:
if(uri!=null&& uri.endsWith("jsp")){
//NO3如果是动态资源,设置三个响应头通知浏览器不缓存
response.setHeader("expires","-1");
response.setHeader("cache-control","no-cache");
response.setHeader("pragma","no-cache");
}else if(uri!=null &&uri.endsWith("html")){
//NO4如果是静态资源,缓存一定的时间
StringstrHtml = filterConfig.getInitParameter("html");
longtime = System.currentTimeMillis()+Integer.parseInt(strHtml)*1000;
//time为毫秒值
response.setDateHeader("expires",time);
response.setHeader("cache-control",time/1000+"");
response.setHeader("pragma",time/1000+"");
}
c)总结:写Filter一定要知道该Filter过滤哪个或哪些资源,不是所有的Filter都过滤/*的资源。
动态资源缓存,静态资源缓存
静止缓存动态资源如jsp
//禁止浏览器缓存动态资源,例如JSP资源
public class FilterDemo5 implements Filter {
privateFilterConfig filterConfig;
public voidinit(FilterConfig filterConfig) throws ServletException {
this.filterConfig= filterConfig;
}
public voiddoFilter(ServletRequest req, ServletResponse res,FilterChain chain) throwsIOException, ServletException {
//NO将父子接口强转
HttpServletRequestrequest = (HttpServletRequest) req;
HttpServletResponseresponse = (HttpServletResponse) res;
//NO1取得客户端访问的资源的URI,形式/day19/login.jsp
Stringuri = request.getRequestURI();
//NO2判段是否以jsp结尾,即动态资源
if(uri!=null&& uri.endsWith("jsp")){
//NO3如果是动态资源,设置三个响应头通知浏览器不缓存
response.setHeader("expires","-1");
response.setHeader("cache-control","no-cache");
response.setHeader("pragma","no-cache");
}elseif(uri!=null && uri.endsWith("html")){
//NO4如果是静态资源,缓存一定的时间,有助于减轻服务器压力
StringstrHtml = filterConfig.getInitParameter("html");
longtime = System.currentTimeMillis()+Integer.parseInt(strHtml)*1000;
//time为毫秒值
response.setDateHeader("expires",time);
response.setHeader("cache-control",time/1000+"");
response.setHeader("pragma",time/1000+"");
}
//NO5放行资源
chain.doFilter(request,response);
}
public voiddestroy() {
}
}
web.xml中配置
<filter>
<filter-name>FilterDemo5</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo5</filter-class>
<init-param>
<param-name>html</param-name>
<param-value>86400</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterDemo5</filter-name>
<!-- /*表示拦截所有,/表示项目名称,*代表所有 -->
<!-- 不是用户访问的,指的是filter拦截所有资源 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
loign.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
<form action="${pageContext.request.contextPath}/LoginServlet" method="post">
<table border="1" align="center">
<caption>用户登录</caption>
<tr>
<th>用户名</th>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<th>密码</th>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
</body>
</html>
login.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<form action="/day19/LoginServlet" method="post">
<table border="1" align="center">
<caption><br>用户自动登录</caption>
<tr>
<th>用户名</th>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<th>密码</th>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<th>时间</th>
<td>
<input checked name="time" type="radio" value="60"/>1分钟
<input name="time" type="radio" value="180"/>3分钟
<input name="time" type="radio" value="300"/>5分钟
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
</body>
</html>